Jordan Savant # Software Engineer

Kernel Dev Blog 2 -- In Code

4/5/2020

I was able to get the Kernel compiled and loaded yesterday following the guide with relatively no problems. I had no idea that you could change your installed Kernely version at boot time after it is comiled and then make module_install install

The first chapter in the Linux Device Drivers book was also great, even from a development philosphy standpoint of "mechanism" vs "policy". I have not seen that dilineation before and I believe that principle could apply to a lot of things in general software engineering.

For example the separation of concerns across layers in an MVC web architecture, where mechanism of models or services should not be concerned with a higher level layers policy around user authorization).

Before moving into the rest of the guide for coding I took a look through the Kernel to spelunk for various things, which landed me in the Documentation/process/ folder where I have been reading a lot.


/Documentation/process/1.Intro.rst

Linux is over 8 million lines of code and over 1000 contributors to each release

Getting code into mainline is important for more long term reasons that short:

  • Available to be improved by others
  • Peer review from others breeds success (isolationism is weakness)
  • Available on all Linux platforms
  • If other developers make breaking changes, they must fix them
  • Influence over direction of Linux
  • Other third-party may take your spot

GPL 2 License -- I am not a lawyer but I need to understand this

/Documentation/process/2.Process.rst

Rough Release Cycle

  • New releases occur every 2-3 months
  • Linus opens a 2 week period for maintainers to submit patches
  • He approves them into the mainline and after 2 weeks forms a "version-rc" kernely (5.6-rc1)
  • Only patches come in to stabilize release candidate at this time for 6 to 9 weeks
  • After iterations of stability the version is released as "version" stable release (5.6 stable release)
  • From there it goes to the "stable team" to put in more stability patches into an "update release" (5.6.1) etc

Patch Lifecycle

  • Design - requirements laid out
  • Early Review - mailing list reviews
  • Wider Review - accepted by subsystem maintainer into subsystem tree and '-next' tree
  • Merging into Mainline - linus does this during merge window
  • Stable release - resolving issues when exposed to more users
  • Long Term maintenance - be responsible and available to support it

Subsystem Trees and Trust

Linus merges all main patches into core, but he has a lieutenant system to make it sane

Kernel is logically broken into: networking, specific architector support, memory management, video devices etc

Subsystem maintainers are gatekeepers to code and they merge in patches into a large patch

Next Trees

Patches are also merged into the "-next" tree so you can use this to see if your code may conflicts with other unmerged patches

http://www.kernel.org/pub/linux/kernel/next/

Staging Trees

I enjoyed looking through drivers/staging/ where drivers that are being worked on for upcoming hardware have been merged and do compile but are not in the core yet. They are required to have a "TODO" file in them with things they need to change.

Greg Kroah-Hartman currently maintains the staging tree. I cloned from his repo.

Tools

GIT, Mercerial, Quilt

Quilt is a patch management system (not source code management system). It does not track history but tracks a set of changes against evolving codebase

Mailing Lists

http://vger.kernel.org/vger-lists.html

Beware of overwhelming email

linux-kernel is the core list and to survive:

  • send list to separate folder
  • dont try and follow all conversations, filter on topics of interest
  • dont feed the trolls
  • respond preserving Cc: header for all involved
  • search the list archives (and internet) before asking questions
  • do not "top-post" (putting answer above quoted text)
  • ask on the correct mailing list

Best place to look for lists are the MAINTAINERS file packaged in the kernel source code

Ones of interest to me could be:

  • linux-kernel
  • linux-newbie
  • kernel-janitors

Getting Started

Beginning with a large project can be intimidating; one often wants to test the waters with something smaller first some developers jump into the creation of patches fixing spelling errors or minor coding style issues Unfortunately, such patches create a level of noise which is distracting for the development community as a whole increasingly, they are looked down upon and will not get the sort of reception they wish for

Andrew Morton gives this advice for aspiring kernel developers

The #1 project for all kernel beginners should surely be "make sure that the kernel runs perfectly at all times on all machines which you can lay your hands on". Usually the way to do this is to work with others on getting things fixed up (this can require persistence!) but that's fine - it's a part of kernel development.

Look at current list of regressions and open bugs to resolve

pausing here to do some coding practice Next is /Documentation/process/3.Early-stage.rst


Adding some Code

In drivers/net/ethernet/intel/e1000/e1000_main.c I placed a printk as the guide stated in the e1000_probe function that is called with the device is initalized

This driver is used on the VM version

