让Thunderbolt可以使用更大的BAR

问题描述 在Xilinx 7-Series FPGA上用AXI Memory Mapped to PCI Express IP核设置了一个256M的BAR,这个BAR直接连接到主板的PCIe上可以正常进行MMIO,但将FPGA通过Thunderbolt硬盘盒+M.2转PCIe连接到Thunderbolt上却无法使用。 通过查阅dmesg可观测到如下报错信息: [ 246.677146] pci 0000:0c:00.0: BAR 0: no…

Draco(MICRO'20) Architectural and Operating System Support for System Call Security 阅读笔记

要解决的问题 Linux内核提供了seccomp来对syscall权限进行检查,被广泛应用在容器、沙盒等多种场景,例如Docker和Android。但原版seccomp的实现是通过BPF对定义的规则一条条进行检查,如下图所示,十分低效: 同时,作者也进行了一系列的benchmark发现这样的检查带来了较大的开销: 其中,左边的docker-default指的是Docker默认使用的seccomp-profile,syscall-noargs指的是使application-specific profile但只检查syscall id而不检查参数,而syscall-complete就在noargs的基础上加上参数检查,最后加上-2x的后缀表示的是这些检查复制2次,来建模更复杂的安全检查场景。 可以看出,seccomp检查带来的开销即使是对于像nginx这样的macro-benchmarks也是比较大的,但现有的seccomp使用BPF,规则十分灵活,因此需要针对这种灵活的规则设计一种加速的方法。 Observation 检查系统调用ID会给Docker容器中的应用带来明显(noticeable)的性能开销。 检查系统调用参数比只检查系统调用ID的开销大得多(significantly more expensive)。 规则加倍,开销加倍。 syscall with 相同id和参数存在局部性(下图指明了实验中的距离) 解决方法 为了解决这个问题,作者引入了一个Fast…

聊聊内存序

最近读完了 A Primer on Memory Consistency and Cache Coherence这本书,写一篇文章结合我个人了解的其他知识总结一下内存序。 文章假定读者学习了基本的体系结构。 概念 Cache Coherence 相信大家对Cache有一个基本的理解。但这里需要引出一个新的概念,共享内存中的Private Cache。 即使是简单的单核处理器,往往L1 I-Cache与D-Cache也是Private的。因为IFU(取指单元)与LSU(访存单元)通常分布在处理器流水线的不同阶段,它们可能需要同时访问。既然是Private,这个时候如果我们通过访存指令写入了一些指令(通过D-Cache)到某个内存地址,而这个地址已经在I-Cache中,结果就在取指时有可能取到旧值,如何解决这一问题? 也许L1…

在Xilinx FPGA上搭建SoC

背景 之前出于科研需求和龙芯杯比赛需求都自己搭建过SoC来运行CPU软核,整理一下我的搭建SoC的流程。以下的讨论基于MIPS和RISC-V两种软核ISA为例。 大家也可以参考我搭建的两个SoC以及对应的软件: cyysoc (RISC-V Rocket+Coherent DMA) pblaze_soc 某大船SSD上的xc7k325t-2 FPGA+2G 72bit DDR3 ECC 用了某个PCI-E引出到SFP接口的扩展板,连接光模块/电口模块提供网络 PCI-E和SFP的IO在FPGA上都是GTX 用了某个该板子的IO接口转USB UART的扩展板 扩展板上面还有rgmii…

基于PiKVM制作M1 Mac Mini KVM

背景 因科研需求,让实验室购买了一台M1芯片的Mac Mini进行相关测试。但由于我的操作会涉及大量Kernel Panic,且希望将机器丢在远端,因此需要有一种方法能够让我远程进行真机的键盘鼠标操作以及按电源键的操作。 相关工作 之前有了解到PiKVM项目,通过树莓派的OTG功能接上HDMI采集卡,就可以实现远程控制电脑的键盘鼠标,并可以自定义各种GPIO的设备,实现连接开关按钮、LED指示灯,甚至还支持伺服电机,能够直接连接机械手完成按电源键的操作。 此外,它还可以通过OTG模拟一个ncm/rndis网卡、USB串口、USB光驱、U盘等设备。但值得注意的是,这些设备在macOS与Linux中均可使用,但U-Boot不支持ncm/rndis网卡与USB串口,甚至打开后会导致U-Boot中无法使用PiKVM键盘控制(原因待研究)。 挑战 最大的挑战在于,Apple Silicon的Mac不再像之前的x86机器那样,通过按住键盘上的option就可以进入启动菜单,而需要长按电源键,这就给远程管理带来了困难。 受到twd2的这三篇文章启发(远程控制Apple M1 Mac Mini、制作Apple M1 Mac Mini远程控制装置、安装Apple M1…

浅谈现代处理器实现超大L1 Cache的方式

浅谈现代处理器实现超大L1 Cache的方式 昨天观看WWDC时看到Apple M2处理器的L1 Cache大小已经达到了192K+128K,这不禁使我产生好奇,Apple如何做到这一点。(尽管事后发现M1处理器已经实现了,但那时的我还不懂电路上的困难。) 超大L1 Cache是一件复杂的事情,对于L1 Cache,我们都希望它的访问延迟尽可能低。而由于我们目前的处理器和操作系统采用的虚拟内存分页机制,在使用虚拟地址访问内存时,需要首先得到对应虚拟地址的物理地址,这就导致在一条访存指令算出访存的虚拟地址后,我们首先需要查询TLB,而若查询TLB再将地址送入缓存,无疑增加了访问延迟。而对于许多高性能设计的处理器而言,L1 Cache的访问往往是制约处理器频率的主要关键路径,因此涉及到L1 Cache的电路路径都需要非常慎重考虑具体设计的路径长度。 基于目前CPU中的Cache主要采用组相连的结构,在该结构上解决方法通常采用VIPT的方式,即Virtually Indexed Physically Tagged。如下图所示,通过虚拟地址的一部分作为访问Cache的索引,同时将虚拟地址送入TLB中,这样我们就实现了电路上访问Cache与访问TLB的并行,在访问结束后对比TLB输出的物理地址高位与Cache访问得到的物理地址Tag,就完成了缓存是否命中的判断。 VIPT Cache在具体实现时,我们需要考虑缓存重名的问题。例如CPU上运行着2个进程有一个共享内存,这块共享内存对应着一块物理地址,但在2个进程中的虚拟地址不同,而如果CPU只是简单地将两份虚拟地址的数据都直接保存在缓存中,就会导致缓存不一致的问题。 SOTA的大部分处理器并未解决该问题(例如我们常见的Intel和AMD),只是将VIPT简化为伪VIPT。因为在许多ISA的虚拟内存管理中,最小页面大小为4KB,因此,我只需要保证作为Index的部分在虚拟地址的低12位内(即4KB内)即可。不过,这种方法导致L1 Cache中单路的大小无法超过MMU规定的最小页面大小,而组相连的场景下,随着路数增加,电路上判断并选择带来的电路长度也随之增加,同样提高了电路的延迟,导致频率的降低或划分流水线阶段后IPC(Instructions…

调试sfence.vma,12天之差错过Linux Patch一个

起因 最近造了个RISC-V CPU模拟器——CEMU,并实现了软件模拟TLB来加速地址翻译。而TLB和页表并不自带一致性,在RISC-V上需使用sfence.vma这样的指令来刷掉TLB和Page Table Cache(如果存在)和硬件流水线上的指令来确保页表修改生效。并通过了RISC-V Test中的所有测试,然而在启动Linux进入Busybox却遇到如下问题: 尽管Busybox能跑起来并正常使用,但同样的内核在qemu和Rocket上都是完全正常的,因此我继续探索了一下可能的问题。后来objdump了一下busybox的这个地址,发现是一条ret(jalr)指令,而跳转的地址是从栈上ld的。 因此我就怀疑是页表出现了问题导致fork的时候这个进程的栈对别的进程的栈产生了破坏。 第一次尝试 我首先怀疑了TLB查找出现问题,因此我修改了sfence.vma指令的实现,将sfence.vma实现为不管asid和va,全刷TLB,结果用户进程正常载入了。 后续继续做了些尝试,发现只要在执行sfence.vma的时候忽略ASID,但保留va的判断,用户进程依然正常运行。 第二次尝试 这次在实验室里twd2和dram一起来看我调试了。我在每次TLB Hit的情况下都重新进行一遍Page Table Walk,并检查Walk出来的PTE结果和TLB的区别。 结果发现Linux Kernel在一个Hart启动的时候会出现一次页表的W位不同的问题,但那是一条sfence.vma指令的fetch,所以没有对运行结果产生影响。…

U-Boot RISC-V M Mode的灵车SMP启动

为了方便运行任意M Mode软件,同时不想自制Bootloader。我决定在我的RISC-V SoC上使用M Mode U-Boot。然后再上面跑OpenSBI再把Linux作为OpenSBI的Payload运行。但U-Boot的go命令只会修改当前Hart的PC,并不会让其他Hart进行跳转。这就导致后续OpenSBI启动Linux一发送IPI就不断进入Trap Handler。 最后我想了个简单解决方法是,一旦进入Trap Handler且发现是当前无法解决的Trap就跳转到DRAM_BASE(也就是OpenSBI的TEXT段开始地址),并将a0寄存器设置上hartid(符合OpenSBI要求)。这样当IPI产生时其他核就会进入OpenSBI。配合Rocket Chip开双核,经过多次测试,Linux SMP均正常工作。不过比较灵车,理论上正确做法应该修改U-Boot代码控制其他核的IPI跳转。 修改在此:https://github.com/cyyself/u-boot/commit/c637a978068c434691899f1139b8b3e6c45efc93 在这种方法下,只需要保证设备树科学,然后使用u-boot通过tftp/串口将OpenSBI编译的fw_payload.bin载入到DRAM_BASE,然后使用go 0x80000000即可完成SMP启动。不过这种灵车做法需要确保的是,启动过程发送IPI之前不会对U-Boot使用的内存地址进行任何破坏。

修网(AXI Ethernet)

故障现象 今日发现我之前搭建的基于Rocket Chip的SoC,在U-Boot中网卡工作,但Linux中网卡一直无法工作。并发现经常在Linux中使用ip link set eth0 up在看到dmesg输出3行网卡开启信息后系统就卡死,并在reset核心后U-boot(XIP)载入到开始访问DRAM的位置就停下。看起来像是AXI总线上(因为我没有进行Reset)有请求在我reset期间没有完成,这大概可以说明AXI总线上发了一些核的Slave无法处理的请求。 起初我怀疑问题有一部分和中断有关,因为U-Boot没有使用中断,但通过检查/proc/interrupts发现连接在PLIC上两个网卡的中断号都能在set eth0 up后出现多次中断。然后看了下Linux的Documentation中的设备树相关部分,发现我的网卡中断和DMA中断设置不对(要求把DMA中断也放在网卡中断中,但实测是等价的),修改后问题依旧,按照一个别人能工作的设备树写法修改后问题依旧。 而继续搜索相关资料发现,别人遇到的问题多数都是PHY相关。然而我使用的是SFP接口的1000BaseX,AXI Ethernet会自己实例化一个PHY,并不是外置的。 解决方法 后来我对比了我的SoC和别人的SoC,发现我拖出来的AXI DMA IP核的Memory Map Data…

用Linux resctrl玩x86 CPU上的L3 CAT

最近基于Verilator框架写了一个SoC仿真器,用C++实现了AXI接口以便软件定义MMIO。然而写完后运行发现,它的速度确实比FPGA要慢上非常多,FPGA上几秒钟完成的事情用Verilator仿真可能要跑几分钟才能跑出来。而RTL仿真是对于CPU的Cache压力很大的应用场景,因此就玩了下Linux的resctrl进行测试。方便后续选购CPU。 Linux resctrl已经支持Intel和AMD处理器中的许多技术。包括常见到的用来共享隔离Cache缓解侧信道的Intel CAT技术。然而我手里的Intel 12900K通过查看/proc/cpuinfo发现它只支持L2 CAT。而自己的AMD 5800X却可以支持L3 CAT,因此就用它进行了测试。而resctrl的配置主要参考了User Interface for Resource Control feature。 首先,对于Kernel v5.0以上,需要在config中打开CONFIG_X86_CPU_RESCTRL。Debian已经默认打开。 然后,挂载resctrl文件系统: sudo mount…

Xilinx Block Memory Generator踩坑小记

最近在用Verilator自研软件定义AXI Slave来实现SoC上设备的模拟,于是把Xilinx的Block Memory Generator当做了一个ground truth进行研究,于是就发现了一个会导致aw/w通道死锁的小坑。 复位后Master直接拉高awvalid和wvalid,则Slave不会拉高awready。但实际上Slave已经开始接收数据。 同时由于Block Memory Generator的AXI接口没有判断wlast是否符合要求,而Master一直到传输结束都不知道Slave已经接受了数据,导致一直没有拉高bready,就会导致aw/w通道死锁。 解决方法:Master在复位后的下个周期再进行操作。且AXI的Spec也要求Master在复位时应拉低ARVALID, AWVALID, WVALID。

Xilinx MIG的ECC内存踩坑小记

最近在某灵车7K325T FPGA上搭SoC,由于该灵车开发板有9个8bit DDR3组成72bit,因此就打算尝试一下ECC内存。 调试过程中遇到以下问题: 1. 开启ECC后init_calib_complete不拉高 init_calib_complete不拉高意味着内存train失败。最后发现是ddr3的dm信号在ECC开启时默认是关闭的,而我们需要将对应引脚手动拉低为0。修改后恢复。 2. AXI接口上的RRESP出现2'b10,即SLAVE ERROR。 在开启ECC后如果读取未曾写入的内存地址,会由于ECC bit没有更新导致出现ECC校验失败。在使用过程中确保该地址写入过即可。 神奇的是,我用Chipyard生成的BOOM核接到开启ECC的MIG上,如果跳转到一个没有写指令的地址时,Exception Code为2,即Illegal instruction,并非Instruction access fault。

新手的Vivado Block Design踩坑小记

最近在使用Vivado的Block Design搭建SoC,由于许多东西的User Guide不知道去哪找,因此在这里整理了一下自己作为新手使用Block Design踩过的坑。 1. 需要Create HDL Wrapper 在BD搭建完成后,点击右键选Create HDL Wrapper,然后就可以作为Top或是在别的模块中例化了。 2. 无法将System Verilog作为模块 遇到一个大问题就是自己写的System Verilog模块怎么都无法加入。后来查阅UG994发现直到Vivado 2021.2依然不支持将System Verilog作为Block…

使用nandsim模拟超过64G的大容量MTD设备

最近做毕设项目需要模拟mtd设备,并对yaffs进行相关测试。而由于要求模拟1TB容量的mtd设备,而若使用block2mtd,由于它的page size为1B大小,无法进行yaffs的挂载。 后来同学发现了Linux Kernel自带了nandsim模块,我们可以模拟一个块设备。且这个模块启动的时候可以通过overridesize参数设置整个mtd的大小为所选模拟设备的erase_size为2的整数幂。 但我们实测发现,如果overridesize设置过大,会报出以下错误: ➜ sudo modprobe nandsim first_id_byte=0x98 second_id_byte=0xd7 third_id_byte=0x94 fourth_id_byte=0x32 overridesize=20 insmod: ERROR: could not…

修好了D1板板使用Clang编译内核的问题,错误的Variables in Specified Registers用法

最近在修D1板板的驱动。遇到一些很迷惑的问题。 GCC编译的D1内核是好的,Clang不开LTO的内核是坏的,Clang编译的LTO THIN的内核是坏的,Clang编译的LTO Full内核勉强能用,Clang编译的LTO Full+CFI的内核是坏的。 但由于我们科研需要必须要使用Clang LTO+CFI,因此必须要保证能跑通开启了LTO和CFI的Kernel。 上述勉强能用的内核网卡还出现了异常的延迟、丢包、DUP。且从板子上ping外部延迟恒定为1s,而从外部ping板子延迟恒定为2s。而IPv6甚至完全不可用。 而勉强能用的内核上的SD卡,挂载上去写完文件再卸载后,接到别的电脑上挂载,却出现了文件系统损坏的情况。 而后来,经过2老师测试勉强能用的内核上的网卡驱动,发现以下问题: 经研究,clang编译的d1 linux,发包时,如果同时收到了包(比如别人发的广播包),那么发出去的包部分字节会被覆盖为收到的包 因此,我开始怀疑该问题是访问IO时Cache一致性出了问题,我就把目光从驱动本身转向了内核里维护Cache一致性的相关代码。 后来,我发现了一个这样的函数: void sbi_dma_sync(unsigned long start,…

AMD Zen 2/3处理器上的迷惑现象

今天在实验室装了一台AMD Ryzen 5700G的机器,想看看和自己寝室里放的AMD Ryzen 5800X性能差距多少,考虑到架构相同仅L3 Cache大小不同,因此就进行了一个简单的循环测试来看看单核Turbo Boost性能差距有多大。 实验室的5700G机器上安装了Ubuntu 21.04(考虑到20.04目前内核版本为5.4,无法支持Zen 3的一些电源管理特性,而实验室同学喜欢用Ubuntu),而我自己台式机则是滚的Debian sid。 两台机器自带的编译器如下(后续已经发现只与编译器有关): 实验室的5700G:gcc version 10.3.0 (Ubuntu 10.3.0-1ubuntu1) 寝室的5800X:gcc…

解决Clang+LLVM编译的Kernel多余.LBB符号导致Call Trace不方便查阅的问题

最近因为科研需求需要在全志D1开发板做性能的Evaluation,但是这个开发板的驱动用GCC编译是正常,而使用Clang+LLVM编译时存在许多问题,SD卡、网卡、USB全都有问题,因此考虑自己做一些修复。 但是由于硬件不方便在QEMU模拟,开发板的调试全靠串口输出,因此比较困难,但是一个大问题是LLVM编译的内核多了许多.LBB符号,导致Call Trace大概会长这样: [ 2.666348] [<ffffffff80004ecc>] .LBB2_1+0x20/0x2c [ 2.671152] [<ffffffff808f2c64>] dump_stack_lvl+0x4a/0x66 [ 2.676562] [<ffffffff808f2c98>] .LBB4_1+0x10/0x18 [ 2.681360] [<ffffffff808f27ce>]…

大学前三年的流水账

首先在开头提醒未来保研的学弟学妹,一定要通过提前联系一些学校的老师给自己有个定位,特别是在大一的时候因为竞赛或者种种原因没有取得高绩点但是专业能力较强而在Rank上无法体现的同学。而保研签卖身契如果自己不打算鸽一定要非常非常慎重。 自己的经历从大一说起。 大一 大一的时候对计算机领域研究了解太少了,看大家都在卷AI以为科研就只有AI相关,但自己又特别不喜欢这个方向,于是当时对保研的想法就是能保就读个划水专硕混学历,若不能保就直接去大厂。然后大一上进来期中考试高数还考了班上120多人内的第3名,就觉得自己没必要把绩点卷成这样,当时恰好自己对高中的OI生涯结果不满意(NOIP省一),于是大学便想继续在ICPC/CCPC(以前称为ACM竞赛)完成自己的遗愿,随后就把重心放在了这些比赛上。 然后很快,大一后半学期在学业上开始摸鱼,竞赛训练倒是更加频繁了,期末考也远没有期中考那么好了,特别是历史课和英语课因为没重视加上自己本来不擅长拖了很大的后腿,最后那个学期大概排名刚好20%。 然后到了大一下,又开始揽了更多的比赛并在自己加入的组织承担了更多的工作。后来有一件事情彻底改变了学习的状态。当时给那届CQUPC(重庆大学程序设计大赛)编写了Web报名系统以及负责了群发短信通知的工作。结果当时需要群发短信通知的日子刚好是比赛前一天晚上,而当时恰好高数老师需要补进度连补了四节课,而我当时给那个比赛编写的群发短信脚本又出了问题,在上课时间一直在折腾这事情,但毕竟当时就得通知到,无论如何都得发出去,最后原因在于被运营商限制了,找了客服解决,但后果是我落下了一晚上的高数课。 至此以后,我高数课就再也听不懂了,而当时各种比赛的压力也日益繁重,当时除了*CPC的日常训练外还报名参加了一个微信小程序的比赛,导致各种压力在一起一直没有挤出时间补上那一晚上落下的高数课,于是过上了抄作业的生活。结果在期末考前三周,连续参加了CTF校赛、ICPC南昌邀请赛、四川省大学生程序设计竞赛,还在那个时间赶工交了微信小程序作品,结果期末复习也真的来不及了,最后那个学期绩点非常惨,四分制GPA直接掉到2.8,感觉自己已经保研无望了。而现在回头来看,当时取得的竞赛成绩在后来都有更好的替代了。 期末结束,开始了计算机类专业分流,我们这一届也是第一届专业分流。当时教务老师明说了我们这届开始保研的时候按照全学院拉通排名,不分专业,因此大家选择专业的时候也主要跟随自己兴趣为主,但大多数人还是选择了计算机科学与技术。然后我当时报名了计科卓越班的选拔,虽然我当时绩点不高但是大一上成绩其实还行,且靠着比赛经历的加成(感觉主要是省程序设计大赛的金牌),还是通过了卓越班的选拔面试,进入了计科卓越工程师班。不过这一选择也成为了我在大三时破防的一个点,若当时没有通过,我可能选择的是信息安全。 大二 经过了绩点倒闭的大一下学期,大二就彻底对GPA躺平了,把心思全部放在算法竞赛上。当时基本每周和队友开1-2场5小时的模拟训练赛外加自己训练以及补题。最后结果还是不错的,在当年的EC-Final上拿了银牌,并且最后最难的那题三个人都有各自的贡献,也在最后10分钟评测机不堪重负等不来结果的时候我们把可能错的位置全部都改一遍,最后终榜出来发现那题过了,尽管那题不过也是银牌,但是总算是对这场比赛没有任何遗憾了。 然后大二下因为疫情在家生活节奏不太适应,又每天晚上被父母拉着出去锻炼身体占用了许多时间,所以一事无成,这个学期就到此为止吧。 唯一需要铺垫的事情是大二下的时候第一次参加了CET-6考试,因为大二上ICPC Asia EC-Final时间与CET-6冲突了,然后第一次参加也没重视就想看看当前水平,就裸考了,最后成绩是350多(具体多少忘了),总之是非常倒闭。因此就打算大三竞赛打完好好补一下英语的短板了。 大三上,突然可以单列保研 到了大三,开学的时候和室友组队参加了数学建模竞赛,结果恰好遇到了一个我非常擅长的问题,是一个图论题,然后我就拿着之前参加算法竞赛攒下的DP+网络流知识搞出了一个非常好的结果,队友也拿强化学习做了一部分,且这些算法结果好又可以把算法写的非常详细,最后我们获得了全国一等奖。按照当时已经符合学校的单列保研标准了。当时也非常高兴自己可以去混个学历了。 大三上,突然有志于系统结构方向科研 但也很快,就在这个学期,我们当时有一位助教在做操作系统的教改,把清华的uCore操作系统实验引入了我们学校,然后我当时看了指导书后对OS非常着迷。特别是把那些实验自己读代码读文档后补全代码做完以后发现自己对计算机系统的认识发生了本质性的变化,特别是搞清楚了内存管理后,开始理解了为什么像Java这样需要GC的语言在某些场景具有优势,觉得一下子思维都开阔了。于是发现自己找到了自己真正喜欢的东西,计算机底层的相关研究,或者说体系结构。于是开始有了好好做研究的想法,从曾经只想读个水专硕变成了想直博认真做研究。…

Back to Top