Sunday, June 28, 2015

GSoC: Some notes of hacking on drm drivers

In the very first, I converted the DRM_BOCHS within just one patch, it's doing too many things, makes me lost my way in kernel land. Daniel suggusted me to split up the patch into smaller steps, this really helps a lot.

Then when test each small step, I find I got stuck in the function register_framebuffer(), locked up while holding console_lock. So Daniel explained a bit the background:

For all kernel log output to the console there is one big lock to protect it all, that's the console_lock. We also need this lock to register a new console and register a legacy fbdev, we have that in drm to be able to use the fb console.

Problem is now that the first thing fbcon does is setup a mode while we still hold console_lock, which means it's going to call all the bochs modeset functions, if it crash in there or anything else happens, not a single line will go to dmesg since console_lock is locked.

The messages that the between the console_lock() and console_unlock() will not display to the console imediatelly, but shows after the lock was released.

At the end of register_framebuffer the console_lock get released, and everything that was logged with DRM_DEBUG or printk appears in one go in the logs, which means if now bug is there it looks like the printing works. But if it crash nothing past the console_lock() call will ever show up anywhere.

Solution:
We need to get rid of fbcon for debugging.
This means the screen will be dark until X comes up, and there won't be a kernel console any more.

So needs prep:
1. make sure X comes up automatically
2. make sure we can log into the vm using ssh (since no other console will work)
3. change the kernel config and set FRMEBUFFER_CONSOLE=n (make munuconfig)

There is even easier way to do this:
Turn off fbdev support in bochs, set bochs.enable_fbdev = false will work.

I tested it with a working distro kernel, set enable_fbdev = false will not print drm log messages like before, and X can finally start up.

Now, as we are clear of the background and solution, we should be able to log into the machine with ssh and look at dmesg to figure out what's wrong.

The native linux and the qemu VM are not in the same Network segment, it's ok to ssh from vm to native linux, but not work the other way around, so I have to configure the qemu network.

