searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Qemu搭建PCIE学习环境

2023-03-29 02:13:50
162
0
  • 工具信息
  • 主机:VMwareWorkstation或VirtualBox + CentOS Linux release 8.5.2111

VMwareWorkstation或VirtualBox

自行安装

CentOS Linux release 8.5.2111

https://mirrors.aliyun.com/centos/8/isos/x86_64/

选择:CentOS-8.5.2111-x86_64-dvd1.iso

 

  • 虚拟机:qemu-7.1.0

https://download.qemu.org/qemu-7.1.0.tar.xz

 

  • 内核:linux-4.19.99

https://mirrors.aliyun.com/linux-kernel/v4.x/linux-4.19.99.tar.xz

 

  • Busy Box:busybox-1.36.0

https://busybox.net/downloads/busybox-1.36.0.tar.bz2

 

  • 目的

在主机CentOS(VMware虚拟机)上通过qemu-7.1.0启动添加了PCIE调试信息后编译的linux-4.19.99,结合qemu-7.1.0提供的e1000搭建PCIE的学习环境,对内核涉及到的PCIE文件做简单介绍。本文仅仅是搭建PCIE学习环境,不包括PCIE的理论介绍。最终效果如下:

 

(1)     Qemu启动加了调试信息的内核

/home/jis1/qemu-7.1.0/build/qemu-system-x86_64 \

-smp 1 \

-m 1024M -kernel /home/jis1/linux-4.19.99/x86_64/arch/x86/boot/bzImage \

-nographic \

-L /home/jis1/qemu-7.1.0/pc-bios/

-append "root=/dev/ram0 rw rootfstype=ext4 console=ttyS0 init=/linuxrc pci=noacpi" \

-nic tap,id=tape0,ifname=tap0,script=no,downscript=no \

-initrd /home/jis1/busybox-1.36.0/ramdisk.gz \

-device virtio-net-pci,id=net1,mac=00:00:00:00:00:02,mq=on \

 

(2)     启动过程中有添加的调试信息(本文目的)

[    3.972627] pci 0000:00:02.0: BAR 2: assigned [mem 0xfec01000-0xfec01fff]

[    3.979393]

[    3.979393]  pcibios_bus_to_resource-86: window->res = [io  0x0000-0xffff]

[    3.987623]

[    3.987623]  pcibios_bus_to_resource-86: window->res = [mem 0x00000000-0xffffffffff]

[    3.994463]

[    3.994463]  pci_assign_resource-329: BAR 1: [mem size 0x00001000]

[    4.001766] pci 0000:00:04.0: BAR 1: assigned [mem 0xfec02000-0xfec02fff]

 

(3)     lspci能查看网卡e1000的信息

/ # lspci -k 00:04.0

00:01.0 Class 0601: 8086:7000

00:04.0 Class 0200: 1af4:1000 virtio-pci

00:00.0 Class 0600: 8086:1237

00:01.3 Class 0680: 8086:7113

00:03.0 Class 0200: 8086:100e e1000

00:01.1 Class 0101: 8086:7010

00:02.0 Class 0300: 1234:1111

 

  • 环境搭建步骤
    • 安装主机CentOS

可以使用物理机,也可以使用VMwareWorkstation + CentOS或VirtualBox + CentOS模拟,这里不详述安装步骤。安装后的CentOS信息如下:

[root@localhost jis1]# cat /etc/os-release

NAME="CentOS Stream"

VERSION="8"

ID="centos"

ID_LIKE="rhel fedora"

VERSION_ID="8"

PLATFORM_ID="platform:el8"

PRETTY_NAME="CentOS Stream 8"

ANSI_COLOR="0;31"

CPE_NAME="cpe:/o:centos:centos:8"

HOME_URL="https://centos.org/"

BUG_REPORT_URL="https://bugzilla.redhat.com/"

REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux 8"

REDHAT_SUPPORT_PRODUCT_VERSION="CentOS Stream"

[root@localhost jis1]# uname -a

Linux localhost.localdomain 4.18.0-408.el8.x86_64 #1 SMP Mon Jul 18 17:42:52 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

[root@localhost jis1]#

 

  • 安装依赖的工具
  • 基础工具

[root@localhost jis1]# yum -y install git automake libtool glib2 glib2-devel

[root@localhost jis1]#yum install ncurses-devel bison flex openssl-devel perl elfutils-libelf-devel

 

  • 编译安装re2c

[root@localhost jis1]# wget https://down.24kplus.com/linux/re2c-1.1.1.tar.gz

 

[root@localhost jis1]# tar xf re2c-1.1.1.tar.gz

[root@localhost jis1]# cd re2c-1.1.1/

[root@localhost re2c-1.1.1]# git init

[root@localhost re2c-1.1.1]# ./autogen.sh

[root@localhost re2c-1.1.1]# ./configure