static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
        struct net_device *netdev;
        struct e1000_adapter *adapter = NULL;
        struct e1000_hw *hw;

        printk(KERN_DEBUG "I AM INVINCIBLE!!!\n");

        static int cards_found;
        static int global_quad_port_a; /* global ksp3 port a indication */

When compiling I received the following warning:

drivers/net/ethernet/intel/e1000/e1000_main.c:928:2: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
  static int cards_found;
  ^~~~~~

I learned that a coding ISO C90 forbids mixed declarations and code that there is C Standard that is enforced at the compiler level \ ? /

so I switched it around to

static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
        struct net_device *netdev;
        struct e1000_adapter *adapter = NULL;
        struct e1000_hw *hw;

        static int cards_found;
        static int global_quad_port_a; /* global ksp3 port a indication */
        int i, err, pci_using_dac;
        u16 eeprom_data = 0;
        u16 tmp = 0;
        u16 eeprom_apme_mask = E1000_EEPROM_APME;
        int bars, need_ioport;
        bool disable_dev = false;

        printk(KERN_DEBUG "I AM INVINCIBLE!!!\n");

        /* do not allocate ioport bars when not needed */
        need_ioport = e1000_is_need_ioport(pdev);
        if (need_ioport) {

And it compiled.

I rebooted and searched and found the printed line

$ dmesg | grep -C5 INVINCIBLE
[    7.218840] ahci 0000:00:0d.0: SSS flag set, parallel bus scan disabled
[    7.219245] ahci 0000:00:0d.0: AHCI 0001.0100 32 slots 1 ports 3 Gbps 0x1 impl SATA mode
[    7.219655] ahci 0000:00:0d.0: flags: 64bit ncq stag only ccc
[    7.220873] e1000: Intel(R) PRO/1000 Network Driver - version 7.3.21-k8-NAPI
[    7.221182] e1000: Copyright (c) 1999-2006 Intel Corporation.
[    7.221454] I AM INVINCIBLE!!!
[    7.229828] scsi host2: ahci
[    7.230075] ata3: SATA max UDMA/133 abar m8192@0xf1806000 port 0xf1806100 irq 21
[    7.261574] usb 1-1: new full-speed USB device number 2 using ohci-pci
[    7.304187] cryptd: max_cpu_qlen set to 1000
[    7.316483] AVX2 version of gcm_enc/dec engaged.

And also in the kernel log

$ grep -C5 INVINCIBLE /var/log/kern.log
Apr  5 14:54:50 doomkern kernel: [    7.218840] ahci 0000:00:0d.0: SSS flag set, parallel bus scan disabled
Apr  5 14:54:50 doomkern kernel: [    7.219245] ahci 0000:00:0d.0: AHCI 0001.0100 32 slots 1 ports 3 Gbps 0x1 impl SATA mode
Apr  5 14:54:50 doomkern kernel: [    7.219655] ahci 0000:00:0d.0: flags: 64bit ncq stag only ccc
Apr  5 14:54:50 doomkern kernel: [    7.220873] e1000: Intel(R) PRO/1000 Network Driver - version 7.3.21-k8-NAPI
Apr  5 14:54:50 doomkern kernel: [    7.221182] e1000: Copyright (c) 1999-2006 Intel Corporation.
Apr  5 14:54:50 doomkern kernel: [    7.221454] I AM INVINCIBLE!!!
Apr  5 14:54:50 doomkern kernel: [    7.229828] scsi host2: ahci
Apr  5 14:54:50 doomkern kernel: [    7.230075] ata3: SATA max UDMA/133 abar m8192@0xf1806000 port 0xf1806100 irq 21
Apr  5 14:54:50 doomkern kernel: [    7.261574] usb 1-1: new full-speed USB device number 2 using ohci-pci
Apr  5 14:54:50 doomkern kernel: [    7.304187] cryptd: max_cpu_qlen set to 1000
Apr  5 14:54:50 doomkern kernel: [    7.316483] AVX2 version of gcm_enc/dec engaged.

printk is a Linux Kernel API function that lets us print to the kernel log. Apparently printf is not available in the Linux Kernel mode

dmesg is "dmesg - print or control the kernel ring buffer". What is the Kernel Ring Buffer?

The Kernel Ring Buffer

The syslog daemon is what writes to log files, but this daemon is not available the beginning boot of the kernel since it iself is booted from the kernel. As a result logs from printk are stored in a memory buffer and when the syslog daemon starts up it collects that buffer and writes it to a proper log file. dmesg I think is just reading and writing to this buffer.