Qemu networking:
There are two parts to networking within QEMU:

  • the virtual network device that is provided to the guest(e.g. a PCI network card).
  • the network backend that interacts with the emulated NIC (e.g. puts packets onto the host's network).
There are a range of options for each part. By default QEMU will create a SLiRP user network backend and an appropriate virtual network device for the guest (eg an E1000 PCI card for most x86 PC guests).

Note: if you are using the (default) SLiRP user networking, the ping(ICMP) will not work, though TCP and UDP will.

In most cases, if you don't have any specific networking requirements other than be able to access to a web page from your guest, user networking(slirp) is a good choice. However, if you are looking to run any kind of network service or have your guest participate in a network in any meaningful way, tap is usually the best choice.

Tap
The tap networking backend makes use of a tap networking device in the host. It offers very good performance and can be configured to create virtually any type of network topology. Unfortunately, it requires configuraion of that network topology in the host which tends to be different depending on the operating system you are using. Generally speaking, it also requres that you have root privileges.
  -netdev tap, id=mynet0

Below is what I did configuring the network.

We need two tools to configure the network.
  1. #apt-get install bridge-utils
  2. #apt-get install uml-utilities
Then configure the bridge:
  1. #ifconfig eth0 down
  2. #brctl addbr br0
  3. #brctl addif br0 eth0
  4. #brctl stp br0 off
  5. #brctl setfd br0 1
  6. #brctl sethello br0 1
  7. #ifconfig br0 0.0.0.0 promisc up
  8. #ifconfig eth0 0.0.0.0 promisc up
  9. #dhclient br0
Then configure TAP device:
  1. #tunctl -t tap0 -u root
  2. #brctl addif br0 tap0
  3. #ifconfig tap0 0.0.0.0 promisc up
Now add some option when I start the qemu:
qemu-system-x86_64 -m 1024 -smp 2 -hda ./linux-bochs.img -no-acpi -vga std -k en -us -serial stdio -net nic -net tap,ifname=tap0,script=no,downscript=no

It works, now I can use ping and ssh to comunicate from host to guest.

Note:
Must make sure that eth0 has the IP of 0.0.0.0, if the ip of eth0 is same as br0, it will not work.

modetest, a basic kms test program
  ./modetest -h
  ./modetest -M bochs-drm
  ./modetest -p
  ./modetest -s 21@19:1024x768


Wednesday, June 10, 2015

GSoc: Configure a serial console for the Qemu Virtual Machine

As I am stuck in the dark when I boot up, so I asked for help on the mailing list. And got some help from Gerd Hoffmann, here is what he said:
With fbdev enabled a lot initialization happens with some important console lock taken, which has the effect that you don't see any kernel messages until it succeeded. 
He suggested me to configure a serial console for the virtual machine.

Following is what I did configuring the serial console:

  1. In the virtual machine, add a parament to the grub menuentry something like "console=ttyS0,9600n8"
  2. Add a parameter when start the qemu virtual machine, the command now looks like:
    • qemu-system-x86_64 -m 1024 -smp 2 -hda ./linux-bochs.img -no-acpi -vga std -k en-us -serial pty
    • and get the redirected device: "char device redirected to /dev/pts/2"
  3. Now I can see the kernel messages from the the virtual machine using the following command:
    • cat /dev/pts/2

This is trivial, post it here if anyone came across the same problem.

2015/06/11
After email with Gred, here is what he suggested:

  • use 115200 as line speed to speedup the console a bit
  • -serial stdio might be more convenient, so that we don't need the "cat /dev/pts/2" step, the messages from the virtual machine serial console will display to the qemu terminal of the host machine.
  • on modern linux distros (anything systemd-based) you should automatically get a login prompt on the serial line in case it is configured as console. Try adding "ignore_loglevel" and "drm.debug=0x07" to the kernel command line.
  • we can blacklist the module in modprobe.conf (or /etc/modprobe.d) to prevent it from autoloading.

Wednesday, June 3, 2015

GSoC: Update kernel on qemu virtual machine with bochs and Set up the Github repo

1.Update kernel on qemu virtual machine with bochs

The origin kernel version is 3.2.0, and I am working on airlied's repo:
  git://anongit.freedesktop.org/drm-intel

I don't change kernel very often, usually when a new Linux distribution(e.g. Ubuntu 15.04) is out, I will download that and set up a new Virtual Machine, not smart and nothing to do with kernel update. After days of google and trying, finally I set up the new kernel, which is 4.0.0-rc4+.

Following is what I do setting up the new kernel:
  I compile the linux source code on the host machine(even though it is a VMware VM, compile on it is far more quicker than compile on the qemu VM, which is running on the host VMware VM).
  Working dir is ~/work
  • use the kernel config of host VM(same as the qemu VM)
   #cp /boot/config-3.2.0-4-amd64 ~/work/linux/.config
  • select 'M' for Bochs and Cirrus driver
   #make menuconfig
  • compile and install (This takes the longest time)
   #make bzImage
   #make modules
   #make modules_install
   #make install

  After these operations, we got the following files(or directory) install in the host VM:
   /lib/modules/4.0.0-rc4+/
   /boot/initrd.img-4.0.0-rc4+
   /boot/System.map-4.0.0-rc4+
   /boot/vmlinuz-4.0.0-rc4+
  These are what we need to set up the new kernel for the qemu VM, we compress them in a single file and scp it from the host to qemu VM, decompress it and put them in the right places(same as the host).
  We still need some other operations:
   #cd /lib/modules/4.0.0-rc4+/
   #depmod -a -v 4.0.0-rc4+
  and update the grup menuentry:
   #update-grub 

Ok, now reboot, choose the newly installed kernel entry, it works! 

And check the kernel version:
   #uname -r
  I got 4.0.0-rc4+
check the modules running on the qemu virtual machine:
   #lsmod
  got the following modules related to bochs:
   bochs_drm
   ttm
   drm_kms_helper
   drm
   i2c_core
   syscopyarea
   sysfillrect
   sysimgblt
   
And then I checked if there was any error in dmesg, got the following warning:

[  302.072360] ------------[ cut here ]------------
[  302.076145] WARNING: CPU: 0 PID: 2907 at drivers/gpu/drm/ttm/ttm_bo_vm.c:265 ttm_bo_vm_open+0x34/0x3b [ttm]()
[  302.076465] Modules linked in: rfcomm bnep bluetooth rfkill uinput nfsd auth_rpcgss oid_registry nfs_acl nfs lockd grace fscache sunrpc loop bochs_drm ttm drm_kms_helper drm kvm_amd kvm psmouse i2c_core evdev syscopyarea sysfillrect pcspkr serio_raw sysimgblt ext4 crc16 jbd2 mbcache sg sr_mod cdrom sd_mod ata_generic ata_piix e1000 libata scsi_mod
[  302.077427] CPU: 0 PID: 2907 Comm: Xorg Not tainted 4.0.0-rc4+ #1
[  302.077458] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2007
[  302.077647]  0000000000000000 0000000000000009 ffffffff813b526d 0000000000000000
[  302.077698]  ffffffff8103e8c3 00000000810f6832 ffffffffa021df5a ffff880027100400
[  302.077724]  ffff88001ae5c800 ffff880027100400 ffff88002f87c3b0 ffff88002f8b50c0
[  302.077778] Call Trace:
[  302.078839]  [<ffffffff813b526d>] ? dump_stack+0x40/0x50
[  302.078946]  [<ffffffff8103e8c3>] ? warn_slowpath_common+0x98/0xb0
[  302.079076]  [<ffffffffa021df5a>] ? ttm_bo_vm_open+0x34/0x3b [ttm]
[  302.079117]  [<ffffffffa021df5a>] ? ttm_bo_vm_open+0x34/0x3b [ttm]
[  302.079146]  [<ffffffff8103d242>] ? copy_process.part.32+0xbe0/0x1689
[  302.079175]  [<ffffffff8111caae>] ? get_empty_filp+0xef/0x174
[  302.079201]  [<ffffffff8103de35>] ? do_fork+0xb4/0x25e
[  302.079230]  [<ffffffff813b960d>] ? stub_clone+0x6d/0x90
[  302.079255]  [<ffffffff813b9332>] ? system_call_fastpath+0x12/0x17
[  302.079435] ---[ end trace d4b7cc30b85ed796 ]---

I am not sure if this warining is fatal, post it here just for later compare with the bochs driver after converting to atomic mode-setting.

2.Set up the Github repo

Firstly create a new empty repository on github, then you got the repo's url:
  https://github.com/zhjwpku/gsoc.git

Since currently my origin is airlied's, I changed it by:
  #git remote rename origin airlied
Then I add some remotes:
  #git remote add origin https://github.com/zhjwpku/gsoc.git
  #git push
  #git remote add drm-intel git://anongit.freedesktop.org/drm-intel

Finish setting up the github repo.