[root@localhost re2c-1.1.1]# make && make install

[root@localhost re2c-1.1.1]# re2c -v

re2c 1.1.1

[root@localhost re2c-1.1.1]#

 

  • 编译安装ninja

[root@localhost jis1]#wget https://codeload.github.com/ninja-build/ninja/tar.gz/refs/tags/v1.10.2

[root@localhost jis1]# mv v1.10.2 ninja-1.10.2.tar.gz

[root@localhost jis1]# tar xf ninja-1.10.2.tar.gz

[root@localhost jis1]# cd ninja-1.10.2/

 

查看可执行文件python3所在的目录,修改configure.py,把“#!/usr/bin/env python”替换成python3所在的目录“#/usr/bin/python3”

[root@localhost ninja-1.10.2]# which python3

/usr/bin/python3

[root@localhost ninja-1.10.2]# vi configure.py

#!/usr/bin/env python  // 替换成“#/usr/bin/python3”

 

编译安装ninja:

[root@localhost ninja-1.10.2]# ./configure.py –bootstrap

[root@localhost ninja-1.10.2]# cp ninja /usr/bin/

[root@localhost ninja-1.10.2]# ninja --version

1.10.2

[root@localhost ninja-1.10.2]#

 

  • 编译安装qemu

从官网下载qemu模拟器(https://download.qemu.org/qemu-7.1.0.tar.xz)。

 

[root@localhost jis1]# tar xf qemu-7.1.0.tar.xz

[root@localhost jis1]# cd qemu-7.1.0/

[root@localhost qemu-7.1.0]# mkdir build

[root@localhost qemu-7.1.0]# cd build

[root@localhost build]# ../configure --target-list=x86_64-softmmu,x86_64-linux-user  --python=/usr/bin/python3

[root@localhost build]# make

[root@localhost build]# ./qemu-system-x86_64 --version

QEMU emulator version 7.1.0

Copyright (c) 2003-2022 Fabrice Bellard and the QEMU Project developers

 

注:这里使用参数“--target-list”仅编译x86_64的qemu工具。

编译过程中如果遇到问题可以参考如下网址解决:

https://blog.csdn.net/yzx19/article/details/123423668

 

  • 编译内核

从官网下载内核版本:https://mirrors.aliyun.com/linux-kernel/v4.x/linux-4.19.99.tar.xz

 

  • 生成默认编译选项.config文件

[root@localhost jis1]# tar xf linux-4.19.99.tar.xz

[root@localhost jis1]# cd linux-4.19.99/

[root@localhost linux-4.19.99]# make O=x86_64 x86_64_defconfig

[root@localhost linux-4.19.99]# ls -a x86_64/ |grep config

.config

[root@localhost linux-4.19.99]#

 

  • 配置使用ramdisk

[root@localhost linux-4.19.99]# make O=x86_64 menuconfig

 

General setup  --->

       ----> [*] Initial RAM filesystem and RAM disk (initramfs/initrd) support

Device Drivers  --->

   [*] Block devices  --->

        <*>   RAM block device support

        (65536) Default RAM disk size (kbytes)

 

  • 编译生成bzImage

[root@localhost linux-4.19.99]# make O=x86_64 bzImage

//经过一段时间的编译,生成了bzImage

 

[root@localhost linux-4.19.99]# ls x86_64/arch/x86/boot/ |grep bz    bzImage

 

  • 制作根文件系统
  • 从官网下载内核版本并编译:

[root@localhost jis1]# wget https://busybox.net/downloads/busybox-1.36.0.tar.bz2

[root@localhost jis1]# tar xf busybox-1.36.0.tar.bz2

[root@localhost jis1]# cd busybox-1.36.0/

[root@localhost busybox-1.36.0]#make menuconfig

// 选择编译成静态

Settings  --->

    Build Options  --->

         [*] Build BusyBox as a static binary (no shared libs)

[root@localhost busybox-1.36.0]#make

[root@localhost busybox-1.36.0]#make install

 

  • 新生成文件“sh”,输入如下内容

 

#!/bin/bash

sudo rm -rf rootfs

sudo rm -rf tmpfs

sudo rm -rf ramdisk*

sudo mkdir rootfs

sudo cp ../busybox*/_install/*  rootfs/ -raf

sudo mkdir -p rootfs/proc/

sudo mkdir -p rootfs/sys/

sudo mkdir -p rootfs/tmp/

sudo mkdir -p rootfs/root/

sudo mkdir -p rootfs/var/

sudo mkdir -p rootfs/mnt/

if [ ! -d proc ] && [ ! -d sys ] && [ ! -d dev ] && [ ! -d etc/init.d ]; then

        mkdir proc sys dev etc etc/init.d

fi

 

if [ -f etc/init.d/rcS ]; then

                   rm etc/init.d/rcS

fi

echo "#!/bin/sh" > etc/init.d/rcS

echo "mount -t proc none /proc" >> etc/init.d/rcS

echo "mount -t sysfs none /sys" >> etc/init.d/rcS

echo "/sbin/mdev -s" >> etc/init.d/rcS

chmod +x etc/init.d/rcS

 

sudo cp etc rootfs/ -arf

sudo mkdir -p rootfs/lib

sudo cp -arf /lib/i386-linux-gnu/* rootfs/lib/

sudo rm rootfs/lib/*.a

sudo strip rootfs/lib/*

sudo mkdir -p rootfs/dev/

sudo mknod rootfs/dev/tty1 c 4 1

sudo mknod rootfs/dev/tty2 c 4 2

sudo mknod rootfs/dev/tty3 c 4 3

sudo mknod rootfs/dev/tty4 c 4 4

sudo mknod rootfs/dev/console c 5 1

sudo mknod rootfs/dev/null c 1 3

sudo dd if=/dev/zero of=ramdisk bs=1M count=32

sudo mkfs.ext4 -F ramdisk

sudo mkdir -p tmpfs

sudo mount -t ext4 ramdisk ./tmpfs/  -o loop

sudo cp -raf rootfs/*  tmpfs/

sudo umount tmpfs

sudo gzip --best -c ramdisk > ramdisk.gz

 

  • 使用脚本生成根文件系统

[root@localhost busybox-1.36.0]# chmod +x create_rootfs.sh

[root@localhost busybox-1.36.0]# ./create_rootfs.sh

 

[root@localhost busybox-1.36.0]# ll |grep ramdisk.gz

-rw-r--r--.  1 root root  1587035 Mar 25 13:39 ramdisk.gz

 

  • 启动内核

 

  • 使用如下qemu命令启动内核

/home/jis1/qemu-7.1.0/build/qemu-system-x86_64 \

-smp 1 \

-m 1024M -kernel /home/jis1/linux-4.19.99/x86_64/arch/x86/boot/bzImage \

-nographic \

-L /home/jis1/qemu-7.1.0/pc-bios/

-append "root=/dev/ram0 rw rootfstype=ext4 console=ttyS0 init=/linuxrc pci=noacpi" \

-nic tap,id=tape0,ifname=tap0,script=no,downscript=no \

-initrd /home/jis1/busybox-1.36.0/ramdisk.gz \

-device virtio-net-pci,id=net1,mac=00:00:00:00:00:02,mq=on \

 

    注:要指定“-L /home/jis1/qemu-7.1.0/pc-bios/”,不然会报错:

qemu: could not load PC BIOS 'bios-256k.bin'

 

  • qemu启动编译好的内核后,可以查看pci设备

~ # uname -a

Linux (none) 4.19.99 #1 SMP Sat Mar 25 10:36:50 CST 2023 x86_64 GNU/Linux

~ # lspci

00:01.0 Class 0601: 8086:7000

00:04.0 Class 0200: 1af4:1000

00:00.0 Class 0600: 8086:1237

00:01.3 Class 0680: 8086:7113

00:03.0 Class 0200: 8086:100e

00:01.1 Class 0101: 8086:7010

00:02.0 Class 0300: 1234:1111

~ #

 

这里的“00:04.0 Class 0200: 1af4:1000”就是e1000网卡的模拟,可以用来调试和学习PCIE。

 

  • PCIE调试简单介绍
    • PCIE驱动框架

在开始通过代码来学习PCIE之前,需要对PCIE的概念及驱动框架有基本的了解,网上介绍的比较多,推荐一个介绍得比较好的博客:

https://www.cnblogs.com/LoyenWang/p/14165852.html

 

         如下是我总结的PCIE宏观驱动框架:

  • 系统启动时会注册驱动框架总线pci_bus_type(见drivers\pci\pci-driver.c),pci_bus_type和驱动框架中的其它总线一样,维护设备链表和驱动链表:当有设备节点或驱动节点插入时,pci_bus_type中的match函数pci_bus_match()用于匹配设备和驱动,如果匹配,调用pci_bus_type中的probe函数pci_device_probe()处理。
  • “drivers\pci\controller”下有各种PCIE控制器的驱动程序,如pcie-cadence-host.c是针对cadence的PCIE控制器的驱动、pcie-xilinx-nwl.c是针对赛灵思nwl控制器的驱动;这些驱动会注册到pci_bus_type总线的驱动链表。系统启动过程中通过设备树生成对应设备节点(platform_device)并注册到pci_bus_type总线的设备链表,驱动框架调用match函数pci_bus_match匹配成功后,调用pci_pus_type的probe函数pci_device_probe处理,该probe函数最终找到PCIE控制器的probe函数(如赛灵思PCIE控制器的probe函数nwl_pcie_probe()).
  • PCIE控制器的probe函数对控制器进行必要的设置(各厂家的PCIE控制器有区别)后,最终统一调用函数pci_scan_root_bus_bridge()从0号总线使用DFS算法开始扫描生成pci_dev、pci_bus、pci_slot等与具体设备相关的数据结构。扫描过程中通过调用pci_scan_child_bus() => pci_scan_child_bus_extend()=>pci_scan_single_device()=>pci_device_add()将一个PCIE设备(结构体:pci_dev)加入到驱动框架的设备链表中(,如果有对应的驱动链表上注册过PCIE设备驱动,则调用PCIE设备驱动的probe函数,probe函数一般的作用为“设置芯片寄存器、挂接中断处理函数、提供用户操作接口fops等”,probe函数结束后该PCIE设备就可以正常工作了。
    • 调试介绍

在掌握了PCIE概念和驱动框架后,可以通过代码进行学习,最常用的就是添加打印信息,比如在如下函数中添加打印后,重新编译内核并使用qemu启动新编译的内核就可以看到自己添加的打印信息了。

添加调试信息:

 

启动过程中打印的调试信息:

(1)     Qemu启动加了调试信息的内核

/home/jis1/qemu-7.1.0/build/qemu-system-x86_64 \

-smp 1 \

-m 1024M -kernel /home/jis1/linux-4.19.99/x86_64/arch/x86/boot/bzImage \

-nographic \

-L /home/jis1/qemu-7.1.0/pc-bios/

-append "root=/dev/ram0 rw rootfstype=ext4 console=ttyS0 init=/linuxrc pci=noacpi" \

-nic tap,id=tape0,ifname=tap0,script=no,downscript=no \

-initrd /home/jis1/busybox-1.36.0/ramdisk.gz \

-device virtio-net-pci,id=net1,mac=00:00:00:00:00:02,mq=on \

 

(2)     启动过程中有添加的调试信息(本文目的)

[    3.972627] pci 0000:00:02.0: BAR 2: assigned [mem 0xfec01000-0xfec01fff]

[    3.979393]

[    3.979393]  pcibios_bus_to_resource-86: window->res = [io  0x0000-0xffff]

[    3.987623]

[    3.987623]  pcibios_bus_to_resource-86: window->res = [mem 0x00000000-0xffffffffff]

[    3.994463]

[    3.994463]  pci_assign_resource-329: BAR 1: [mem size 0x00001000]

[    4.001766] pci 0000:00:04.0: BAR 1: assigned [mem 0xfec02000-0xfec02fff]

 

(3)     lspci能查看网卡e1000的信息

/ # lspci -k 00:04.0

00:01.0 Class 0601: 8086:7000

00:04.0 Class 0200: 1af4:1000 virtio-pci

00:00.0 Class 0600: 8086:1237

00:01.3 Class 0680: 8086:7113

00:03.0 Class 0200: 8086:100e e1000

00:01.1 Class 0101: 8086:7010

00:02.0 Class 0300: 1234:1111

 

小技巧:Qemu是作为一个用户态进程使用的,使用过程中要结束qemu进程,可以kill进程的方式。在另外一个终端可以使用如下命令结束qemu进程:

ps aux |grep qemu |awk '{print $2}' |xargs kill -9

 

添加什么样的调试信息需要基于对代码的理解和具体需求,调试信息最好结合lspci一起使用,然而busybox自带的lspci显示的信息比较少,这就需要自己编译lspci工具了,下一篇会介绍lspci的编译和使用,如下是自编译的lspci的显示信息:

# lspci -vvv -s 00:04.0

00:04.0 Class 0200: Device 1af4:1000

        Subsystem: Device 1af4:0001

        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B- DisINTx+

        Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-

        Latency: 0

        Interrupt: pin A routed to IRQ 11

        Region 1: Memory at fec02000 (32-bit, non-prefetchable) [size=4K]

        Region 4: Memory at 180000000 (64-bit, prefetchable) [size=16K]

        Expansion ROM at fec80000 [disabled] [size=256K]

        Capabilities: [98] MSI-X: Enable+ Count=4 Masked-

                Vector table: BAR=1 offset=00000000

                PBA: BAR=1 offset=00000800

        Capabilities: [84] Vendor Specific Information: VirtIO: <unknown>

                BAR=0 offset=00000000 size=00000000

        Capabilities: [70] Vendor Specific Information: VirtIO: Notify

                BAR=4 offset=00003000 size=00001000 multiplier=00000004

        Capabilities: [60] Vendor Specific Information: VirtIO: DeviceCfg

                BAR=4 offset=00002000 size=00001000

        Capabilities: [50] Vendor Specific Information: VirtIO: ISR

                BAR=4 offset=00001000 size=00001000

        Capabilities: [40] Vendor Specific Information: VirtIO: CommonCfg

                BAR=4 offset=00000000 size=00001000

        Kernel driver in use: virtio-pci

 

0条评论
0 / 1000
j****n
5文章数
0粉丝数
j****n
5 文章 | 0 粉丝
原创

Qemu搭建PCIE学习环境

2023-03-29 02:13:50
162
0
  • 工具信息
  • 主机:VMwareWorkstation或VirtualBox + CentOS Linux release 8.5.2111

VMwareWorkstation或VirtualBox

自行安装

CentOS Linux release 8.5.2111

https://mirrors.aliyun.com/centos/8/isos/x86_64/

选择:CentOS-8.5.2111-x86_64-dvd1.iso

 

  • 虚拟机:qemu-7.1.0

https://download.qemu.org/qemu-7.1.0.tar.xz

 

  • 内核:linux-4.19.99

https://mirrors.aliyun.com/linux-kernel/v4.x/linux-4.19.99.tar.xz

 

  • Busy Box:busybox-1.36.0

https://busybox.net/downloads/busybox-1.36.0.tar.bz2

 

  • 目的

在主机CentOS(VMware虚拟机)上通过qemu-7.1.0启动添加了PCIE调试信息后编译的linux-4.19.99,结合qemu-7.1.0提供的e1000搭建PCIE的学习环境,对内核涉及到的PCIE文件做简单介绍。本文仅仅是搭建PCIE学习环境,不包括PCIE的理论介绍。最终效果如下:

 

(1)     Qemu启动加了调试信息的内核

/home/jis1/qemu-7.1.0/build/qemu-system-x86_64 \

-smp 1 \

-m 1024M -kernel /home/jis1/linux-4.19.99/x86_64/arch/x86/boot/bzImage \

-nographic \

-L /home/jis1/qemu-7.1.0/pc-bios/

-append "root=/dev/ram0 rw rootfstype=ext4 console=ttyS0 init=/linuxrc pci=noacpi" \

-nic tap,id=tape0,ifname=tap0,script=no,downscript=no \

-initrd /home/jis1/busybox-1.36.0/ramdisk.gz \

-device virtio-net-pci,id=net1,mac=00:00:00:00:00:02,mq=on \

 

(2)     启动过程中有添加的调试信息(本文目的)

[    3.972627] pci 0000:00:02.0: BAR 2: assigned [mem 0xfec01000-0xfec01fff]

[    3.979393]

[    3.979393]  pcibios_bus_to_resource-86: window->res = [io  0x0000-0xffff]

[    3.987623]

[    3.987623]  pcibios_bus_to_resource-86: window->res = [mem 0x00000000-0xffffffffff]

[    3.994463]

[    3.994463]  pci_assign_resource-329: BAR 1: [mem size 0x00001000]

[    4.001766] pci 0000:00:04.0: BAR 1: assigned [mem 0xfec02000-0xfec02fff]

 

(3)     lspci能查看网卡e1000的信息

/ # lspci -k 00:04.0

00:01.0 Class 0601: 8086:7000

00:04.0 Class 0200: 1af4:1000 virtio-pci

00:00.0 Class 0600: 8086:1237

00:01.3 Class 0680: 8086:7113

00:03.0 Class 0200: 8086:100e e1000

00:01.1 Class 0101: 8086:7010

00:02.0 Class 0300: 1234:1111

 

  • 环境搭建步骤
    • 安装主机CentOS

可以使用物理机,也可以使用VMwareWorkstation + CentOS或VirtualBox + CentOS模拟,这里不详述安装步骤。安装后的CentOS信息如下:

[root@localhost jis1]# cat /etc/os-release

NAME="CentOS Stream"

VERSION="8"

ID="centos"

ID_LIKE="rhel fedora"

VERSION_ID="8"

PLATFORM_ID="platform:el8"

PRETTY_NAME="CentOS Stream 8"

ANSI_COLOR="0;31"

CPE_NAME="cpe:/o:centos:centos:8"

HOME_URL="https://centos.org/"

BUG_REPORT_URL="https://bugzilla.redhat.com/"

REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux 8"

REDHAT_SUPPORT_PRODUCT_VERSION="CentOS Stream"

[root@localhost jis1]# uname -a

Linux localhost.localdomain 4.18.0-408.el8.x86_64 #1 SMP Mon Jul 18 17:42:52 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

[root@localhost jis1]#

 

  • 安装依赖的工具
  • 基础工具

[root@localhost jis1]# yum -y install git automake libtool glib2 glib2-devel

[root@localhost jis1]#yum install ncurses-devel bison flex openssl-devel perl elfutils-libelf-devel

 

  • 编译安装re2c

[root@localhost jis1]# wget https://down.24kplus.com/linux/re2c-1.1.1.tar.gz

 

[root@localhost jis1]# tar xf re2c-1.1.1.tar.gz

[root@localhost jis1]# cd re2c-1.1.1/

[root@localhost re2c-1.1.1]# git init

[root@localhost re2c-1.1.1]# ./autogen.sh

[root@localhost re2c-1.1.1]# ./configure

[root@localhost re2c-1.1.1]# make && make install

[root@localhost re2c-1.1.1]# re2c -v

re2c 1.1.1

[root@localhost re2c-1.1.1]#

 

  • 编译安装ninja

[root@localhost jis1]#wget https://codeload.github.com/ninja-build/ninja/tar.gz/refs/tags/v1.10.2

[root@localhost jis1]# mv v1.10.2 ninja-1.10.2.tar.gz

[root@localhost jis1]# tar xf ninja-1.10.2.tar.gz

[root@localhost jis1]# cd ninja-1.10.2/

 

查看可执行文件python3所在的目录,修改configure.py,把“#!/usr/bin/env python”替换成python3所在的目录“#/usr/bin/python3”

[root@localhost ninja-1.10.2]# which python3

/usr/bin/python3

[root@localhost ninja-1.10.2]# vi configure.py

#!/usr/bin/env python  // 替换成“#/usr/bin/python3”

 

编译安装ninja:

[root@localhost ninja-1.10.2]# ./configure.py –bootstrap

[root@localhost ninja-1.10.2]# cp ninja /usr/bin/

[root@localhost ninja-1.10.2]# ninja --version

1.10.2

[root@localhost ninja-1.10.2]#

 

  • 编译安装qemu

从官网下载qemu模拟器(https://download.qemu.org/qemu-7.1.0.tar.xz)。

 

[root@localhost jis1]# tar xf qemu-7.1.0.tar.xz

[root@localhost jis1]# cd qemu-7.1.0/

[root@localhost qemu-7.1.0]# mkdir build

[root@localhost qemu-7.1.0]# cd build

[root@localhost build]# ../configure --target-list=x86_64-softmmu,x86_64-linux-user  --python=/usr/bin/python3

[root@localhost build]# make

[root@localhost build]# ./qemu-system-x86_64 --version

QEMU emulator version 7.1.0

Copyright (c) 2003-2022 Fabrice Bellard and the QEMU Project developers

 

注:这里使用参数“--target-list”仅编译x86_64的qemu工具。

编译过程中如果遇到问题可以参考如下网址解决:

https://blog.csdn.net/yzx19/article/details/123423668

 

  • 编译内核

从官网下载内核版本:https://mirrors.aliyun.com/linux-kernel/v4.x/linux-4.19.99.tar.xz

 

  • 生成默认编译选项.config文件

[root@localhost jis1]# tar xf linux-4.19.99.tar.xz

[root@localhost jis1]# cd linux-4.19.99/

[root@localhost linux-4.19.99]# make O=x86_64 x86_64_defconfig

[root@localhost linux-4.19.99]# ls -a x86_64/ |grep config

.config

[root@localhost linux-4.19.99]#

 

  • 配置使用ramdisk

[root@localhost linux-4.19.99]# make O=x86_64 menuconfig

 

General setup  --->

       ----> [*] Initial RAM filesystem and RAM disk (initramfs/initrd) support

Device Drivers  --->

   [*] Block devices  --->

        <*>   RAM block device support

        (65536) Default RAM disk size (kbytes)

 

  • 编译生成bzImage

[root@localhost linux-4.19.99]# make O=x86_64 bzImage

//经过一段时间的编译,生成了bzImage

 

[root@localhost linux-4.19.99]# ls x86_64/arch/x86/boot/ |grep bz    bzImage

 

  • 制作根文件系统
  • 从官网下载内核版本并编译:

[root@localhost jis1]# wget https://busybox.net/downloads/busybox-1.36.0.tar.bz2

[root@localhost jis1]# tar xf busybox-1.36.0.tar.bz2

[root@localhost jis1]# cd busybox-1.36.0/

[root@localhost busybox-1.36.0]#make menuconfig

// 选择编译成静态

Settings  --->

    Build Options  --->

         [*] Build BusyBox as a static binary (no shared libs)

[root@localhost busybox-1.36.0]#make

[root@localhost busybox-1.36.0]#make install

 

  • 新生成文件“sh”,输入如下内容

 

#!/bin/bash

sudo rm -rf rootfs

sudo rm -rf tmpfs

sudo rm -rf ramdisk*

sudo mkdir rootfs

sudo cp ../busybox*/_install/*  rootfs/ -raf

sudo mkdir -p rootfs/proc/

sudo mkdir -p rootfs/sys/

sudo mkdir -p rootfs/tmp/

sudo mkdir -p rootfs/root/

sudo mkdir -p rootfs/var/

sudo mkdir -p rootfs/mnt/

if [ ! -d proc ] && [ ! -d sys ] && [ ! -d dev ] && [ ! -d etc/init.d ]; then

        mkdir proc sys dev etc etc/init.d

fi

 

if [ -f etc/init.d/rcS ]; then

                   rm etc/init.d/rcS

fi

echo "#!/bin/sh" > etc/init.d/rcS

echo "mount -t proc none /proc" >> etc/init.d/rcS

echo "mount -t sysfs none /sys" >> etc/init.d/rcS

echo "/sbin/mdev -s" >> etc/init.d/rcS

chmod +x etc/init.d/rcS

 

sudo cp etc rootfs/ -arf

sudo mkdir -p rootfs/lib

sudo cp -arf /lib/i386-linux-gnu/* rootfs/lib/

sudo rm rootfs/lib/*.a

sudo strip rootfs/lib/*

sudo mkdir -p rootfs/dev/

sudo mknod rootfs/dev/tty1 c 4 1

sudo mknod rootfs/dev/tty2 c 4 2

sudo mknod rootfs/dev/tty3 c 4 3

sudo mknod rootfs/dev/tty4 c 4 4

sudo mknod rootfs/dev/console c 5 1

sudo mknod rootfs/dev/null c 1 3

sudo dd if=/dev/zero of=ramdisk bs=1M count=32

sudo mkfs.ext4 -F ramdisk

sudo mkdir -p tmpfs

sudo mount -t ext4 ramdisk ./tmpfs/  -o loop

sudo cp -raf rootfs/*  tmpfs/

sudo umount tmpfs

sudo gzip --best -c ramdisk > ramdisk.gz

 

  • 使用脚本生成根文件系统

[root@localhost busybox-1.36.0]# chmod +x create_rootfs.sh

[root@localhost busybox-1.36.0]# ./create_rootfs.sh

 

[root@localhost busybox-1.36.0]# ll |grep ramdisk.gz

-rw-r--r--.  1 root root  1587035 Mar 25 13:39 ramdisk.gz

 

  • 启动内核

 

  • 使用如下qemu命令启动内核

/home/jis1/qemu-7.1.0/build/qemu-system-x86_64 \

-smp 1 \

-m 1024M -kernel /home/jis1/linux-4.19.99/x86_64/arch/x86/boot/bzImage \

-nographic \

-L /home/jis1/qemu-7.1.0/pc-bios/

-append "root=/dev/ram0 rw rootfstype=ext4 console=ttyS0 init=/linuxrc pci=noacpi" \

-nic tap,id=tape0,ifname=tap0,script=no,downscript=no \

-initrd /home/jis1/busybox-1.36.0/ramdisk.gz \

-device virtio-net-pci,id=net1,mac=00:00:00:00:00:02,mq=on \

 

    注:要指定“-L /home/jis1/qemu-7.1.0/pc-bios/”,不然会报错:

qemu: could not load PC BIOS 'bios-256k.bin'

 

  • qemu启动编译好的内核后,可以查看pci设备

~ # uname -a

Linux (none) 4.19.99 #1 SMP Sat Mar 25 10:36:50 CST 2023 x86_64 GNU/Linux

~ # lspci

00:01.0 Class 0601: 8086:7000

00:04.0 Class 0200: 1af4:1000

00:00.0 Class 0600: 8086:1237

00:01.3 Class 0680: 8086:7113

00:03.0 Class 0200: 8086:100e

00:01.1 Class 0101: 8086:7010

00:02.0 Class 0300: 1234:1111

~ #

 

这里的“00:04.0 Class 0200: 1af4:1000”就是e1000网卡的模拟,可以用来调试和学习PCIE。

 

  • PCIE调试简单介绍
    • PCIE驱动框架

在开始通过代码来学习PCIE之前,需要对PCIE的概念及驱动框架有基本的了解,网上介绍的比较多,推荐一个介绍得比较好的博客:

https://www.cnblogs.com/LoyenWang/p/14165852.html

 

         如下是我总结的PCIE宏观驱动框架:

  • 系统启动时会注册驱动框架总线pci_bus_type(见drivers\pci\pci-driver.c),pci_bus_type和驱动框架中的其它总线一样,维护设备链表和驱动链表:当有设备节点或驱动节点插入时,pci_bus_type中的match函数pci_bus_match()用于匹配设备和驱动,如果匹配,调用pci_bus_type中的probe函数pci_device_probe()处理。
  • “drivers\pci\controller”下有各种PCIE控制器的驱动程序,如pcie-cadence-host.c是针对cadence的PCIE控制器的驱动、pcie-xilinx-nwl.c是针对赛灵思nwl控制器的驱动;这些驱动会注册到pci_bus_type总线的驱动链表。系统启动过程中通过设备树生成对应设备节点(platform_device)并注册到pci_bus_type总线的设备链表,驱动框架调用match函数pci_bus_match匹配成功后,调用pci_pus_type的probe函数pci_device_probe处理,该probe函数最终找到PCIE控制器的probe函数(如赛灵思PCIE控制器的probe函数nwl_pcie_probe()).
  • PCIE控制器的probe函数对控制器进行必要的设置(各厂家的PCIE控制器有区别)后,最终统一调用函数pci_scan_root_bus_bridge()从0号总线使用DFS算法开始扫描生成pci_dev、pci_bus、pci_slot等与具体设备相关的数据结构。扫描过程中通过调用pci_scan_child_bus() => pci_scan_child_bus_extend()=>pci_scan_single_device()=>pci_device_add()将一个PCIE设备(结构体:pci_dev)加入到驱动框架的设备链表中(,如果有对应的驱动链表上注册过PCIE设备驱动,则调用PCIE设备驱动的probe函数,probe函数一般的作用为“设置芯片寄存器、挂接中断处理函数、提供用户操作接口fops等”,probe函数结束后该PCIE设备就可以正常工作了。
    • 调试介绍

在掌握了PCIE概念和驱动框架后,可以通过代码进行学习,最常用的就是添加打印信息,比如在如下函数中添加打印后,重新编译内核并使用qemu启动新编译的内核就可以看到自己添加的打印信息了。

添加调试信息:

 

启动过程中打印的调试信息:

(1)     Qemu启动加了调试信息的内核

/home/jis1/qemu-7.1.0/build/qemu-system-x86_64 \

-smp 1 \

-m 1024M -kernel /home/jis1/linux-4.19.99/x86_64/arch/x86/boot/bzImage \

-nographic \

-L /home/jis1/qemu-7.1.0/pc-bios/

-append "root=/dev/ram0 rw rootfstype=ext4 console=ttyS0 init=/linuxrc pci=noacpi" \

-nic tap,id=tape0,ifname=tap0,script=no,downscript=no \

-initrd /home/jis1/busybox-1.36.0/ramdisk.gz \

-device virtio-net-pci,id=net1,mac=00:00:00:00:00:02,mq=on \

 

(2)     启动过程中有添加的调试信息(本文目的)

[    3.972627] pci 0000:00:02.0: BAR 2: assigned [mem 0xfec01000-0xfec01fff]

[    3.979393]

[    3.979393]  pcibios_bus_to_resource-86: window->res = [io  0x0000-0xffff]

[    3.987623]

[    3.987623]  pcibios_bus_to_resource-86: window->res = [mem 0x00000000-0xffffffffff]

[    3.994463]

[    3.994463]  pci_assign_resource-329: BAR 1: [mem size 0x00001000]

[    4.001766] pci 0000:00:04.0: BAR 1: assigned [mem 0xfec02000-0xfec02fff]

 

(3)     lspci能查看网卡e1000的信息

/ # lspci -k 00:04.0

00:01.0 Class 0601: 8086:7000

00:04.0 Class 0200: 1af4:1000 virtio-pci

00:00.0 Class 0600: 8086:1237

00:01.3 Class 0680: 8086:7113

00:03.0 Class 0200: 8086:100e e1000

00:01.1 Class 0101: 8086:7010

00:02.0 Class 0300: 1234:1111

 

小技巧:Qemu是作为一个用户态进程使用的,使用过程中要结束qemu进程,可以kill进程的方式。在另外一个终端可以使用如下命令结束qemu进程:

ps aux |grep qemu |awk '{print $2}' |xargs kill -9

 

添加什么样的调试信息需要基于对代码的理解和具体需求,调试信息最好结合lspci一起使用,然而busybox自带的lspci显示的信息比较少,这就需要自己编译lspci工具了,下一篇会介绍lspci的编译和使用,如下是自编译的lspci的显示信息:

# lspci -vvv -s 00:04.0

00:04.0 Class 0200: Device 1af4:1000

        Subsystem: Device 1af4:0001

        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B- DisINTx+

        Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-

        Latency: 0

        Interrupt: pin A routed to IRQ 11

        Region 1: Memory at fec02000 (32-bit, non-prefetchable) [size=4K]

        Region 4: Memory at 180000000 (64-bit, prefetchable) [size=16K]

        Expansion ROM at fec80000 [disabled] [size=256K]

        Capabilities: [98] MSI-X: Enable+ Count=4 Masked-

                Vector table: BAR=1 offset=00000000

                PBA: BAR=1 offset=00000800

        Capabilities: [84] Vendor Specific Information: VirtIO: <unknown>

                BAR=0 offset=00000000 size=00000000

        Capabilities: [70] Vendor Specific Information: VirtIO: Notify

                BAR=4 offset=00003000 size=00001000 multiplier=00000004

        Capabilities: [60] Vendor Specific Information: VirtIO: DeviceCfg

                BAR=4 offset=00002000 size=00001000

        Capabilities: [50] Vendor Specific Information: VirtIO: ISR

                BAR=4 offset=00001000 size=00001000

        Capabilities: [40] Vendor Specific Information: VirtIO: CommonCfg

                BAR=4 offset=00000000 size=00001000

        Kernel driver in use: virtio-pci

 

文章来自个人专栏
linux-驱动-pcie
5 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
0