用龙芯EJTAG硬件断点优化Linux ptrace watch性能

在MIPS标准的协处理器0(CP0)中定义一组硬件watchpoints接口,由于某些原因,龙芯3系列处理器并未实现,这就导致了在该架构Linux系统中用gdb watch只能使用软件断点,真心非常、非常慢。:(

好消息是龙芯3系列处理器是实现了MIPS EJTAG的,兼容2.61标准,那么能否利用MIPS EJTAG的硬件断点功能部件实现Linux ptrace的watchpoints功能呢?答案是肯定的。让我们一起看看具体的方法吧。

首先,我们需要更改BIOS中的异常处理函数,将EJTAG调试异常重新路由至Linux内核中处理,因为MIPS EJTAG异常处理程序的入口地址固定为0xbfc00480

         /* Debug exception */
         .align  7           /* bfc00480 */
         .set    push
         .set    noreorder
         .set    arch=mips64r2
         dmtc0   k0, CP0_DESAVE
         mfc0    k0, CP0_DEBUG
         andi    k0, 0x2
         beqz    k0, 1f
          mfc0   k0, CP0_STATUS
         andi    k0, 0x18
         bnez    k0, 2f
          nop
 1:
         mfc0    k0, CP0_EBASE
         ins     k0, zero, 0, 12
         addiu   k0, 0x480
         jr      k0
          dmfc0  k0, CP0_DESAVE
 2:
         la      k0, 0xdeadbeef
         dmtc0   k0, CP0_DEPC
         dmfc0   k0, CP0_DESAVE
         deret
         .set    pop

这段处理程序实现了两个功能:
1. 将来自用户态的sdbbp指令触发的异常路由至地址 0xdeadbeef。
2. 将来自内核态的sdbbp指令触发的异常或是任意态的非sdbbp触发的异常路由至 ebase+0x480。

接着,我们还需要修改内核,实现下列功能:
1. 实现 EJTAG watch 相关的 probe、install、read、clear 等操作,及合适的调试异常处理程序。
2. 实现 Linux ptrace watch 接口与 EJTAG watch 的对接。

See: https://github.com/heiher/linux-stable/commits/ejtag-watch-4.9

Over!

How to write SCGI applications in Python and JavaScript

Download & Install HevSCGIServerLibrary

git clone git://github.com/hev-scgi/hev-scgi-server-library
cd hev-scgi-server-library
make
 
sudo cp bin/libhev-scgi-server.so /usr/lib64/
sudo cp gir/HevSCGI-1.0.gir /usr/share/gir-1.0/
sudo cp gir/HevSCGI-1.0.typelib /usr/lib64/girepository-1.0/

Python Demo
https://github.com/hev-scgi/hev-scgi-server-python

git clone git://github.com/hev-scgi/hev-scgi-server-python
cd hev-scgi-server-python
 
python3 src/main.py

JavaScript Demo
https://github.com/hev-scgi/hev-scgi-server-gjs

git clone git://github.com/hev-scgi/hev-scgi-server-gjs
cd hev-scgi-server-gjs
 
gjs -I src src/main.js

Over!

优化 ibus-table 性能

ibus-table 是 Python 语言实现的 ibus 输入法框架的码表引擎,ibus 的绝大多数形码输入法使用该引擎,如郑码、五笔等等。

使用过该引擎的用户或多或少有这样的感觉,就是反应慢,尤其在低性能的计算机上感觉格外明显。无需复杂的性能分析工具,仅用 top 命令就不难发现,用一个约有20万条记录的郑码码表,在连续输入中文时,ibus-table 进程的CPU使用率几乎100%,这还是在一个 i3 2.5GHz 的 PC 平台上。那么在一个更低性能的平台上,输入体验可以想象。

再通过 pref 工具跟踪可以发现,在连续输入时,大部分CPU使用主要来自于 sqlite 数据库查询操作和候选词排序。在阅读引擎代码后,我做了一个实验,在 tabsqlitedb.py 的 select_words 中删除掉 sqlite 查询与排序,返回静态记录。结果CPU使用率降低到了只有5%左右。

因此,给 select_words 加个缓存应该是个不错的选择,就用 HashMap 来实现这个缓存,按键输入作为 key,排序后的结果作为 value。结果很明显,连接输入中文时的进程CPU使用率从几乎100%下降到了10%。

已经合并至 1.9.18: https://github.com/kaio/ibus-table/releases/tag/1.9.18

Over!

解决小米4电信4G版刷LineageOS信号问题

小米4电信4G版 LineageOS 官方版本存在两类网络信号相关的问题:
1. 电信 CDMA 卡无信号。
2. 电信 CDMA 4G卡只能使用 LTE 网络,无法接打电话、收发短信。

解决方法
刷入官方 ROM 后,在 recovery 中挂载 /system,然后编辑 /system/build.prop 文件:

# 文件中原有此行配置,将值修改为 22
ro.telephony.default_network=22
# 额外增加以下三行
ril.subscription.types=NV,RUIM
persist.radio.force_on_dc=true
persist.omh.enabled=true

Over!

RPi2 远程控制PC电源开关

远程连接物理机调试、测试固件、内核级补丁时,因补丁功能异常导致死机是经常发生的,如果你有一个 Rpi,那就可以派上用场了,本文记录了使用 Rpi2 的 GPIO 远程控制 PC 电源开关的方法。

物理连接
rpi2 有数量众多的 pinout,将 rpi2 的 pin37(gpio26) 与 pc front panel 的 pwr_sw_p 连接,再将 rpi2 的 pin39(gnd) 与 pc front panel 的 pwr_sw_n 连接。如图:
RP2_Pinout
panel(1)

软件控制

# 先将 gpio 26 export,这步不必每次都做,当 /sys/class/gpio/gpio26 目录不存在时执行。
echo 26 > /sys/class/gpio/export
cd /sys/class/gpio/gpio26
# 开机
echo out > direction; echo 0 > value; sleep 1; echo in > direction
# 关机
echo out > direction; echo 0 > value; sleep 5; echo in > direction

Over!

ArchLinux 部署 SSD 缓存

在 Linux 系统上使用带宽更高、延迟更小的 SSD 作为 HDD 的缓存来打造软件实现的“混合硬盘”是一种容量和性能折中的方案。在 Linux 系统中使用高速外存作低速外存的缓存有两个成熟的方案:1. lvmcache 2. bcache。本文记录的是基于 lvmcache 在 Arch Linux 系统上的部署方法。

硬件情况
1. 一块120GB容量的固态硬盘 (/dev/sda)。
2. 一块1TB容量的机械硬盘 (/dev/sdb)。

分区规划

/dev/sda1     20GB     lvm
/dev/sda2     100GB    lvm
/dev/sdb      1TB      lvm

LVM 规划

VG (system) -> { PV (/dev/sda1) }
VG (data) -> { PV (/dev/sdb), PV (/dev/sda2) }
 
LV (system/arch) 19.9GB
LV (data/home) 917GB
LV (data/home_cache) 91GB

操作系统完全安装在 SSD 中, home 存放于 HDD 中,但使用 SSD 的剩余空间作为 cache。为什么不把所有数据存放于 HDD 中,仅用 SSD 作为 cache 呢?测试结果是当 cache 加入后就影响了系统的启动,所有只能应用于数据区。

详细步骤
1. 使用 ArchLinux iso 启动盘启动系统。
2. fdisk /dev/sda 先创建一个类型为 lvm 容量为 20GB 的标准主分区,再创建一个类型为 lvm 容量为 100GB 的标准主分区。
3. pvcreate /dev/sda1
4. pvcreate /dev/sda2
5. pvcreate /dev/sdb
6. vgcreate system /dev/sda1
7. vgcreate data /dev/sdb
8. lvcreate -L 19.9G system -n arch
9. mkfs.ext4 -E discard /dev/mapper/system-arch
10. mount /dev/mapper/system-arch /mnt
11. pacstrap /mnt 按照需要安装系统
12. arch-chroot /mnt
13. lvcreate –type cache –cachemode wirteback -L 91G -n home_cache data/home /dev/sda2
14. 另开一个 tty, mount -o bind /run /mnt/run
15. 回到原 tty, vim /etc/mkinitcpio.conf,找到 HOOkS,在 block 和 filesystem 之间增加个 lvm2
16. mkinitcpio -p linux
17. vim /etc/default/grub,找到 GRUB_PRELOAD_MODULES,增加 lvm。
18. grub-mkconfig -o /boot/grub/grub.cfg
19. grub-install /dev/sda
20. 退出,重启。

查看 cache 状态

sudo lvs -o cache_read_hits,cache_read_misses,cache_write_hits,cache_write_misses data/home

Over!

MIPS J类指令目标范围

MIPS 跳转指令共分为三类:基于PC的相对跳转、基于PC区域的相对跳转、基于寄存器的绝对跳转。其中基于 PC 区域的相对跳转也就是我们要说的 J 类指令。

J类指令有长达26位的指令 index 编码域,因为指令都是4字节对齐的,所有表示的范围是 256M(28位)。那么J类跳转的目标地址是如何计算的呢?

目标PC = 延迟槽指令PC的28位以上的高位 || (J类指令26位的立即数 << 2)

是不是不易想像范围,看看图示吧:

j-class
 
|: 265M 边界
j: j 指令位置
t: 可行的跳转目标位置
 
----------------|--------------------------------|--------------------------------|----------------
---------------j|tttttttttttttttttttttttttttttttt|--------------------------------|----------------
----------------j-ttttttttttttttttttttttttttttttt|--------------------------------|----------------
----------------|j-tttttttttttttttttttttttttttttt|--------------------------------|----------------
----------------|tttttttttttttttj-ttttttttttttttt|--------------------------------|----------------
----------------|ttttttttttttttttttttttttttttttj-|--------------------------------|----------------
----------------|-------------------------------j|tttttttttttttttttttttttttttttttt|----------------
----------------|--------------------------------j-ttttttttttttttttttttttttttttttt|----------------

Over!