diff --git a/Readme.md b/Readme.md index d6580e5705b421d937f15f22c9dcf0e19779345d..11ca635e3026d37850fd5f9b76a988774357425f 100755 --- a/Readme.md +++ b/Readme.md @@ -40,6 +40,7 @@ Phytium-Jailhouse针对飞腾系列芯片做了深度适配以及功能扩展。 $ make $ make install 在编译jailhouse前,请根据第4节内容确认是否需要对源码进行配置。 + (6)Jailhouse中编译python脚本需要提前安装python3、python3-pip和python3-mako软件包。 (7)编译后的cell文件在jailhouse code的configs/arm64目录下,裸机程序在jailhouse code的inmates/demos/arm64目录下。 @@ -544,6 +545,168 @@ D2000上命令序列和运行效果如下图所示。 测试结果:non-root cell数据能正常存储到SATA上。 +### 4.4.4 IVSHMEM网络通信测试 + +基于Jailhouse IVSHMEM通信机制以及Linux网络驱动ivshmem-net,可实现cell间网络通信功能。适用的平台为E2000Q、D2000、D3000,支持的Linux内核版本为5.10或6.6内核。需要说明的是,该测试目前仅支持non root cell运行Linux系统,本节测试以E2000Q平台为例进行演示。 + +#### 4.4.4.1 Cell间网络通信系统搭建 +(1)首先在root cell配置文件e2000q.c中定义CONFIG_IVSHMEM_TEST宏,打开IVSHMEM测试相关的配置,然后重新编译Jailhouse: + +![输入图片说明](pic/ivshmem-net-1.png) + +(2)然后加载Jailhouse驱动模块和ivshmem-net驱动模块(在driver目录下)、加载E2000Q的root cell,命令序列如下: + + # insmod jailhouse.ko + # insmod ivshmem-net.ko + # jailhouse enable e2000q.cell + +(3)启动non root cell Linux系统: + + # ./tools/jailhouse-cell-linux \ + # -i ./initrd_new.img \ /* 该image如有需要,请联系飞腾嵌入式软件部 */ + # -d configs/arm64/dts/inmate-e2000q-ivshmem-net.dtb \ + # -c "console=ttyAMA1,115200 earlycon=pl011, 0x2800d000 rw loglevel=8 pci=nomsi" \ + # configs/arm64/e2000q-linux-ivshmem-net-demo.cell \ + # /root/linux-kernel/arch/arm64/boot/Image \ + +注意:non root cell中同样需要安装ivshmem-net.ko,否则没有驱动。可通过将ivshmem-net.ko放入一个外部存储设备(emmc、U盘等等),然后将这个设备隔离给non root cell(参考前面章节的内容),启动non root cell Linux后挂载该存储设备,最后insmod安装ivshmem-net.ko驱动即可。 + +(4)检查root cell和non root cell中是否存在对应的网络设备,并配置为同一网段内的IP: + +![输入图片说明](pic/ivshmem-net-2.png) + +![输入图片说明](pic/ivshmem-net-3.png) + +注意:non root cell Linux中不安装ivshmem-net.ko驱动的情况下,不会有对应的网络设备enp0s1。 + +(5)在root cell Linux系统中添加静态路由: + + # ip route add 10.31.90.129 via 10.31.90.183 dev enP1p0s1 + +![输入图片说明](pic/ivshmem-net-4.png) + +注意:请根据自己设置的IP地址进行替换。 + +(6)root cell与non root cell进行互ping,检查网络是否互通: + +![输入图片说明](pic/ivshmem-net-5.png) + +![输入图片说明](pic/ivshmem-net-6.png) + +#### 4.4.4.2 Linux网络通信测试 + +在进行本节实验之前,请先完成上一节中的内容,确保cell间的网络可以相互ping通。 + +(1)在non root cell Linux系统中启动服务端程序(位于tools/demos): + + # ./ivshmem-net-server + +![输入图片说明](pic/ivshmem-net-7.png) + +注意:关于如何将服务端程序放入non root cell Linux文件系统请参考4.4.4.1节中第3步描述的方法。 + +(2)在root cell Linux系统中启动客户端程序(位于tools/demos),并输入任意字符串: + + # ./tools/demos/ivshmem-net-client 10.31.90.129 + +![输入图片说明](pic/ivshmem-net-8.png) + +注意:ivshmem-net-client程序的参数请根据自己设置的IP地址进行替换。 + +(3)此时,在non root cell Linux中可以接收到root cell Linux发送过来的信息: + +![输入图片说明](pic/ivshmem-net-9.png) + +### 4.4.5 从外部存储中启动根文件系统 + +在前面章节的测试中,从non root cell中启动一个Linux系统所使用的根文件系统为内存文件系统initramfs,本节内容将演示如何从外部存储介质中启动一个真实的根文件系统,目前在E2000Q上测试过的外部存储介质有:U盘、eMMC、SATA盘、nvme盘。本节测试假设用户已经在这些外部存储介质上制作了根文件系统。下面以U盘(eMMC、SATA盘的操作方法与U盘类似)与nvme盘为例进行演示。 + +注意1:请勿将root cell正在使用的外部存储(宿主机根文件系统)分配给non root cell。 + +注意2:无特殊需求,推荐使用U盘、eMMC或者SATA盘的方式,配置起来比nvme简单。 + +#### 4.4.5.1 U盘 + +(1)首先,添加non root cell配置,将U盘所对应的USB控制器隔离至non root cell,具体方法请参考USB测试章节中的内容。 + +(2)在宿主机中解绑相关的USB驱动,防止其干扰non root cell而引起Jailhouse报错: + + # cd /sys/bus/platform/devices/31a08000.usb3/driver + # echo 31a08000.usb3 > unbind + +注意:请根据自己的环境选择对应的USB控制器。 + +(3)启动root cell: + + # insmod jailhouse.ko + # jailhouse enable e2000q.cell + +(4)启动non root cell Linux系统: + + # ./tools/jailhouse-cell-linux \ + # -i ./initrd_new.img \ /* 该image如有需要,请联系飞腾嵌入式软件部 */ + # -d configs/arm64/dts/inmate-e2000q.dtb \ + # -c "console=ttyAMA1,115200 earlycon=pl011,0x2800d000 swiotlb=force pcie_aspm=off loglevel=8 pci=nomsi root=/dev/sda2 rootwait rw" \ + # configs/arm64/e2000q-linux-demo.cell \ + # /root/linux-kernel/arch/arm64/boot/Image \ + +注意:请根据自己的环境选择U盘根文件系统所在的分区,替换参数root=/dev/sda2。 + +#### 4.4.5.2 NVME盘 + +Jailhouse隔离PCIe设备所需要的cell配置,与用户当前宿主机Linux系统中的PCIe拓扑密切相关,PCIe拓扑不同,配置也会略有不同。因此本节内容仅展示配置方法,用户可根据自身情况进行调整。本节实验环境的PCIe拓扑、以及使用的nvme硬盘为: + +![输入图片说明](pic/real-fs-1.png) + +![输入图片说明](pic/real-fs-2.png) + +(1)在root cell配置文件e2000q.c中添加nvme设备所连接的PCIe桥(这里是00:01.0)的描述: + +![输入图片说明](pic/real-fs-3.png) + +(2)在root cell配置文件e2000q.c中添加PCIe桥对应的capability: + +![输入图片说明](pic/real-fs-4.png) + +(3)在root cell配置文件中添加nvme盘的PCIe设备描述: + +![输入图片说明](pic/real-fs-5.png) + +(4)在root cell配置文件e2000q.c中添加nvme盘对应的capability: + +![输入图片说明](pic/real-fs-6.png) +![输入图片说明](pic/real-fs-7.png) + +(5)在non root cell配置文件e2000q-linux-demo.c中同样添加步骤1~4中的内容。 + +(6)在non root cell配置文件中添加桥设备、nvme盘的bar0地址空间描述: + +![输入图片说明](pic/real-fs-8.png) + +(7)在宿主机Linux系统中解绑nvme盘的驱动: + + # echo 1 > /sys/bus/pci/devices/0000:01:00.0/remove + +(8)重新编译Jailhouse,使用新的配置文件启动root cell: + + # insmod jailhouse.ko + # jailhouse enable e2000q.cell + +(9)使用新的配置文件启动non root cell: + + # ./tools/jailhouse-cell-linux \ + # -i ./initrd_new.img \ /* 该image如有需要,请联系飞腾嵌入式软件部 */ + # -d configs/arm64/dts/inmate-e2000q.dtb \ + # -c "console=ttyAMA1,115200 earlycon=pl011,0x2800d000 swiotlb=force pcie_aspm=off loglevel=8 pci=nomsi root=/dev/nvme0n1p2 rootwait rw" \ + # configs/arm64/e2000q-linux-demo.cell \ + # /root/linux-kernel/arch/arm64/boot/Image \ + +![输入图片说明](pic/real-fs-9.png) + +注意1:请根据自己的环境选择根文件系统所在的分区,替换参数root=/dev/nvme0n1p2。 + +注意2:由于nvme自身的硬件特性,若在关闭Jailhouse后想二次隔离nvme盘,请重启机器。 + # 5 Non-root linux实时性测试 测试使用了stress和while循环脚本(均运行四个进程)来增加系统负载,命令如下: diff --git a/pic/E2000Q_CAN_config1.png b/pic/E2000Q_CAN_config1.png index 6bf0b66d35babc53a1a3976a925176be5a5a5a3e..ea4d9d67fdb0636b29e52bd70b781691e2e4d11c 100644 Binary files a/pic/E2000Q_CAN_config1.png and b/pic/E2000Q_CAN_config1.png differ diff --git a/pic/E2000Q_GPIO_config3.png b/pic/E2000Q_GPIO_config3.png index 3f2373c9f24221c43b24e10b5a9253de15ad926e..b06c9e5fa27a32da3781bf3ed99a3805be9790b6 100644 Binary files a/pic/E2000Q_GPIO_config3.png and b/pic/E2000Q_GPIO_config3.png differ diff --git a/pic/E2000Q_I2C_config3.png b/pic/E2000Q_I2C_config3.png index 833b447818012450759a0e705a8b0d9648c82868..20ffb4e71fdb4958b5c4a4f89618fa781550f5bb 100644 Binary files a/pic/E2000Q_I2C_config3.png and b/pic/E2000Q_I2C_config3.png differ diff --git a/pic/E2000Q_eMMC_config3.png b/pic/E2000Q_eMMC_config3.png index a93b35262c66705af5a677e6da8a922979299379..8def6f4b57c3b938f8e43156544eafb66772900a 100644 Binary files a/pic/E2000Q_eMMC_config3.png and b/pic/E2000Q_eMMC_config3.png differ diff --git a/pic/ivshmem-net-1.png b/pic/ivshmem-net-1.png new file mode 100644 index 0000000000000000000000000000000000000000..3c9224702951b08f98e15cfa7c06c2eb002027b0 Binary files /dev/null and b/pic/ivshmem-net-1.png differ diff --git a/pic/ivshmem-net-2.png b/pic/ivshmem-net-2.png new file mode 100644 index 0000000000000000000000000000000000000000..364dfc9bd0b5f09faab0116ceef5bf06f7af0406 Binary files /dev/null and b/pic/ivshmem-net-2.png differ diff --git a/pic/ivshmem-net-3.png b/pic/ivshmem-net-3.png new file mode 100644 index 0000000000000000000000000000000000000000..8842869d1da29666a414e310f6fc37d9c51f45bf Binary files /dev/null and b/pic/ivshmem-net-3.png differ diff --git a/pic/ivshmem-net-4.png b/pic/ivshmem-net-4.png new file mode 100644 index 0000000000000000000000000000000000000000..1d65a7f7d218b48fe54b77d6a705962dc73c7568 Binary files /dev/null and b/pic/ivshmem-net-4.png differ diff --git a/pic/ivshmem-net-5.png b/pic/ivshmem-net-5.png new file mode 100644 index 0000000000000000000000000000000000000000..28161a11fd5ff3ee0e5efe303fec18d31a6f5804 Binary files /dev/null and b/pic/ivshmem-net-5.png differ diff --git a/pic/ivshmem-net-6.png b/pic/ivshmem-net-6.png new file mode 100644 index 0000000000000000000000000000000000000000..641e095bd60431104442df08f3ed05853a85225f Binary files /dev/null and b/pic/ivshmem-net-6.png differ diff --git a/pic/ivshmem-net-7.png b/pic/ivshmem-net-7.png new file mode 100644 index 0000000000000000000000000000000000000000..9a194984722430b6ae7145ac6287973ada440b07 Binary files /dev/null and b/pic/ivshmem-net-7.png differ diff --git a/pic/ivshmem-net-8.png b/pic/ivshmem-net-8.png new file mode 100644 index 0000000000000000000000000000000000000000..355a3d868435ff9db7106299786ab0af9dcb7efa Binary files /dev/null and b/pic/ivshmem-net-8.png differ diff --git a/pic/ivshmem-net-9.png b/pic/ivshmem-net-9.png new file mode 100644 index 0000000000000000000000000000000000000000..42a5bdeb6d7b89c730ca1b632ae65621cffd88dd Binary files /dev/null and b/pic/ivshmem-net-9.png differ diff --git a/pic/real-fs-1.png b/pic/real-fs-1.png new file mode 100644 index 0000000000000000000000000000000000000000..f7d015a436f7043f7865252bdf7ed39e235e2ea2 Binary files /dev/null and b/pic/real-fs-1.png differ diff --git a/pic/real-fs-2.png b/pic/real-fs-2.png new file mode 100644 index 0000000000000000000000000000000000000000..b81c0199abbc6a8b243a78612911d11638e0676d Binary files /dev/null and b/pic/real-fs-2.png differ diff --git a/pic/real-fs-3.png b/pic/real-fs-3.png new file mode 100644 index 0000000000000000000000000000000000000000..9a912f90b72712a6c22ffba9bb6c0f8e879f3d09 Binary files /dev/null and b/pic/real-fs-3.png differ diff --git a/pic/real-fs-4.png b/pic/real-fs-4.png new file mode 100644 index 0000000000000000000000000000000000000000..4aadb5f41fe8762e05026aaa0f08f6850a4b9513 Binary files /dev/null and b/pic/real-fs-4.png differ diff --git a/pic/real-fs-5.png b/pic/real-fs-5.png new file mode 100644 index 0000000000000000000000000000000000000000..bec840da39d782b5eaf8e9305a0c3752e504b5a3 Binary files /dev/null and b/pic/real-fs-5.png differ diff --git a/pic/real-fs-6.png b/pic/real-fs-6.png new file mode 100644 index 0000000000000000000000000000000000000000..cdae7fdc1121fe774439198af98c39e915a18c9b Binary files /dev/null and b/pic/real-fs-6.png differ diff --git a/pic/real-fs-7.png b/pic/real-fs-7.png new file mode 100644 index 0000000000000000000000000000000000000000..dedb179d9510e62b7933af37d6c3a68d030e62c5 Binary files /dev/null and b/pic/real-fs-7.png differ diff --git a/pic/real-fs-8.png b/pic/real-fs-8.png new file mode 100644 index 0000000000000000000000000000000000000000..efd8d9069e073d5a056280e097dfb50dd0d38f00 Binary files /dev/null and b/pic/real-fs-8.png differ diff --git a/pic/real-fs-9.png b/pic/real-fs-9.png new file mode 100644 index 0000000000000000000000000000000000000000..86bf2cfcf225a28196395c31eed8dc7b710d4e8f Binary files /dev/null and b/pic/real-fs-9.png differ diff --git a/src/jailhouse/.gitignore b/src/jailhouse/.gitignore index dba80674cd8ae2a5e832f72e55a4b3e94b6f1d43..f73404c26d4132e00f97d4d4e042926efd52fb5f 100644 --- a/src/jailhouse/.gitignore +++ b/src/jailhouse/.gitignore @@ -17,6 +17,7 @@ Module.symvers modules.order driver/jailhouse.ko driver/uio_ivshmem.ko +driver/ivshmem-net.ko include/jailhouse/config.h hypervisor/hypervisor.lds inmates/lib/arm/inmate.lds @@ -24,6 +25,8 @@ inmates/lib/arm64/inmate.lds pyjailhouse/pci_defs.py tools/demos/cache-timings tools/demos/ivshmem-demo +tools/demos/ivshmem-net-server +tools/demos/ivshmem-net-client tools/jailhouse tools/jailhouse-gcov-extract tools/jailhouse-config-collect diff --git a/src/jailhouse/Makefile b/src/jailhouse/Makefile index 74017395f8c7412e801357d0621d706079a73c96..5d73f89693ad5c80a3d0db5708572c7b680ded2a 100644 --- a/src/jailhouse/Makefile +++ b/src/jailhouse/Makefile @@ -55,7 +55,7 @@ tool_inmates_install: $(DESTDIR)$(libexecdir)/jailhouse install: modules_install firmware_install tool_inmates_install $(Q)$(MAKE) -C tools $@ src=. ifeq ($(strip $(PYTHON_PIP_USABLE)), yes) - $(PIP) install --upgrade --force-reinstall $(PIP_ROOT) . + $(PIP) install --upgrade --force-reinstall --break-system-packages $(PIP_ROOT) . endif .PHONY: modules_install install clean firmware_install modules tools docs \ diff --git a/src/jailhouse/configs/arm64/d2000-ivshmem-demo.c b/src/jailhouse/configs/arm64/d2000-ivshmem-demo.c index 51c67e7319b50aaa3534fc3ce13c73b3c1b28218..9e297134d31a6c996bf0b1f5ddd05b3d6ec13e42 100644 --- a/src/jailhouse/configs/arm64/d2000-ivshmem-demo.c +++ b/src/jailhouse/configs/arm64/d2000-ivshmem-demo.c @@ -33,7 +33,7 @@ struct { .num_irqchips = ARRAY_SIZE(config.irqchips), .num_pci_devices = ARRAY_SIZE(config.pci_devices), - .vpci_irq_base = 101, + .vpci_irq_base = 101-32, .console = { .address = 0x28000000, @@ -55,8 +55,7 @@ struct { .pin_bitmap = { 1 << (38 - 32), 0, - 0, - 1 << (101 + 32 - 128), + 1 << (101 - 96), }, }, }, @@ -121,7 +120,7 @@ struct { { .type = JAILHOUSE_PCI_TYPE_IVSHMEM, .domain = 0, - .bdf = 0x0e << 3, + .bdf = 0x0 << 3, .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, .shmem_regions_start = 0, .shmem_dev_id = 1, diff --git a/src/jailhouse/configs/arm64/d2000-linux-demo.c b/src/jailhouse/configs/arm64/d2000-linux-demo.c index 466bde914671cff1755321b1c2d7a50e5db0bad2..1678b2b398c381f9207d561ea38b314b5363ac76 100644 --- a/src/jailhouse/configs/arm64/d2000-linux-demo.c +++ b/src/jailhouse/configs/arm64/d2000-linux-demo.c @@ -45,7 +45,7 @@ struct { }, .cpus = { - 0xf, + 0x1, }, .mem_regions = { diff --git a/src/jailhouse/configs/arm64/d2000-linux-ivshmem-net-demo.c b/src/jailhouse/configs/arm64/d2000-linux-ivshmem-net-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..08b6af6192d02622f43ffef17bb00fa7451088a4 --- /dev/null +++ b/src/jailhouse/configs/arm64/d2000-linux-ivshmem-net-demo.c @@ -0,0 +1,110 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for Phytium D2000 ivshmem-net test + * Copyright (c) 2025 Phytium Technology Co., Ltd + * + * Authors: + * Huaizhi Wen + * + * This work is licensed under the terms of the GNU GPL, version 2. + * See the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[8]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "linux-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG | JAILHOUSE_CON_REGDIST_4, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .cpu_reset_address = 0x0, + .vpci_irq_base = 101-32, + + .console = { + .address = 0x28001000, + .type = JAILHOUSE_CON_TYPE_PL011, + .flags = JAILHOUSE_CON_ACCESS_MMIO | JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x1, + }, + + .irqchips = { + { + .address = 0x29a00000, + .pin_base = 32, + .pin_bitmap = { + 1 << (39 - 32), + 0, + 1 << (101 - 96) | 1 << (102 - 96) | 1 << (103 - 96) | 1 << (104 - 96), + }, + }, + }, + + .mem_regions = { + + JAILHOUSE_SHMEM_NET_REGIONS(0xb1010000, 1), + + /* UART */{ + .phys_start = 0x28001000, + .virt_start = 0x28001000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | + JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + + /* RAM: for linux-loader space */ + { + .phys_start = 0x2000000000, + .virt_start = 0, + .size = 0x800000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + + /* RAM */ + { + .phys_start = 0x2000080000, + .virt_start = 0x2000080000, + .size = 0x40000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | JAILHOUSE_MEM_LOADABLE, + }, + + /* Communication Region */ + { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .pci_devices = { + /* IVSHMEM 0000:00:01.0 (networking) */ + { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; + diff --git a/src/jailhouse/configs/arm64/d2000.c b/src/jailhouse/configs/arm64/d2000.c index 74c83505f4282eb592a594ef057ed4c30a82ef17..20f217139348200b7718887d667bb5435cf968b0 100644 --- a/src/jailhouse/configs/arm64/d2000.c +++ b/src/jailhouse/configs/arm64/d2000.c @@ -7,6 +7,7 @@ * Authors: * shixiaofeng * Shaojun Yang + * Huaizhi Wen * * This work is licensed under the terms of the GNU GPL, version 2. * See the COPYING file in the top-level directory. @@ -18,10 +19,14 @@ struct { struct jailhouse_system header; __u64 cpus[1]; - struct jailhouse_memory mem_regions[29]; + struct jailhouse_memory mem_regions[33]; struct jailhouse_irqchip irqchips[1]; - struct jailhouse_pci_device pci_devices[3]; +#ifdef CONFIG_IVSHMEM_TEST + struct jailhouse_pci_device pci_devices[2]; +#else + struct jailhouse_pci_device pci_devices[2]; struct jailhouse_pci_capability pci_caps[14]; +#endif } __attribute__((packed)) config = { .header = { .signature = JAILHOUSE_SYSTEM_SIGNATURE, @@ -39,10 +44,17 @@ struct { JAILHOUSE_CON_REGDIST_4, }, .platform_info = { +#ifdef CONFIG_IVSHMEM_TEST + .pci_mmconfig_base = 0x34000000, + .pci_mmconfig_end_bus = 0x0, + .pci_is_virtual = 1, + .pci_domain = 0xffff, +#else .pci_mmconfig_base = 0x40000000, .pci_mmconfig_end_bus = 0xff, .pci_is_virtual = 0, .pci_domain = 0, +#endif .arm = { .gic_version = 3, @@ -61,9 +73,10 @@ struct { .num_memory_regions = ARRAY_SIZE(config.mem_regions), .num_irqchips = ARRAY_SIZE(config.irqchips), .num_pci_devices = ARRAY_SIZE(config.pci_devices), +#ifndef CONFIG_IVSHMEM_TEST .num_pci_caps = ARRAY_SIZE(config.pci_caps), - - .vpci_irq_base = 100, +#endif + .vpci_irq_base = 105-32, }, }, @@ -103,6 +116,7 @@ struct { .size = 0x2000, .flags = JAILHOUSE_MEM_READ, }, + JAILHOUSE_SHMEM_NET_REGIONS(0xb1010000, 0), /* Main memory */ { .phys_start = 0x80000000, @@ -310,6 +324,7 @@ struct { }, .pci_devices = { +#ifdef CONFIG_IVSHMEM_TEST { .type = JAILHOUSE_PCI_TYPE_IVSHMEM, .domain = 0, @@ -321,6 +336,18 @@ struct { .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, }, + /* IVSHMEM 0000:00:01.0 (networking) */ + { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, +#else /* PCI bridge @00:04.0 */ { .type = JAILHOUSE_PCI_TYPE_BRIDGE, @@ -343,8 +370,10 @@ struct { .caps_start = 8, .num_caps = 6, }, +#endif }, +#ifndef CONFIG_IVSHMEM_TEST .pci_caps = { /* PCI bridge @00:04.0 [0-7] */ { @@ -434,4 +463,5 @@ struct { .flags = JAILHOUSE_PCICAPS_WRITE, }, } +#endif }; diff --git a/src/jailhouse/configs/arm64/d3000-linux-ivshmem-net-demo.c b/src/jailhouse/configs/arm64/d3000-linux-ivshmem-net-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..e190dc6710f21a8cdea627d164ed9ca4fe68b769 --- /dev/null +++ b/src/jailhouse/configs/arm64/d3000-linux-ivshmem-net-demo.c @@ -0,0 +1,112 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for Phytium D3000 ivshmem-net test + * Copyright (c) 2025 Phytium Technology Co., Ltd + * + * Authors: + * Huaizhi Wen + * + * This work is licensed under the terms of the GNU GPL, version 2. + * See the COPYING file in the top-level directory. + */ + +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[8]; + struct jailhouse_irqchip irqchips[1]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "linux-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG | JAILHOUSE_CELL_VIRTUAL_CONSOLE_PERMITTED | JAILHOUSE_CELL_VIRTUAL_CONSOLE_ACTIVE, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .cpu_reset_address = 0x0, + .vpci_irq_base = 125-32, + + .console = { + .address = 0x28009000, + .type = JAILHOUSE_CON_TYPE_PL011, + .flags = JAILHOUSE_CON_ACCESS_MMIO | JAILHOUSE_CON_REGDIST_4, + }, + + }, + + .cpus = { + 0x1, + }, + + .mem_regions = { + JAILHOUSE_SHMEM_NET_REGIONS(0xb1010000, 1), + + /* UART 1 */ + { + .phys_start = 0x28009000, + .virt_start = 0x28009000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + + /* RAM: for linux-loader space */ + { + .phys_start = 0x2000000000, + .virt_start = 0, + .size = 0x800000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + + /* RAM */ + { + .phys_start = 0x2000080000, + .virt_start = 0x2000080000, + .size = 0x40000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_DMA | JAILHOUSE_MEM_LOADABLE, + }, + + /* Communication Region */ + { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_COMM_REGION, + }, + + }, + + .irqchips = { + /* GIC */ { + .address = 0x36800000, + .pin_base = 32, + .pin_bitmap = { + 0, + 0, + 1 << (104 - 96) | 1 << (107 - 96) | 1 << (125 - 96) | 1 << (126 - 96) | 1 << (127 - 96), + 0, + }, + }, + }, + + .pci_devices = { + /* IVSHMEM 0000:00:01.0 (networking) */ + { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; + diff --git a/src/jailhouse/configs/arm64/d3000.c b/src/jailhouse/configs/arm64/d3000.c index c7116032fa7813a6327e7594d2cb632989b8c109..eeb2ac88249c1a56ee70e51887cd1e72406bbe6e 100644 --- a/src/jailhouse/configs/arm64/d3000.c +++ b/src/jailhouse/configs/arm64/d3000.c @@ -17,10 +17,14 @@ struct { struct jailhouse_system header; __u64 cpus[1]; - struct jailhouse_memory mem_regions[35]; + struct jailhouse_memory mem_regions[39]; struct jailhouse_irqchip irqchips[1]; - struct jailhouse_pci_device pci_devices[3]; +#ifdef CONFIG_IVSHMEM_TEST + struct jailhouse_pci_device pci_devices[2]; +#else + struct jailhouse_pci_device pci_devices[2]; struct jailhouse_pci_capability pci_caps[14]; +#endif } __attribute__((packed)) config = { .header = { .signature = JAILHOUSE_SYSTEM_SIGNATURE, @@ -38,10 +42,17 @@ struct { JAILHOUSE_CON_REGDIST_4, }, .platform_info = { +#ifdef CONFIG_IVSHMEM_TEST + .pci_mmconfig_base = 0x38000000, + .pci_mmconfig_end_bus = 0x0, + .pci_is_virtual = 1, + .pci_domain = 0xffff, +#else .pci_mmconfig_base = 0x40000000, .pci_mmconfig_end_bus = 0xff, .pci_is_virtual = 0, .pci_domain = 0, +#endif .arm = { .gic_version = 3, @@ -57,8 +68,9 @@ struct { .num_memory_regions = ARRAY_SIZE(config.mem_regions), .num_irqchips = ARRAY_SIZE(config.irqchips), .num_pci_devices = ARRAY_SIZE(config.pci_devices), +#ifndef CONFIG_IVSHMEM_TEST .num_pci_caps = ARRAY_SIZE(config.pci_caps), - +#endif .vpci_irq_base = 92-32, }, }, @@ -99,6 +111,7 @@ struct { .size = 0x2000, .flags = JAILHOUSE_MEM_READ, }, + JAILHOUSE_SHMEM_NET_REGIONS(0xb1010000, 0), /* Main memory 0 */ { .phys_start = 0x80000000, @@ -353,6 +366,7 @@ struct { }, .pci_devices = { +#ifdef CONFIG_IVSHMEM_TEST { .type = JAILHOUSE_PCI_TYPE_IVSHMEM, .domain = 0, @@ -363,6 +377,18 @@ struct { .shmem_peers = 3, .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, }, + /* IVSHMEM 0000:00:01.0 (networking) */ + { + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, +#else /* PCI bridge @00:02.0 */ { .type = JAILHOUSE_PCI_TYPE_BRIDGE, @@ -390,8 +416,9 @@ struct { .msix_region_size = 0x4000, .msix_address = 0x587e0000, }, +#endif }, - +#ifndef CONFIG_IVSHMEM_TEST .pci_caps = { /* PCI bridge @00:02.0 [0-7] */ { @@ -480,6 +507,6 @@ struct { .flags = JAILHOUSE_PCICAPS_WRITE, }, } - +#endif }; diff --git a/src/jailhouse/configs/arm64/dts/inmate-d2000-ivshmem-net.dts b/src/jailhouse/configs/arm64/dts/inmate-d2000-ivshmem-net.dts new file mode 100644 index 0000000000000000000000000000000000000000..faf23c45a60ff08a8c02e100bc65481447f1250a --- /dev/null +++ b/src/jailhouse/configs/arm64/dts/inmate-d2000-ivshmem-net.dts @@ -0,0 +1,143 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for Phytium D2000 ivshmem-net test, + * corresponding to configs/arm64/d2000-linux-ivshmem-net-demo.c + * + * Copyright (c) 2025 Phytium Technology Co., Ltd. + * + * Authors: + * Huaizhi Wen + * + * This work is licensed under the terms of the GNU GPL, version 2. + * See the COPYING file in the top-level directory. + */ + +/dts-v1/; + +/memreserve/ 0x0000000080000000 0x0000000000010000; +/ { + compatible = "phytium,d2000"; + interrupt-parent = <0x01>; + #address-cells = <0x02>; + #size-cells = <0x02>; + model = "D2000 Development Board"; + + hypervisor { + compatible = "jailhouse,cell"; + }; + + aliases { + serial1 = "/soc/uart@28001000"; + }; + + chosen { + stdout-path = "serial1:115200n8"; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + cpu_suspend = <0xc4000001>; + cpu_off = <0x84000002>; + cpu_on = <0xc4000003>; + sys_poweroff = <0x84000008>; + sys_reset = <0x84000009>; + }; + + cpus { + #address-cells = <0x02>; + #size-cells = <0x00>; + + cpu@0 { + device_type = "cpu"; + compatible = "phytium,ftc663\0arm,armv8"; + reg = <0x00 0x00>; + enable-method = "psci"; + numa-node-id = <0x00>; + }; + }; + + gic: interrupt-controller@29900000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <0x03>; + #address-cells = <0x02>; + #size-cells = <0x02>; + ranges; + interrupt-controller; + reg = <0x00 0x29a00000 0x00 0x20000 0x00 0x29b00000 0x00 0x100000 0x00 0x29c00000 0x00 0x10000 0x00 0x29c10000 0x00 0x10000 0x00 0x29c20000 0x00 0x10000>; + interrupts = <0x01 0x09 0x04>; + phandle = <0x01>; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <0x01 0x0d 0x08 0x01 0x0e 0x08 0x01 0x0b 0x08 0x01 0x0a 0x08>; + clock-frequency = <0x2dc6c00>; + }; + + pmu { + compatible = "arm,armv8-pmuv3"; + interrupts = <0x01 0x07 0x08>; + }; + + clocks { + #address-cells = <0x02>; + #size-cells = <0x02>; + ranges; + + clk48mhz: clk48mhz { + compatible = "fixed-clock"; + #clock-cells = <0x00>; + clock-frequency = <0x2dc6c00>; + phandle = <0x03>; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <0x02>; + #size-cells = <0x02>; + dma-coherent; + ranges; + + uart@28001000 { + compatible = "arm,pl011\0arm,primecell"; + reg = <0x00 0x28001000 0x00 0x1000>; + baud = <0x1c200>; + reg-shift = <0x02>; + reg-io-width = <0x04>; + interrupts = <0x00 0x07 0x04>; + clocks = <&clk48mhz &clk48mhz>; + clock-names = "uartclk\0apb_pclk"; + status = "ok"; + }; + + interrupt-controller@29000000 { + compatible = "phytium,ixic"; + reg-names = "ctr\0hpb"; + reg = <0x00 0x29000000 0x00 0x60000 0x00 0x29100000 0x00 0x2000>; + interrupt-controller; + interrupt-parent = <0x01>; + #interrupt-cells = <0x03>; + intx-spi-base = <0x1c>; + phandle = <0x0a>; + }; + + pci@34000000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0x00 0x00 0x00 0x01 &gic 0x00 0x00 0x00 0x45 0x01>, + <0x00 0x00 0x00 0x02 &gic 0x00 0x00 0x00 0x46 0x01>, + <0x00 0x00 0x00 0x03 &gic 0x00 0x00 0x00 0x47 0x01>, + <0x00 0x00 0x00 0x04 &gic 0x00 0x00 0x00 0x48 0x01>; + reg = <0x0 0x34000000 0x0 0x100000>; + ranges = <0x02000000 0x00 0x20000000 0x0 0x20000000 0x00 0x10000>; + }; + }; +}; diff --git a/src/jailhouse/configs/arm64/dts/inmate-d2000.dts b/src/jailhouse/configs/arm64/dts/inmate-d2000.dts index 3f1a6675d71a68d8dcb11b8a719f542b592aed60..8be34f76e273258805f3aea8bba597b92631b450 100644 --- a/src/jailhouse/configs/arm64/dts/inmate-d2000.dts +++ b/src/jailhouse/configs/arm64/dts/inmate-d2000.dts @@ -8,6 +8,7 @@ * * Authors: * Shaojun Yang + * Huaizhi Wen * * This work is licensed under the terms of the GNU GPL, version 2. * See the COPYING file in the top-level directory. @@ -57,30 +58,6 @@ enable-method = "psci"; numa-node-id = <0x00>; }; - - cpu@1 { - device_type = "cpu"; - compatible = "phytium,ftc663\0arm,armv8"; - reg = <0x00 0x01>; - enable-method = "psci"; - numa-node-id = <0x00>; - }; - - cpu@100 { - device_type = "cpu"; - compatible = "phytium,ftc663\0arm,armv8"; - reg = <0x00 0x100>; - enable-method = "psci"; - numa-node-id = <0x00>; - }; - - cpu@101 { - device_type = "cpu"; - compatible = "phytium,ftc663\0arm,armv8"; - reg = <0x00 0x101>; - enable-method = "psci"; - numa-node-id = <0x00>; - }; }; interrupt-controller@29900000 { @@ -93,15 +70,6 @@ reg = <0x00 0x29a00000 0x00 0x20000 0x00 0x29b00000 0x00 0x100000 0x00 0x29c00000 0x00 0x10000 0x00 0x29c10000 0x00 0x10000 0x00 0x29c20000 0x00 0x10000>; interrupts = <0x01 0x09 0x04>; phandle = <0x01>; - - /* - gic-its@29920000 { - compatible = "arm,gic-v3-its"; - msi-controller; - reg = <0x00 0x29a20000 0x00 0x20000>; - phandle = <0x09>; - }; - */ }; timer { @@ -120,26 +88,12 @@ #size-cells = <0x02>; ranges; - clk250mhz: clk250mhz { - compatible = "fixed-clock"; - #clock-cells = <0x00>; - clock-frequency = <0xee6b280>; - phandle = <0x05>; - }; - clk48mhz: clk48mhz { compatible = "fixed-clock"; #clock-cells = <0x00>; clock-frequency = <0x2dc6c00>; phandle = <0x03>; }; - - clk600mhz: clk600mhz { - compatible = "fixed-clock"; - #clock-cells = <0x00>; - clock-frequency = <0x23c34600>; - phandle = <0x04>; - }; }; soc { @@ -179,7 +133,6 @@ #size-cells = <0x02>; #interrupt-cells = <0x01>; reg = <0x00 0x40000000 0x00 0x10000000>; - //msi-parent = <0x09>; bus-range = <0x00 0xff>; interrupt-map-mask = <0x00 0x00 0x00 0x07>; interrupt-map = <0x00 0x00 0x00 0x01 0x0a 0x00 0x1c 0x04 0x00 0x00 0x00 0x02 0x0a 0x00 0x1d 0x04 0x00 0x00 0x00 0x03 0x0a 0x00 0x1e 0x04 0x00 0x00 0x00 0x04 0x0a 0x00 0x1f 0x04>; diff --git a/src/jailhouse/configs/arm64/dts/inmate-d3000-ivshmem-net.dts b/src/jailhouse/configs/arm64/dts/inmate-d3000-ivshmem-net.dts new file mode 100644 index 0000000000000000000000000000000000000000..34683e729eb58244b83b0e6c1b50e20221a4a9a8 --- /dev/null +++ b/src/jailhouse/configs/arm64/dts/inmate-d3000-ivshmem-net.dts @@ -0,0 +1,133 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for Phytium D3000 ivshmem-net test, + * corresponding to configs/arm64/d3000-linux-ivshmem-net-demo.c + * + * Copyright (c) 2025 Phytium Technology Co., Ltd. + * + * Authors: + * Huaizhi Wen + * + * This work is licensed under the terms of the GNU GPL, version 2. + * See the COPYING file in the top-level directory. + */ + +/dts-v1/; + +/memreserve/ 0x0000000080000000 0x0000000000010000; +/ { + compatible = "phytium,pd2308"; + interrupt-parent = <0x01>; + #address-cells = <0x02>; + #size-cells = <0x02>; + model = "Pd2308 DEMO"; + + hypervisor { + compatible = "jailhouse,cell"; + }; + + aliases { + serial1 = "/soc/uart@28009000"; + }; + + chosen { + stdout-path = "serial1:115200n8"; + }; + + psci { + compatible = "arm,psci-1.0\0arm,psci-0.2\0arm,psci"; + method = "smc"; + cpu_suspend = <0xc4000001>; + cpu_off = <0x84000002>; + cpu_on = <0xc4000003>; + sys_poweroff = <0x84000008>; + sys_reset = <0x84000009>; + }; + + cpus { + #address-cells = <0x02>; + #size-cells = <0x00>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0x00 0x00>; + enable-method = "psci"; + numa-node-id = <0x00>; + }; + }; + + gic: interrupt-controller@36800000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <0x03>; + #address-cells = <0x02>; + #size-cells = <0x02>; + ranges; + interrupt-controller; + reg = <0x00 0x36800000 0x00 0x20000 0x00 0x36860000 0x00 0x100000>; + interrupts = <0x01 0x09 0x04>; + phandle = <0x01>; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <0x01 0x0d 0x08 0x01 0x0e 0x08 0x01 0x0b 0x08 0x01 0x0a 0x08>; + clock-frequency = <0x2faf080>; + }; + + pmu { + compatible = "arm,armv8-pmuv3"; + interrupts = <0x01 0x07 0x08>; + }; + + clocks { + #address-cells = <0x02>; + #size-cells = <0x02>; + ranges; + + sysclk_100mhz: clk100mhz { + compatible = "fixed-clock"; + #clock-cells = <0x00>; + clock-frequency = <0x5f5e100>; + phandle = <0x0c>; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <0x02>; + #size-cells = <0x02>; + ranges; + + uart@28009000 { + compatible = "arm,pl011\0arm,primecell"; + reg = <0x00 0x28009000 0x00 0x1000>; + baud = <0x1c200>; + reg-shift = <0x02>; + reg-io-width = <0x04>; + interrupts = <0x00 0x48 0x04>; + clocks = <&sysclk_100mhz &sysclk_100mhz>; + clock-names = "uartclk\0apb_pclk"; + status = "ok"; + phandle = <0x19>; + }; + + pci@38000000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0x00 0x00 0x00 0x01 &gic 0x00 0x00 0x00 0x5d 0x01>, + <0x00 0x00 0x00 0x02 &gic 0x00 0x00 0x00 0x5e 0x01>, + <0x00 0x00 0x00 0x03 &gic 0x00 0x00 0x00 0x5f 0x01>, + <0x00 0x00 0x00 0x04 &gic 0x00 0x00 0x00 0x4b 0x01>; + reg = <0x0 0x38000000 0x0 0x100000>; + ranges = <0x02000000 0x00 0x30000000 0x0 0x30000000 0x00 0x10000>; + }; + }; +}; + diff --git a/src/jailhouse/configs/arm64/dts/inmate-d3000.dts b/src/jailhouse/configs/arm64/dts/inmate-d3000.dts index 9d7d438e7ee882042f00f6bb946165937921b03f..f50cd47cf4eaf77ec7262762f83a3ee770116fe6 100644 --- a/src/jailhouse/configs/arm64/dts/inmate-d3000.dts +++ b/src/jailhouse/configs/arm64/dts/inmate-d3000.dts @@ -87,61 +87,12 @@ #size-cells = <0x02>; ranges; - clk250mhz { - compatible = "fixed-clock"; - #clock-cells = <0x00>; - clock-frequency = <0xee6b280>; - phandle = <0x0d>; - }; - - clk48mhz { - compatible = "fixed-clock"; - #clock-cells = <0x00>; - clock-frequency = <0x2dc6c00>; - phandle = <0x09>; - }; - - clk50mhz { - compatible = "fixed-clock"; - #clock-cells = <0x00>; - clock-frequency = <0x2faf080>; - phandle = <0x0a>; - }; - sysclk_100mhz: clk100mhz { compatible = "fixed-clock"; #clock-cells = <0x00>; clock-frequency = <0x5f5e100>; phandle = <0x0c>; }; - - clk200mhz { - compatible = "fixed-clock"; - #clock-cells = <0x00>; - clock-frequency = <0xbebc200>; - phandle = <0x10>; - }; - - clk600mhz { - compatible = "fixed-clock"; - #clock-cells = <0x00>; - clock-frequency = <0x23c34600>; - phandle = <0x11>; - }; - - clk1200mhz { - compatible = "fixed-clock"; - #clock-cells = <0x00>; - clock-frequency = <0x47868c00>; - phandle = <0x08>; - }; - - clk300mhz { - compatible = "fixed-clock"; - #clock-cells = <0x00>; - clock-frequency = <0x11e1a300>; - phandle = <0x0b>; - }; }; soc { diff --git a/src/jailhouse/configs/arm64/dts/inmate-e2000q-ivshmem-net.dts b/src/jailhouse/configs/arm64/dts/inmate-e2000q-ivshmem-net.dts new file mode 100644 index 0000000000000000000000000000000000000000..9b5e3df7101f136362415f06b7ab2db526164925 --- /dev/null +++ b/src/jailhouse/configs/arm64/dts/inmate-e2000q-ivshmem-net.dts @@ -0,0 +1,185 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for Phytium E2000Q ivshmem-net test, + * corresponding to configs/arm64/e2000q-linux-ivshmem-net-demo.c + * + * Copyright (c) 2022-2025 Phytium Technology Co., Ltd + * + * Authors: + * Huaizhi Wen + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +/dts-v1/; + +/memreserve/ 0x0000000080000000 0x0000000000010000; +/ { + compatible = "phytium,pe2204"; + interrupt-parent = <0x01>; + #address-cells = <0x02>; + #size-cells = <0x02>; + model = "Pe2204 DEMO DDR4"; + + hypervisor { + compatible = "jailhouse,cell"; + }; + + aliases { + serial1 = "/soc/uart@2800d000"; + }; + + chosen { + stdout-path = "serial1:115200n8"; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + cpu_suspend = <0xc4000001>; + cpu_off = <0x84000002>; + cpu_on = <0xc4000003>; + sys_poweroff = <0x84000008>; + sys_reset = <0x84000009>; + }; + + cpus { + #address-cells = <0x02>; + #size-cells = <0x00>; + + cpu@0 { + device_type = "cpu"; + compatible = "phytium,ftc310\0arm,armv8"; + reg = <0x00 0x200>; + enable-method = "psci"; + }; + + cpu@1 { + device_type = "cpu"; + compatible = "phytium,ftc310\0arm,armv8"; + reg = <0x00 0x201>; + enable-method = "psci"; + }; + }; + + gic: interrupt-controller@30800000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <0x03>; + #address-cells = <0x02>; + #size-cells = <0x02>; + ranges; + interrupt-controller; + reg = <0x00 0x30800000 0x00 0x20000 0x00 0x30880000 0x00 0x80000 0x00 0x30840000 0x00 0x10000 0x00 0x30850000 0x00 0x10000 0x00 0x30860000 0x00 0x10000>; + interrupts = <0x01 0x09 0x08>; + phandle = <0x01>; + }; + + pmu { + compatible = "arm,armv8-pmuv3"; + interrupts = <0x01 0x07 0x08>; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <0x01 0x0d 0x08 0x01 0x0e 0x08 0x01 0x0b 0x08 0x01 0x0a 0x08>; + clock-frequency = <0x2faf080>; + }; + + clocks { + #address-cells = <0x02>; + #size-cells = <0x02>; + ranges; + + sysclk_48mhz: clk48mhz { + compatible = "fixed-clock"; + #clock-cells = <0x00>; + clock-frequency = <0x2dc6c00>; + phandle = <0x13>; + }; + + sysclk_50mhz: clk50mhz { + compatible = "fixed-clock"; + #clock-cells = <0x00>; + clock-frequency = <0x2faf080>; + phandle = <0x0c>; + }; + + sysclk_100mhz: clk100mhz { + compatible = "fixed-clock"; + #clock-cells = <0x00>; + clock-frequency = <0x5f5e100>; + phandle = <0x0d>; + }; + + sysclk_200mhz: clk200mhz { + compatible = "fixed-clock"; + #clock-cells = <0x00>; + clock-frequency = <0xbebc200>; + phandle = <0x11>; + }; + + sysclk_250mhz: clk250mhz { + compatible = "fixed-clock"; + #clock-cells = <0x00>; + clock-frequency = <0xee6b280>; + phandle = <0x12>; + }; + + sysclk_300mhz: clk300mhz { + compatible = "fixed-clock"; + #clock-cells = <0x00>; + clock-frequency = <0x11e1a300>; + }; + + sysclk_600mhz: clk600mhz { + compatible = "fixed-clock"; + #clock-cells = <0x00>; + clock-frequency = <0x23c34600>; + phandle = <0x0e>; + }; + + sysclk_1200mhz: clk1200mhz { + compatible = "fixed-clock"; + #clock-cells = <0x00>; + clock-frequency = <0x47868c00>; + phandle = <0x0b>; + }; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <0x02>; + #size-cells = <0x02>; + dma-coherent; + ranges; + + uart@2800d000 { + compatible = "arm,pl011\0arm,primecell"; + reg = <0x00 0x2800d000 0x00 0x1000>; + interrupts = <0x00 0x54 0x04>; + clocks = <&sysclk_100mhz &sysclk_100mhz>; + clock-names = "uartclk\0apb_pclk"; + status = "okay"; + }; + + pci@34000000 { + compatible = "pci-host-ecam-generic"; + device_type = "pci"; + bus-range = <0 0>; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 7>; + interrupt-map = <0x00 0x00 0x00 0x01 &gic 0x00 0x00 0x00 0xbf 0x01>, + <0x00 0x00 0x00 0x02 &gic 0x00 0x00 0x00 0xc0 0x01>, + <0x00 0x00 0x00 0x03 &gic 0x00 0x00 0x00 0xc1 0x01>, + <0x00 0x00 0x00 0x04 &gic 0x00 0x00 0x00 0x3f 0x01>; + reg = <0x0 0x34000000 0x0 0x100000>; + ranges = <0x02000000 0x00 0x20000000 0x0 0x20000000 0x00 0x10000>; + }; + + }; +}; + diff --git a/src/jailhouse/configs/arm64/e2000q-linux-ivshmem-net-demo.c b/src/jailhouse/configs/arm64/e2000q-linux-ivshmem-net-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..eb8b6aff91c5a9f9f18873014436ac9c7f0a8a6a --- /dev/null +++ b/src/jailhouse/configs/arm64/e2000q-linux-ivshmem-net-demo.c @@ -0,0 +1,115 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Configuration for Phytium E2000Q ivshmem-net test + * Copyright (c) 2022-2025 Phytium Technology Co., Ltd + * + * Authors: + * Huaizhi Wen + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ +#include +#include + +struct { + struct jailhouse_cell_desc cell; + __u64 cpus[1]; + struct jailhouse_memory mem_regions[8]; + struct jailhouse_irqchip irqchips[2]; + struct jailhouse_pci_device pci_devices[1]; +} __attribute__((packed)) config = { + .cell = { + .signature = JAILHOUSE_CELL_DESC_SIGNATURE, + .revision = JAILHOUSE_CONFIG_REVISION, + .name = "linux-demo", + .flags = JAILHOUSE_CELL_PASSIVE_COMMREG | JAILHOUSE_CON_REGDIST_4, + + .cpu_set_size = sizeof(config.cpus), + .num_memory_regions = ARRAY_SIZE(config.mem_regions), + .num_irqchips = ARRAY_SIZE(config.irqchips), + .num_pci_devices = ARRAY_SIZE(config.pci_devices), + .cpu_reset_address = 0x0, + .vpci_irq_base = 223-32, + + .console = { + .address = 0x2800d000, + .type = JAILHOUSE_CON_TYPE_PL011, + .flags = JAILHOUSE_CON_ACCESS_MMIO | JAILHOUSE_CON_REGDIST_4, + }, + }, + + .cpus = { + 0x3, + }, + + .mem_regions = { + + JAILHOUSE_SHMEM_NET_REGIONS(0xb1010000, 1), + /* UART 1 */ + { + .phys_start = 0x2800d000, + .virt_start = 0x2800d000, + .size = 0x1000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_IO | JAILHOUSE_MEM_ROOTSHARED, + }, + + /* RAM: for linux-loader space */ + { + .phys_start = 0x2000000000, + .virt_start = 0x0, + .size = 0x00010000, /* 64KB */ + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE, + }, + + /* RAM */ + { + .phys_start = 0x2000080000, + .virt_start = 0x2000080000, + .size = 0x40000000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_EXECUTE | JAILHOUSE_MEM_LOADABLE | JAILHOUSE_MEM_DMA, + }, + + /* communication region */ + { + .virt_start = 0x80000000, + .size = 0x00001000, + .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_COMM_REGION, + }, + }, + + .irqchips = { + /* GIC */ + { + .address = 0x30800000, + .pin_base = 32, + .pin_bitmap = { + 0, + 1 << (95 - 64), + 1 << (116 - 96), /* UART1=116 */ + 0, + }, + }, + { + .address = 0x30800000, + .pin_base = 160, + .pin_bitmap = { + 0, 1 << (223 - 192), 1 << (224 - 224) | 1 << (225 - 224), 0, + }, + }, + }, + + .pci_devices = { + { /* IVSHMEM 0000:00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 0, + .shmem_dev_id = 1, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, + }, +}; diff --git a/src/jailhouse/configs/arm64/e2000q.c b/src/jailhouse/configs/arm64/e2000q.c index aa9fb4cdc8d41316e9329c2d1386228072a0287c..459b69be25ef3f2fdef920662adcbc8806988531 100644 --- a/src/jailhouse/configs/arm64/e2000q.c +++ b/src/jailhouse/configs/arm64/e2000q.c @@ -17,14 +17,14 @@ struct { struct jailhouse_system header; __u64 cpus[1]; - struct jailhouse_memory mem_regions[78]; - struct jailhouse_irqchip irqchips[1]; + struct jailhouse_memory mem_regions[82]; + struct jailhouse_irqchip irqchips[2]; #ifdef CONFIG_PCIE_E1000E_TEST - struct jailhouse_pci_device pci_devices[3]; + struct jailhouse_pci_device pci_devices[4]; struct jailhouse_pci_capability pci_caps[11]; union jailhouse_stream_id stream_ids[2]; #else - struct jailhouse_pci_device pci_devices[1]; + struct jailhouse_pci_device pci_devices[2]; #endif } __attribute__((packed)) config = { .header = { @@ -85,7 +85,7 @@ struct { .num_stream_ids = ARRAY_SIZE(config.stream_ids), #endif - .vpci_irq_base = 95-32, + .vpci_irq_base = 72-32, }, }, @@ -126,7 +126,7 @@ struct { .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE, }, - + JAILHOUSE_SHMEM_NET_REGIONS(0xb1010000, 0), /* Main Memory Address Space */ /* RAM-0 */ { @@ -682,6 +682,13 @@ struct { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, }, }, + { + .address = 0x30800000, + .pin_base = 160, + .pin_bitmap = { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + }, + }, }, .pci_devices = { @@ -695,6 +702,16 @@ struct { .shmem_peers = 3, .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED, }, + { /* IVSHMEM 0000:00:01.0 (networking) */ + .type = JAILHOUSE_PCI_TYPE_IVSHMEM, + .domain = 0, + .bdf = 1 << 3, + .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_INTX, + .shmem_regions_start = 5, + .shmem_dev_id = 0, + .shmem_peers = 2, + .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH, + }, #ifdef CONFIG_PCIE_E1000E_TEST /* PCI bridge @00:02.0 */ { diff --git a/src/jailhouse/driver/Makefile b/src/jailhouse/driver/Makefile index 25bd179d89465344a5b78e33573e5eb752b40d27..e0cf0483caa02407a3efb9a9ef32c76d04f9b462 100644 --- a/src/jailhouse/driver/Makefile +++ b/src/jailhouse/driver/Makefile @@ -12,12 +12,13 @@ # KERNEL_VERSION = $(shell echo $(KERNELRELEASE) | awk -F. '{ printf("%d%03d%03d\n", $$1, $$2, $$3); }') -TARGET_VERSION = 5010209 +TARGET_VERSION_5-10-209 = 5010209 obj-m := jailhouse.o -ifeq ($(shell [ $(KERNEL_VERSION) -ge $(TARGET_VERSION) ] && echo 1),1) +ifeq ($(shell [ $(KERNEL_VERSION) -ge $(TARGET_VERSION_5-10-209) ] && echo 1),1) obj-m += uio_ivshmem.o + obj-m += ivshmem-net.o endif ccflags-y := -I$(src)/../hypervisor/arch/$(SRCARCH)/include \ diff --git a/src/jailhouse/driver/ivshmem-net.c b/src/jailhouse/driver/ivshmem-net.c new file mode 100644 index 0000000000000000000000000000000000000000..c2d40cf7235222c128fefc25cd4bf73c21e79c72 --- /dev/null +++ b/src/jailhouse/driver/ivshmem-net.c @@ -0,0 +1,1135 @@ +/* + * Copyright 2016 Mans Rullgard + * Copyright (c) Siemens AG, 2016-2020 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IVSHM_PROTO_UNDEFINED 0x0000 +#define IVSHM_PROTO_NET 0x0001 +#define IVSHM_PROTO_VIRTIO_FRONT 0x8000 +#define IVSHM_PROTO_VIRTIO_BACK 0xc000 +#define IVSHM_PROTO_VIRTIO_DEVID_MASK 0x7fff + +#define IVSHM_CFG_PRIV_CNTL 0x03 +#define IVSHM_PRIV_CNTL_ONESHOT_INT BIT(0) +#define IVSHM_CFG_STATE_TAB_SZ 0x04 +#define IVSHM_CFG_RW_SECTION_SZ 0x08 +#define IVSHM_CFG_OUTPUT_SECTION_SZ 0x10 +#define IVSHM_CFG_ADDRESS 0x18 + +#define PCI_DEVICE_ID_IVSHMEM 0x4106 + +struct ivshm_regs { + u32 id; + u32 max_peers; + u32 int_control; + u32 doorbell; + u32 state; +}; + +#define IVSHM_INT_ENABLE BIT(0) + +#define DRV_NAME "ivshmem-net" + +#define IVSHM_NET_STATE_UNKNOWN (~0) +#define IVSHM_NET_STATE_RESET 0 +#define IVSHM_NET_STATE_INIT 1 +#define IVSHM_NET_STATE_READY 2 +#define IVSHM_NET_STATE_RUN 3 + +#define IVSHM_NET_FLAG_RUN 0 + +#define IVSHM_NET_MTU_DEF 16384 + +#define IVSHM_NET_FRAME_SIZE(s) ALIGN(18 + (s), SMP_CACHE_BYTES) + +#define IVSHM_NET_VQ_ALIGN 64 + +#define IVSHM_NET_SECTION_TX 0 +#define IVSHM_NET_SECTION_RX 1 + +#define IVSHM_NET_MSIX_STATE 0 +#define IVSHM_NET_MSIX_TX_RX 1 + +#define IVSHM_NET_NUM_VECTORS 2 + +struct ivshm_net_queue { + struct vring vr; + u32 free_head; + u32 num_free; + u32 num_added; + u16 last_avail_idx; + u16 last_used_idx; + + void *data; + void *end; + u32 size; + u32 head; + u32 tail; +}; + +struct ivshm_net_stats { + u32 tx_rx_interrupts; + u32 tx_packets; + u32 tx_notify; + u32 tx_pause; + u32 rx_packets; + u32 rx_notify; + u32 napi_poll; + u32 napi_complete; + u32 napi_poll_n[10]; +}; + +struct ivshm_net { + struct ivshm_net_queue rx; + struct ivshm_net_queue tx; + + u32 vrsize; + u32 qlen; + u32 qsize; + + struct napi_struct napi; + + struct mutex state_lock; + u32 state; + u32 last_peer_state; + u32 *state_table; + + unsigned long flags; + + struct workqueue_struct *state_wq; + struct work_struct state_work; + + struct ivshm_net_stats stats; + + struct ivshm_regs __iomem *ivshm_regs; + void *shm[2]; + resource_size_t shmlen; + u32 peer_id; + + u32 tx_rx_vector; + + struct pci_dev *pdev; +}; + +static void *ivshm_net_desc_data(struct ivshm_net *in, + struct ivshm_net_queue *q, + unsigned int region, + struct vring_desc *desc, + u32 *len) +{ + u64 offs = READ_ONCE(desc->addr); + u32 dlen = READ_ONCE(desc->len); + u16 flags = READ_ONCE(desc->flags); + void *data; + + if (flags) + return NULL; + + if (offs >= in->shmlen) + return NULL; + + data = in->shm[region] + offs; + + if (data < q->data || data >= q->end) + return NULL; + + if (dlen > q->end - data) + return NULL; + + *len = dlen; + + return data; +} + +static void ivshm_net_init_queue(struct ivshm_net *in, + struct ivshm_net_queue *q, + void *mem, unsigned int len) +{ + memset(q, 0, sizeof(*q)); + + vring_init(&q->vr, len, mem, IVSHM_NET_VQ_ALIGN); + q->data = mem + in->vrsize; + q->end = q->data + in->qsize; + q->size = in->qsize; +} + +static void ivshm_net_init_queues(struct net_device *ndev) +{ + struct ivshm_net *in = netdev_priv(ndev); + void *tx; + void *rx; + int i; + + tx = in->shm[IVSHM_NET_SECTION_TX]; + rx = in->shm[IVSHM_NET_SECTION_RX]; + + memset(tx, 0, in->shmlen); + + ivshm_net_init_queue(in, &in->tx, tx, in->qlen); + ivshm_net_init_queue(in, &in->rx, rx, in->qlen); + + swap(in->rx.vr.used, in->tx.vr.used); + + in->tx.num_free = in->tx.vr.num; + + for (i = 0; i < in->tx.vr.num - 1; i++) + in->tx.vr.desc[i].next = i + 1; +} + +static int ivshm_net_calc_qsize(struct net_device *ndev) +{ + struct ivshm_net *in = netdev_priv(ndev); + unsigned int vrsize; + unsigned int qsize; + unsigned int qlen; + + for (qlen = 4096; qlen > 32; qlen >>= 1) { + vrsize = vring_size(qlen, IVSHM_NET_VQ_ALIGN); + vrsize = ALIGN(vrsize, IVSHM_NET_VQ_ALIGN); + if (vrsize < in->shmlen / 8) + break; + } + + if (vrsize > in->shmlen) + return -EINVAL; + + qsize = in->shmlen - vrsize; + + if (qsize < 4 * ETH_MIN_MTU) + return -EINVAL; + + in->vrsize = vrsize; + in->qlen = qlen; + in->qsize = qsize; + + return 0; +} + +static void ivshm_net_notify_tx(struct ivshm_net *in, unsigned int num) +{ + u16 evt, old, new; + + virt_mb(); + + evt = READ_ONCE(vring_avail_event(&in->tx.vr)); + old = in->tx.last_avail_idx - num; + new = in->tx.last_avail_idx; + + if (vring_need_event(evt, new, old)) { + writel(in->tx_rx_vector | (in->peer_id << 16), + &in->ivshm_regs->doorbell); + in->stats.tx_notify++; + } +} + +static void ivshm_net_enable_rx_irq(struct ivshm_net *in) +{ + vring_avail_event(&in->rx.vr) = in->rx.last_avail_idx; + virt_wmb(); +} + +static void ivshm_net_notify_rx(struct ivshm_net *in, unsigned int num) +{ + u16 evt, old, new; + + virt_mb(); + + evt = READ_ONCE(vring_used_event(&in->rx.vr)); + old = in->rx.last_used_idx - num; + new = in->rx.last_used_idx; + + if (vring_need_event(evt, new, old)) { + writel(in->tx_rx_vector | (in->peer_id << 16), + &in->ivshm_regs->doorbell); + in->stats.rx_notify++; + } +} + +static void ivshm_net_enable_tx_irq(struct ivshm_net *in) +{ + vring_used_event(&in->tx.vr) = in->tx.last_used_idx; + virt_wmb(); +} + +static bool ivshm_net_rx_avail(struct ivshm_net *in) +{ + virt_mb(); + return READ_ONCE(in->rx.vr.avail->idx) != in->rx.last_avail_idx; +} + +static size_t ivshm_net_tx_space(struct ivshm_net *in) +{ + struct ivshm_net_queue *tx = &in->tx; + u32 tail = tx->tail; + u32 head = tx->head; + u32 space; + + if (head < tail) + space = tail - head; + else + space = max(tx->size - head, tail); + + return space; +} + +static bool ivshm_net_tx_ok(struct net_device *ndev) +{ + struct ivshm_net *in = netdev_priv(ndev); + + return in->tx.num_free >= 2 && + ivshm_net_tx_space(in) >= 2 * IVSHM_NET_FRAME_SIZE(ndev->mtu); +} + +static u32 ivshm_net_tx_advance(struct ivshm_net_queue *q, u32 *pos, u32 len) +{ + u32 p = *pos; + + len = IVSHM_NET_FRAME_SIZE(len); + + if (q->size - p < len) + p = 0; + *pos = p + len; + + return p; +} + +static bool ivshm_net_tx_clean(struct net_device *ndev) +{ + struct ivshm_net *in = netdev_priv(ndev); + struct ivshm_net_queue *tx = &in->tx; + struct vring_used_elem *used; + struct vring *vr = &tx->vr; + struct vring_desc *desc; + struct vring_desc *fdesc; + u16 last = tx->last_used_idx; + unsigned int num; + bool tx_ok; + u32 fhead; + + fdesc = NULL; + fhead = 0; + num = 0; + + while (last != virt_load_acquire(&vr->used->idx)) { + void *data; + u32 len; + u32 tail; + + used = vr->used->ring + (last % vr->num); + if (used->id >= vr->num || used->len != 1) { + netdev_err(ndev, "invalid tx used->id %d ->len %d\n", + used->id, used->len); + break; + } + + desc = &vr->desc[used->id]; + + data = ivshm_net_desc_data(in, &in->tx, IVSHM_NET_SECTION_TX, + desc, &len); + if (!data) { + netdev_err(ndev, "bad tx descriptor, data == NULL\n"); + break; + } + + tail = ivshm_net_tx_advance(tx, &tx->tail, len); + if (data != tx->data + tail) { + netdev_err(ndev, "bad tx descriptor\n"); + break; + } + + if (!num) + fdesc = desc; + else + desc->next = fhead; + + fhead = used->id; + + tx->last_used_idx = ++last; + num++; + tx->num_free++; + BUG_ON(tx->num_free > vr->num); + + tx_ok = ivshm_net_tx_ok(ndev); + if (!tx_ok) + ivshm_net_enable_tx_irq(in); + } + + if (num) { + fdesc->next = tx->free_head; + tx->free_head = fhead; + } else { + tx_ok = ivshm_net_tx_ok(ndev); + } + + return tx_ok; +} + +static void ivshm_net_tx_poll(struct net_device *ndev) +{ + struct netdev_queue *txq = netdev_get_tx_queue(ndev, 0); + + if (!__netif_tx_trylock(txq)) + return; + + if (ivshm_net_tx_clean(ndev) && netif_queue_stopped(ndev)) + netif_wake_queue(ndev); + + __netif_tx_unlock(txq); +} + +static struct vring_desc *ivshm_net_rx_desc(struct net_device *ndev) +{ + struct ivshm_net *in = netdev_priv(ndev); + struct ivshm_net_queue *rx = &in->rx; + struct vring *vr = &rx->vr; + unsigned int avail; + u16 avail_idx; + + avail_idx = virt_load_acquire(&vr->avail->idx); + + if (avail_idx == rx->last_avail_idx) + return NULL; + + avail = vr->avail->ring[rx->last_avail_idx++ & (vr->num - 1)]; + if (avail >= vr->num) { + netdev_err(ndev, "invalid rx avail %d\n", avail); + return NULL; + } + + return &vr->desc[avail]; +} + +static void ivshm_net_rx_finish(struct ivshm_net *in, struct vring_desc *desc) +{ + struct ivshm_net_queue *rx = &in->rx; + struct vring *vr = &rx->vr; + unsigned int desc_id = desc - vr->desc; + unsigned int used; + + used = rx->last_used_idx++ & (vr->num - 1); + vr->used->ring[used].id = desc_id; + vr->used->ring[used].len = 1; + + virt_store_release(&vr->used->idx, rx->last_used_idx); +} + +static int ivshm_net_poll(struct napi_struct *napi, int budget) +{ + struct net_device *ndev = napi->dev; + struct ivshm_net *in = container_of(napi, struct ivshm_net, napi); + int received = 0; + + in->stats.napi_poll++; + + ivshm_net_tx_poll(ndev); + + while (received < budget) { + struct vring_desc *desc; + struct sk_buff *skb; + void *data; + u32 len; + + desc = ivshm_net_rx_desc(ndev); + if (!desc) + break; + + data = ivshm_net_desc_data(in, &in->rx, IVSHM_NET_SECTION_RX, + desc, &len); + if (!data) { + netdev_err(ndev, "bad rx descriptor\n"); + break; + } + + skb = napi_alloc_skb(napi, len); + + if (skb) { + memcpy(skb_put(skb, len), data, len); + skb->protocol = eth_type_trans(skb, ndev); + napi_gro_receive(napi, skb); + } + + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += len; + + ivshm_net_rx_finish(in, desc); + received++; + } + + if (received < budget) { + in->stats.napi_complete++; + napi_complete_done(napi, received); + ivshm_net_enable_rx_irq(in); + if (ivshm_net_rx_avail(in)) + napi_schedule(napi); + } + + if (received) + ivshm_net_notify_rx(in, received); + + in->stats.rx_packets += received; + in->stats.napi_poll_n[received ? 1 + min(ilog2(received), 8) : 0]++; + + return received; +} + +static netdev_tx_t ivshm_net_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct ivshm_net *in = netdev_priv(ndev); + struct ivshm_net_queue *tx = &in->tx; + bool xmit_more = netdev_xmit_more(); + struct vring *vr = &tx->vr; + struct vring_desc *desc; + unsigned int desc_idx; + unsigned int avail; + u32 head; + void *buf; + + if (!ivshm_net_tx_clean(ndev)) { + netif_stop_queue(ndev); + + netdev_err(ndev, "BUG: tx ring full when queue awake!\n"); + return NETDEV_TX_BUSY; + } + + desc_idx = tx->free_head; + desc = &vr->desc[desc_idx]; + tx->free_head = desc->next; + tx->num_free--; + + head = ivshm_net_tx_advance(tx, &tx->head, skb->len); + + if (!ivshm_net_tx_ok(ndev)) { + ivshm_net_enable_tx_irq(in); + netif_stop_queue(ndev); + xmit_more = false; + in->stats.tx_pause++; + } + + buf = tx->data + head; + skb_copy_and_csum_dev(skb, buf); + + desc->addr = buf - in->shm[IVSHM_NET_SECTION_TX]; + desc->len = skb->len; + desc->flags = 0; + + avail = tx->last_avail_idx++ & (vr->num - 1); + vr->avail->ring[avail] = desc_idx; + tx->num_added++; + + virt_store_release(&vr->avail->idx, tx->last_avail_idx); + + if (!xmit_more) { + ivshm_net_notify_tx(in, tx->num_added); + tx->num_added = 0; + } + + in->stats.tx_packets++; + ndev->stats.tx_packets++; + ndev->stats.tx_bytes += skb->len; + + dev_consume_skb_any(skb); + + return NETDEV_TX_OK; +} + +static void ivshm_net_set_state(struct ivshm_net *in, u32 state) +{ + virt_wmb(); + WRITE_ONCE(in->state, state); + writel(state, &in->ivshm_regs->state); +} + +static void ivshm_net_run(struct net_device *ndev) +{ + struct ivshm_net *in = netdev_priv(ndev); + + if (in->state < IVSHM_NET_STATE_READY) + return; + + if (!netif_running(ndev)) + return; + + if (in->last_peer_state == IVSHM_NET_STATE_RUN) + netif_carrier_on(ndev); + + if (test_and_set_bit(IVSHM_NET_FLAG_RUN, &in->flags)) + return; + + netif_start_queue(ndev); + napi_enable(&in->napi); + local_bh_disable(); + napi_schedule(&in->napi); + local_bh_enable(); + ivshm_net_set_state(in, IVSHM_NET_STATE_RUN); +} + +static void ivshm_net_do_stop(struct net_device *ndev) +{ + struct ivshm_net *in = netdev_priv(ndev); + + ivshm_net_set_state(in, IVSHM_NET_STATE_RESET); + + if (!test_and_clear_bit(IVSHM_NET_FLAG_RUN, &in->flags)) + return; + + netif_carrier_off(ndev); + netif_stop_queue(ndev); + napi_disable(&in->napi); +} + +static void ivshm_net_state_change(struct work_struct *work) +{ + struct ivshm_net *in = container_of(work, struct ivshm_net, state_work); + struct net_device *ndev = in->napi.dev; + u32 peer_state = READ_ONCE(in->state_table[in->peer_id]); + + mutex_lock(&in->state_lock); + + if (peer_state == in->last_peer_state) { + mutex_unlock(&in->state_lock); + return; + } + + in->last_peer_state = peer_state; + + switch (in->state) { + case IVSHM_NET_STATE_RESET: + /* + * Wait for the remote to leave READY/RUN before transitioning + * to INIT. + */ + if (peer_state < IVSHM_NET_STATE_READY) + ivshm_net_set_state(in, IVSHM_NET_STATE_INIT); + break; + + case IVSHM_NET_STATE_INIT: + /* + * Wait for the remote to leave RESET before performing the + * initialization and moving to READY. + */ + if (peer_state > IVSHM_NET_STATE_RESET) { + ivshm_net_init_queues(ndev); + ivshm_net_set_state(in, IVSHM_NET_STATE_READY); + + mutex_unlock(&in->state_lock); + + rtnl_lock(); + call_netdevice_notifiers(NETDEV_CHANGEADDR, ndev); + rtnl_unlock(); + + return; + } + break; + + case IVSHM_NET_STATE_READY: + case IVSHM_NET_STATE_RUN: + if (peer_state >= IVSHM_NET_STATE_READY) { + /* + * Link is up and we are running once the remote is in + * READY or RUN. + */ + ivshm_net_run(ndev); + } else if (peer_state == IVSHM_NET_STATE_RESET) { + /* + * If the remote goes to RESET, we need to follow + * immediately. + */ + ivshm_net_do_stop(ndev); + } + break; + } + + mutex_unlock(&in->state_lock); +} + +static void ivshm_net_check_state(struct ivshm_net *in) +{ + queue_work(in->state_wq, &in->state_work); +} + +static irqreturn_t ivshm_net_int_state(int irq, void *data) +{ + struct ivshm_net *in = data; + + ivshm_net_check_state(in); + + return IRQ_HANDLED; +} + +static irqreturn_t ivshm_net_int_tx_rx(int irq, void *data) +{ + struct ivshm_net *in = data; + + in->stats.tx_rx_interrupts++; + + napi_schedule_irqoff(&in->napi); + + return IRQ_HANDLED; +} + +static irqreturn_t ivshm_net_intx(int irq, void *data) +{ + ivshm_net_int_state(irq, data); + ivshm_net_int_tx_rx(irq, data); + + return IRQ_HANDLED; +} + +static int ivshm_net_open(struct net_device *ndev) +{ + struct ivshm_net *in = netdev_priv(ndev); + + netdev_reset_queue(ndev); + ndev->operstate = IF_OPER_UP; + + mutex_lock(&in->state_lock); + ivshm_net_run(ndev); + mutex_unlock(&in->state_lock); + + return 0; +} + +static int ivshm_net_stop(struct net_device *ndev) +{ + struct ivshm_net *in = netdev_priv(ndev); + + ndev->operstate = IF_OPER_DOWN; + + mutex_lock(&in->state_lock); + ivshm_net_do_stop(ndev); + mutex_unlock(&in->state_lock); + + return 0; +} + +static int ivshm_net_change_mtu(struct net_device *ndev, int mtu) +{ + if (netif_running(ndev)) { + netdev_err(ndev, "must be stopped to change its MTU\n"); + return -EBUSY; + } + + ndev->mtu = mtu; + + return 0; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void ivshm_net_poll_controller(struct net_device *ndev) +{ + struct ivshm_net *in = netdev_priv(ndev); + + napi_schedule(&in->napi); +} +#endif + +static const struct net_device_ops ivshm_net_ops = { + .ndo_open = ivshm_net_open, + .ndo_stop = ivshm_net_stop, + .ndo_start_xmit = ivshm_net_xmit, + .ndo_change_mtu = ivshm_net_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ivshm_net_poll_controller, +#endif +}; + +static const char ivshm_net_stats[][ETH_GSTRING_LEN] = { + "tx_rx_interrupts", + "tx_packets", + "tx_notify", + "tx_pause", + "rx_packets", + "rx_notify", + "napi_poll", + "napi_complete", + "napi_poll_0", + "napi_poll_1", + "napi_poll_2", + "napi_poll_4", + "napi_poll_8", + "napi_poll_16", + "napi_poll_32", + "napi_poll_64", + "napi_poll_128", + "napi_poll_256", +}; + +#define NUM_STATS ARRAY_SIZE(ivshm_net_stats) + +static int ivshm_net_get_sset_count(struct net_device *ndev, int sset) +{ + if (sset == ETH_SS_STATS) + return NUM_STATS; + + return -EOPNOTSUPP; +} + +static void ivshm_net_get_strings(struct net_device *ndev, u32 sset, u8 *buf) +{ + if (sset == ETH_SS_STATS) + memcpy(buf, &ivshm_net_stats, sizeof(ivshm_net_stats)); +} + +static void ivshm_net_get_ethtool_stats(struct net_device *ndev, + struct ethtool_stats *estats, u64 *st) +{ + struct ivshm_net *in = netdev_priv(ndev); + unsigned int n = 0; + unsigned int i; + + st[n++] = in->stats.tx_rx_interrupts; + st[n++] = in->stats.tx_packets; + st[n++] = in->stats.tx_notify; + st[n++] = in->stats.tx_pause; + st[n++] = in->stats.rx_packets; + st[n++] = in->stats.rx_notify; + st[n++] = in->stats.napi_poll; + st[n++] = in->stats.napi_complete; + + for (i = 0; i < ARRAY_SIZE(in->stats.napi_poll_n); i++) + st[n++] = in->stats.napi_poll_n[i]; + + memset(&in->stats, 0, sizeof(in->stats)); +} + +#define IVSHM_NET_REGS_LEN (3 * sizeof(u32) + 6 * sizeof(u16)) + +static int ivshm_net_get_regs_len(struct net_device *ndev) +{ + return IVSHM_NET_REGS_LEN; +} + +static void ivshm_net_get_regs(struct net_device *ndev, + struct ethtool_regs *regs, void *p) +{ + struct ivshm_net *in = netdev_priv(ndev); + u32 *reg32 = p; + u16 *reg16; + + *reg32++ = in->state; + *reg32++ = in->last_peer_state; + *reg32++ = in->qlen; + + reg16 = (u16 *)reg32; + + *reg16++ = in->tx.vr.avail ? in->tx.vr.avail->idx : 0; + *reg16++ = in->tx.vr.used ? in->tx.vr.used->idx : 0; + *reg16++ = in->tx.vr.avail ? vring_avail_event(&in->tx.vr) : 0; + + *reg16++ = in->rx.vr.avail ? in->rx.vr.avail->idx : 0; + *reg16++ = in->rx.vr.used ? in->rx.vr.used->idx : 0; + *reg16++ = in->rx.vr.avail ? vring_avail_event(&in->rx.vr) : 0; +} + +static const struct ethtool_ops ivshm_net_ethtool_ops = { + .get_sset_count = ivshm_net_get_sset_count, + .get_strings = ivshm_net_get_strings, + .get_ethtool_stats = ivshm_net_get_ethtool_stats, + .get_regs_len = ivshm_net_get_regs_len, + .get_regs = ivshm_net_get_regs, +}; + +static u64 get_config_qword(struct pci_dev *pdev, unsigned int pos) +{ + u32 lo, hi; + + pci_read_config_dword(pdev, pos, &lo); + pci_read_config_dword(pdev, pos + 4, &hi); + return lo | ((u64)hi << 32); +} + +static int ivshm_net_probe(struct pci_dev *pdev, + const struct pci_device_id *pci_id) +{ + phys_addr_t output_sections_addr, section_addr; + resource_size_t section_sz, output_section_sz; + void *state_table, *output_sections; + struct ivshm_regs __iomem *regs; + struct net_device *ndev; + struct ivshm_net *in; + unsigned int cap_pos; + char *device_name; + int vendor_cap; + u32 id, dword; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) { + dev_err(&pdev->dev, "pci_enable_device: %d\n", ret); + return ret; + } + + ret = pcim_iomap_regions(pdev, BIT(0), DRV_NAME); + if (ret) { + dev_err(&pdev->dev, "pcim_iomap_regions: %d\n", ret); + return ret; + } + + regs = pcim_iomap_table(pdev)[0]; + + id = readl(®s->id); + if (id > 1) { + dev_err(&pdev->dev, "invalid ID %d\n", id); + return -EINVAL; + } + if (readl(®s->max_peers) > 2) { + dev_err(&pdev->dev, "only 2 peers supported\n"); + return -EINVAL; + } + + vendor_cap = pci_find_capability(pdev, PCI_CAP_ID_VNDR); + if (vendor_cap < 0) { + dev_err(&pdev->dev, "missing vendor capability\n"); + return -EINVAL; + } + + if (pci_resource_len(pdev, 2) > 0) { + section_addr = pci_resource_start(pdev, 2); + } else { + cap_pos = vendor_cap + IVSHM_CFG_ADDRESS; + section_addr = get_config_qword(pdev, cap_pos); + } + + cap_pos = vendor_cap + IVSHM_CFG_STATE_TAB_SZ; + pci_read_config_dword(pdev, cap_pos, &dword); + section_sz = dword; + + if (!devm_request_mem_region(&pdev->dev, section_addr, section_sz, + DRV_NAME)) + return -EBUSY; + + state_table = devm_memremap(&pdev->dev, section_addr, section_sz, + MEMREMAP_WB); + if (!state_table) + return -ENOMEM; + + output_sections_addr = section_addr + section_sz; + + cap_pos = vendor_cap + IVSHM_CFG_RW_SECTION_SZ; + section_sz = get_config_qword(pdev, cap_pos); + if (section_sz > 0) { + dev_info(&pdev->dev, "R/W section detected - " + "unused by this driver version\n"); + output_sections_addr += section_sz; + } + + cap_pos = vendor_cap + IVSHM_CFG_OUTPUT_SECTION_SZ; + output_section_sz = get_config_qword(pdev, cap_pos); + if (output_section_sz == 0) { + dev_err(&pdev->dev, "Missing input/output sections\n"); + return -EINVAL; + } + + if (!devm_request_mem_region(&pdev->dev, output_sections_addr, + output_section_sz * 2, DRV_NAME)) + return -EBUSY; + + output_sections = devm_memremap(&pdev->dev, output_sections_addr, + output_section_sz * 2, MEMREMAP_WB); + if (!output_sections) + return -ENOMEM; + + section_addr = output_sections_addr + output_section_sz * id; + dev_info(&pdev->dev, "TX memory at %pa, size %pa\n", + §ion_addr, &output_section_sz); + section_addr = output_sections_addr + output_section_sz * !id; + dev_info(&pdev->dev, "RX memory at %pa, size %pa\n", + §ion_addr, &output_section_sz); + + device_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s[%s]", DRV_NAME, + dev_name(&pdev->dev)); + if (!device_name) + return -ENOMEM; + + ndev = alloc_etherdev(sizeof(*in)); + if (!ndev) + return -ENOMEM; + + pci_set_drvdata(pdev, ndev); + SET_NETDEV_DEV(ndev, &pdev->dev); + + in = netdev_priv(ndev); + in->ivshm_regs = regs; + in->state_table = state_table; + + in->shm[IVSHM_NET_SECTION_TX] = + output_sections + output_section_sz * id; + in->shm[IVSHM_NET_SECTION_RX] = + output_sections + output_section_sz * !id; + + in->shmlen = output_section_sz; + + in->peer_id = !id; + in->pdev = pdev; + in->last_peer_state = IVSHM_NET_STATE_UNKNOWN; + + mutex_init(&in->state_lock); + + ret = ivshm_net_calc_qsize(ndev); + if (ret) + goto err_free; + + in->state_wq = alloc_ordered_workqueue(device_name, 0); + if (!in->state_wq) + goto err_free; + + INIT_WORK(&in->state_work, ivshm_net_state_change); + + eth_hw_addr_random(ndev); + ndev->netdev_ops = &ivshm_net_ops; + ndev->ethtool_ops = &ivshm_net_ethtool_ops; + ndev->mtu = min_t(u32, IVSHM_NET_MTU_DEF, in->qsize / 16); + ndev->min_mtu = ETH_MIN_MTU; + ndev->max_mtu = min_t(u32, ETH_MAX_MTU, in->qsize / 4); + ndev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG; + ndev->features = ndev->hw_features; + + netif_carrier_off(ndev); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0) + netif_napi_add(ndev, &in->napi, ivshm_net_poll, NAPI_POLL_WEIGHT); +#else + netif_napi_add(ndev, &in->napi, ivshm_net_poll); +#endif + + ret = register_netdev(ndev); + if (ret) + goto err_wq; + + ret = pci_alloc_irq_vectors(pdev, 1, 2, PCI_IRQ_LEGACY | PCI_IRQ_MSIX); + if (ret < 0) + goto err_alloc_irq; + + if (pdev->msix_enabled) { + if (ret != 2) { + ret = -EBUSY; + goto err_request_irq; + } + + device_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, + "%s-state[%s]", DRV_NAME, + dev_name(&pdev->dev)); + if (!device_name) { + ret = -ENOMEM; + goto err_request_irq; + } + + ret = request_irq(pci_irq_vector(pdev, IVSHM_NET_MSIX_STATE), + ivshm_net_int_state, 0, device_name, in); + if (ret) + goto err_request_irq; + + device_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, + "%s-tx-rx[%s]", DRV_NAME, + dev_name(&pdev->dev)); + if (!device_name) { + ret = -ENOMEM; + goto err_request_irq2; + } + + ret = request_irq(pci_irq_vector(pdev, IVSHM_NET_MSIX_TX_RX), + ivshm_net_int_tx_rx, 0, device_name, in); + if (ret) + goto err_request_irq2; + + in->tx_rx_vector = IVSHM_NET_MSIX_TX_RX; + } else { + ret = request_irq(pci_irq_vector(pdev, 0), ivshm_net_intx, 0, + device_name, in); + if (ret) + goto err_request_irq; + + in->tx_rx_vector = 0; + } + + pci_set_master(pdev); + + pci_write_config_byte(pdev, vendor_cap + IVSHM_CFG_PRIV_CNTL, 0); + writel(IVSHM_INT_ENABLE, &in->ivshm_regs->int_control); + + writel(IVSHM_NET_STATE_RESET, &in->ivshm_regs->state); + ivshm_net_check_state(in); + + return 0; + +err_request_irq2: + free_irq(pci_irq_vector(pdev, IVSHM_NET_MSIX_STATE), in); +err_request_irq: + pci_free_irq_vectors(pdev); +err_alloc_irq: + unregister_netdev(ndev); +err_wq: + destroy_workqueue(in->state_wq); +err_free: + free_netdev(ndev); + + return ret; +} + +static void ivshm_net_remove(struct pci_dev *pdev) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + struct ivshm_net *in = netdev_priv(ndev); + + writel(IVSHM_NET_STATE_RESET, &in->ivshm_regs->state); + writel(0, &in->ivshm_regs->int_control); + + if (pdev->msix_enabled) { + free_irq(pci_irq_vector(pdev, IVSHM_NET_MSIX_STATE), in); + free_irq(pci_irq_vector(pdev, IVSHM_NET_MSIX_TX_RX), in); + } else { + free_irq(pci_irq_vector(pdev, 0), in); + } + pci_free_irq_vectors(pdev); + + unregister_netdev(ndev); + cancel_work_sync(&in->state_work); + destroy_workqueue(in->state_wq); + free_netdev(ndev); +} + +static const struct pci_device_id ivshm_net_id_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_SIEMENS, PCI_DEVICE_ID_IVSHMEM), + (PCI_CLASS_OTHERS << 16) | IVSHM_PROTO_NET, 0xffffff }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, ivshm_net_id_table); + +static struct pci_driver ivshm_net_driver = { + .name = DRV_NAME, + .id_table = ivshm_net_id_table, + .probe = ivshm_net_probe, + .remove = ivshm_net_remove, +}; +module_pci_driver(ivshm_net_driver); + +MODULE_AUTHOR("Mans Rullgard "); +MODULE_LICENSE("GPL"); diff --git a/src/jailhouse/driver/pci.c b/src/jailhouse/driver/pci.c index 0a8f39df9fb581331acf428271c638f5f2c3863c..d22a8f33937fd95c6ad9b2fbdb18d524fdd22114 100644 --- a/src/jailhouse/driver/pci.c +++ b/src/jailhouse/driver/pci.c @@ -513,11 +513,18 @@ static void destroy_vpci_of_overlay(void) void jailhouse_pci_virtual_root_devices_add(struct jailhouse_system *config) { - if (config->platform_info.pci_is_virtual && config->platform_info.num_pcie_units) { + if (config->platform_info.pci_is_virtual && + config->platform_info.num_pcie_units) { pr_warn("jailhouse: We only support virtual PCIe on a single PCIe region mode\n"); return; } + if (config->platform_info.pci_is_virtual && + config->platform_info.pci_mmconfig_base > MAX_VIRTUAL_PCI_ADDRESS) { + pr_warn("jailhouse: IVSHMEM devices only support the lower 32-bit address space\n"); + return; + } + if (config->platform_info.pci_is_virtual && !create_vpci_of_overlay(config)) { pr_warn("jailhouse: failed to add virtual host controller\n"); diff --git a/src/jailhouse/driver/pci.h b/src/jailhouse/driver/pci.h index 598c6c8d3bc8174a6eb4e2aa078744f9df1253f0..3bb396dfe3ec0873f11927838f6e060d8d80ce63 100644 --- a/src/jailhouse/driver/pci.h +++ b/src/jailhouse/driver/pci.h @@ -13,6 +13,8 @@ #include "cell.h" +#define MAX_VIRTUAL_PCI_ADDRESS 0xFFFFFFFF + enum { JAILHOUSE_PCI_ACTION_ADD, JAILHOUSE_PCI_ACTION_DEL, JAILHOUSE_PCI_ACTION_CLAIM, JAILHOUSE_PCI_ACTION_RELEASE, diff --git a/src/jailhouse/include/jailhouse/cell-config.h b/src/jailhouse/include/jailhouse/cell-config.h index 946ebd4d9436957f396290499be43ad1d81b5431..894d38fd6da9285be3beded6de856c6432bbedfc 100644 --- a/src/jailhouse/include/jailhouse/cell-config.h +++ b/src/jailhouse/include/jailhouse/cell-config.h @@ -174,7 +174,7 @@ struct jailhouse_irqchip { __u64 address; __u32 id; __u32 pin_base; - __u32 pin_bitmap[22]; + __u32 pin_bitmap[4]; } __attribute__((packed)); #define JAILHOUSE_PCI_TYPE_DEVICE 0x01 diff --git a/src/jailhouse/tools/Makefile b/src/jailhouse/tools/Makefile index d513ad1789e0bad44c63a9baa6276eef3c33dab9..e04440d8c0217336af750a70108740d9f2fa5306 100644 --- a/src/jailhouse/tools/Makefile +++ b/src/jailhouse/tools/Makefile @@ -35,7 +35,9 @@ KBUILD_CFLAGS += $(call cc-option, -fno-pie) KBUILD_CFLAGS += $(call cc-option, -no-pie) BINARIES := jailhouse demos/ivshmem-demo -targets += jailhouse.o demos/ivshmem-demo.o +BINARIES += jailhouse demos/ivshmem-net-server +BINARIES += jailhouse demos/ivshmem-net-client +targets += jailhouse.o demos/ivshmem-demo.o ivshmem-net-server.o ivshmem-net-client.o ifeq ($(ARCH),x86) BINARIES += demos/cache-timings diff --git a/src/jailhouse/tools/demos/ivshmem-net-client.c b/src/jailhouse/tools/demos/ivshmem-net-client.c new file mode 100644 index 0000000000000000000000000000000000000000..4f6b051cca0861ad0490064e4cb5c1ff7491b3b8 --- /dev/null +++ b/src/jailhouse/tools/demos/ivshmem-net-client.c @@ -0,0 +1,99 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Phytium Technology Co., Ltd. + * + * Authors: Huaizhi Wen + * + * This work is licensed under the terms of the GNU GPL, version 2. + * See the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include + +#define DEFAULT_PORT 8080 +#define DEFAULT_IP "127.0.0.1" +#define BUFFER_SIZE 1024 + +int main(int argc, char *argv[]) { + if (argc > 3) { + fprintf(stderr, "Usage: %s [server_ip] [port]\n", argv[0]); + exit(EXIT_FAILURE); + } + + const char *ip = DEFAULT_IP; + int port = DEFAULT_PORT; + + if (argc >= 2) ip = argv[1]; + if (argc == 3) port = atoi(argv[2]); + + if (port <= 0 || port > 65535) { + fprintf(stderr, "Invalid port number: %d\n", port); + exit(EXIT_FAILURE); + } + + int sock; + struct sockaddr_in serv_addr; + char buffer[BUFFER_SIZE] = {0}; + + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("socket creation error"); + exit(EXIT_FAILURE); + } + + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(port); + + if (inet_pton(AF_INET, ip, &serv_addr.sin_addr) <= 0) { + perror("invalid address"); + exit(EXIT_FAILURE); + } + + printf("Connecting to %s:%d...\n", ip, port); + + if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { + perror("connection failed"); + exit(EXIT_FAILURE); + } + + printf("Connected to server\n"); + + while (1) { + printf("Enter message (or 'exit' to quit): "); + char* ret = fgets(buffer, BUFFER_SIZE, stdin); + + if (ret == NULL) { + printf("No input or input error\n"); + break; + } + + buffer[strcspn(buffer, "\n")] = '\0'; + + if (strcmp(buffer, "exit") == 0) { + printf("Disconnecting...\n"); + break; + } + + if (send(sock, buffer, strlen(buffer), 0) < 0) { + perror("send failed"); + break; + } + + memset(buffer, 0, BUFFER_SIZE); + ssize_t valread = read(sock, buffer, BUFFER_SIZE - 1); + + if (valread <= 0) { + printf("Server disconnected\n"); + break; + } + + printf("Server reply: %s\n", buffer); + } + + close(sock); + return 0; +} diff --git a/src/jailhouse/tools/demos/ivshmem-net-server.c b/src/jailhouse/tools/demos/ivshmem-net-server.c new file mode 100644 index 0000000000000000000000000000000000000000..b9e0497c44eb6ee5ef1ba39b1089c69ebc4e2f7e --- /dev/null +++ b/src/jailhouse/tools/demos/ivshmem-net-server.c @@ -0,0 +1,96 @@ +/* + * Jailhouse, a Linux-based partitioning hypervisor + * + * Copyright (c) Phytium Technology Co., Ltd. + * + * Authors: Huaizhi Wen + * + * This work is licensed under the terms of the GNU GPL, version 2. + * See the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include + +#define DEFAULT_PORT 8080 +#define BUFFER_SIZE 1024 + +int main(int argc, char *argv[]) { + if (argc > 2) { + fprintf(stderr, "Usage: %s [port]\n", argv[0]); + exit(EXIT_FAILURE); + } + + int port = DEFAULT_PORT; + if (argc == 2) { + port = atoi(argv[1]); + if (port <= 0 || port > 65535) { + fprintf(stderr, "Invalid port number: %d\n", port); + exit(EXIT_FAILURE); + } + } + + int server_fd, new_socket; + struct sockaddr_in address; + int opt = 1; + int addrlen = sizeof(address); + char buffer[BUFFER_SIZE] = {0}; + + if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { + perror("socket failed"); + exit(EXIT_FAILURE); + } + + if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { + perror("setsockopt"); + exit(EXIT_FAILURE); + } + + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons(port); + + if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { + perror("bind failed"); + exit(EXIT_FAILURE); + } + + if (listen(server_fd, 3) < 0) { + perror("listen"); + exit(EXIT_FAILURE); + } + + printf("Server listening on port %d\n", port); + + if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) { + perror("accept"); + exit(EXIT_FAILURE); + } + + printf("Client connected\n"); + + while (1) { + memset(buffer, 0, BUFFER_SIZE); + ssize_t valread = read(new_socket, buffer, BUFFER_SIZE - 1); + + if (valread <= 0) { + printf("Connection closed\n"); + break; + } + + printf("Received: %s\n", buffer); + + const char *reply = "Message received by server"; + if (send(new_socket, reply, strlen(reply), 0) < 0) { + perror("send failed"); + break; + } + } + + close(new_socket); + close(server_fd); + return 0; +}