{"id":51573101,"url":"https://github.com/czhao-dev/linux-device-drivers","last_synced_at":"2026-07-10T21:30:34.743Z","repository":{"id":366519729,"uuid":"1267842432","full_name":"czhao-dev/linux-device-drivers","owner":"czhao-dev","description":"Four Linux kernel modules — character device, block device (blk-mq), network device (NAPI), and PCIe (MMIO/MSI/DMA) drivers — built and tested end-to-end in Docker + QEMU.","archived":false,"fork":false,"pushed_at":"2026-07-08T12:50:37.000Z","size":136,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-08T14:20:18.645Z","etag":null,"topics":["block-driver","c","character-driver","concurrency","device-driver","dma","docker","embedded-linux","ioctl","kernel-module","kernel-programming","linux-kernel","mmio","napi","net-device","network-driver","pcie","qemu","synchronization","systems-programming"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/czhao-dev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-12T22:58:37.000Z","updated_at":"2026-07-08T12:50:44.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/czhao-dev/linux-device-drivers","commit_stats":null,"previous_names":["czhao-dev/linux-kernel-drivers","czhao-dev/linux-device-drivers"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/czhao-dev/linux-device-drivers","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czhao-dev%2Flinux-device-drivers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czhao-dev%2Flinux-device-drivers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czhao-dev%2Flinux-device-drivers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czhao-dev%2Flinux-device-drivers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/czhao-dev","download_url":"https://codeload.github.com/czhao-dev/linux-device-drivers/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/czhao-dev%2Flinux-device-drivers/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35344523,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-10T02:00:06.465Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["block-driver","c","character-driver","concurrency","device-driver","dma","docker","embedded-linux","ioctl","kernel-module","kernel-programming","linux-kernel","mmio","napi","net-device","network-driver","pcie","qemu","synchronization","systems-programming"],"created_at":"2026-07-10T21:30:31.642Z","updated_at":"2026-07-10T21:30:34.731Z","avatar_url":"https://github.com/czhao-dev.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Linux Device Drivers\n\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n[![Language: C](https://img.shields.io/badge/language-C-00599C.svg?logo=c\u0026logoColor=white)](.)\n[![Platform: Linux Kernel Module](https://img.shields.io/badge/platform-Linux%20Kernel%20Module-FCC624.svg?logo=linux\u0026logoColor=black)](.)\n[![Dev env: Docker](https://img.shields.io/badge/dev%20env-Docker-2496ED.svg?logo=docker\u0026logoColor=white)](.)\n[![Tested under: QEMU](https://img.shields.io/badge/tested%20under-QEMU-FF6600.svg?logo=qemu\u0026logoColor=white)](.)\n\nFour Linux kernel modules, each targeting a different driver subsystem and the\ncontract it imposes between kernel and user space, hardware, or the networking\nstack. None require physical hardware: every driver builds and runs end-to-end\nin Docker + QEMU against a real kernel, on Linux, macOS, or Windows.\n\n| Driver | Subsystem | Core mechanisms |\n|---|---|---|\n| [`linux-character-device-driver`](linux-character-device-driver/) | Character device | `file_operations`, mutex, wait queues, blocking I/O, `ioctl` |\n| [`linux-block-device-driver`](linux-block-device-driver/) | Block I/O (`gendisk`/blk-mq) | `bio`/`request` segment iteration, spinlock-protected memcpy, page cache vs. `O_DIRECT` |\n| [`linux-network-device-driver`](linux-network-device-driver/) | Networking (`net_device`) | `sk_buff`, descriptor rings, NAPI, TX queue backpressure |\n| [`linux-pcie-device-driver`](linux-pcie-device-driver/) | PCI / PCIe | BAR-mapped MMIO, MSI interrupts, DMA buffer management |\n\n---\n\n## Overview\n\nEach project targets a different kernel subsystem on purpose, so that together\nthey cover most of the contracts a driver author has to get right.\n\n### [`circbuf`](linux-character-device-driver/) — Virtual Character Device\n\nA kernel module that registers `/dev/circbuf` as a bounded circular-buffer\ndevice. Writers produce bytes into a fixed-size buffer; readers consume them in\nFIFO order. When the buffer is full, writers block; when it is empty, readers\nblock. Multiple processes can open the device concurrently and are safely\narbitrated through kernel synchronization primitives.\n\n**What it covers:** `file_operations` vtable (C-level polymorphism between VFS\nand the driver); `copy_to_user`/`copy_from_user` for crossing the kernel/user\nboundary safely; `mutex` for sleeping critical sections vs. `spinlock` for\natomic ones; `wait_queue_head_t` for blocking I/O; and `ioctl` design for\nout-of-band device control. Because there is no hardware dependency, the focus\nstays entirely on getting these contracts right.\n\n**Key object:** `struct file_operations` — a vtable of function pointers the\nkernel calls when user space invokes `open`, `read`, `write`, `ioctl`, or\n`release` on the device file.\n\n---\n\n### [`vblk`](linux-block-device-driver/) — Virtual RAM-backed Block Device\n\nA kernel module that registers `/dev/vblk0` backed by a `vmalloc`'d region\nof kernel memory. It behaves like a real disk: `dd`, `mkfs`, `mount`, and\narbitrary `pread`/`pwrite` all work against it because it implements the same\n`gendisk` / `block_device_operations` / `blk_mq_ops` contract every real block\ndriver implements. Only the \"hardware\" — a contiguous kernel buffer instead of\na physical device — differs.\n\n**What it covers:** `gendisk` + blk-mq registration (`blk_mq_alloc_disk`,\n`add_disk`); `bio`/`request` segment iteration inside `queue_rq`; why a\n`spinlock` is the right primitive once `copy_to/from_user` is off the table;\nand the page-cache vs. `O_DIRECT` distinction that governs whether I/O ever\nreaches the driver at all. The test suite validates all three paths: buffered\nI/O through the page cache, `O_DIRECT` bypassing it, and a full\n`mke2fs` + `mount` + file I/O + `umount` round trip through ext2.\n\n**Key object:** `struct gendisk` paired with a `struct blk_mq_tag_set` — the\nblock-layer analogue of `file_operations`.\n\n---\n\n### [`netdrv`](linux-network-device-driver/) — Virtual Ethernet Driver Pair with NAPI\n\nA kernel module that creates a software point-to-point Ethernet pair (`vnet0`\n↔ `vnet1`) built around the same structures a real NIC driver uses: TX/RX\ndescriptor rings, NAPI interrupt-mitigated packet reception, and\n`netif_stop_queue`/`netif_wake_queue` TX backpressure. A packet transmitted\non one interface appears as received on the other; the \"wire\" is software,\nbut the driver-side mechanics follow the real networking stack contracts.\n\n**What it covers:** `net_device` registration and `net_device_ops`; `sk_buff`\nlifecycle (allocation, headroom, push/pull); NAPI (why per-packet interrupts\nwould saturate the CPU and how poll-based batching avoids it); TX queue\nbackpressure under load; and network namespace isolation for testing. The\nproject includes a real end-to-end `ping` test that caught an actual bug during\ndevelopment — `IFF_NOARP` made ring counters look healthy while `ping` silently\nfailed 100% of the time.\n\n**Key object:** `struct net_device` — the networking stack's equivalent of\n`gendisk`, paired with a `struct napi_struct` per interface.\n\n---\n\n### [`pcie-edu-driver`](linux-pcie-device-driver/) — PCIe Driver for QEMU's `edu` Device\n\nA kernel module that drives QEMU's built-in `edu` educational PCI device\n(vendor `0x1234`, device `0x11e8`). Unlike the virtual drivers above, this\ntargets a device that is enumerated over the PCIe bus, has BAR-mapped memory\nregisters, raises hardware interrupts, and exposes a DMA engine — it just\nhappens to be emulated by QEMU rather than soldered to a board. The driver\ncode, and everything it has to get right, is identical to what a real NIC,\nstorage controller, or accelerator driver requires.\n\n**What it covers:** the full PCI driver lifecycle (`pci_enable_device`,\n`pci_iomap` for BAR0 MMIO, `pci_alloc_irq_vectors` for MSI,\n`dma_alloc_coherent` for DMA buffers, `pci_unregister_driver` cleanup);\n`ioread32`/`iowrite32` for MMIO register access; an MSI interrupt handler that\nwakes a wait queue to unblock a user-space `ioctl`; and a DMA round-trip test\n(host → device → host). The driver also exposes a `misc` character device at\n`/dev/pcie_edu` so user space can trigger factorial computations and DMA\ntransfers via `ioctl`.\n\n**Key object:** `struct pci_dev` — the bus-enumerated device handle, paired\nwith BAR-mapped MMIO, an MSI interrupt vector, and a `dma_alloc_coherent`\nbuffer.\n\n---\n\n### How the Four Projects Relate\n\nThe character device establishes the kernel/user-space boundary and\nsynchronization primitives. The block device moves that same contract into the\nblock layer's request/bio model, and introduces the page-cache visibility\nproblem. The networking and PCIe drivers build further on that foundation while\nintroducing their own subsystem-specific object models (`net_device`/`sk_buff`\nvs. `pci_dev`/MMIO/MSI) and execution-context rules (softirq NAPI polling vs.\nhardirq MSI handling).\n\n---\n\n## Repository Layout\n\n```text\n.\n├── linux-character-device-driver/   # circbuf — virtual character device\n├── linux-block-device-driver/       # vblk    — virtual RAM-backed block device\n├── linux-network-device-driver/     # netdrv  — virtual Ethernet driver pair\n├── linux-pcie-device-driver/        # pcie-edu-driver — QEMU \"edu\" PCIe driver\n└── LICENSE                          # MIT\n```\n\nEach subdirectory is self-contained, with its own `Makefile`, `docker/`\ntest harness, and `README.md` covering architecture, key concepts,\nbuild/test instructions, design tradeoffs, and verified test results.\n\n---\n\n## Building and Testing\n\n### Prerequisites\n\n| Tool | Minimum version | Notes |\n|---|---|---|\n| Docker | 20.10+ | Required for the recommended Docker + QEMU path |\n| QEMU | 6.0+ | Embedded inside the Docker image; no host install needed |\n| make / gcc | any recent | Only needed for native (non-Docker) builds |\n| Linux host with matching kernel headers | — | Alternative to Docker; see each project's README |\n\nNo physical hardware, no Linux host, and no QEMU pre-install are required for\nthe default Docker path. Docker pulls the matching kernel headers and QEMU\nimage automatically.\n\n### Quick start\n\nEvery driver follows the same pattern: build against real kernel headers inside\nDocker, boot a stock kernel under QEMU, then load and exercise the module\nend-to-end — not a build-only check.\n\n```bash\n# circbuf, vblk, pcie-edu-driver\ncd \u003cproject-directory\u003e\n./docker/run.sh test\n```\n\n```bash\n# netdrv (self-contained Docker image)\ncd linux-network-device-driver\ndocker build -f docker/Dockerfile -t netdrv-e2e . \u0026\u0026 docker run --rm netdrv-e2e\n```\n\n### What the harness does\n\n`docker/run.sh test` (and the equivalent `netdrv` command):\n\n1. Builds the `.ko` against real kernel headers inside a Docker container.\n2. Boots a stock `6.8.0-124-generic` kernel under QEMU with a minimal busybox\n   initramfs.\n3. `insmod`s the module, runs the test suite (basic I/O, stress, filesystem\n   mount where applicable, ioctl round-trips), and `rmmod`s the module.\n4. Checks `dmesg` for panics, lockups, or unexpected warnings.\n5. Exits non-zero on any failure.\n\n### Native (non-Docker) builds\n\nEach project's README documents a native build path for environments where\nDocker is unavailable. The general pattern:\n\n```bash\nmake                  # build the .ko against the running kernel's headers\nsudo insmod \u003cmod\u003e.ko\ndmesg | tail -20      # confirm probe / registration\nsudo ./\u003ctest_binary\u003e\nsudo rmmod \u003cmod\u003e\n```\n\nThis requires a Linux host (or VM) with matching kernel headers and — for the\nPCIe driver — a QEMU session started with `-device edu`.\n\n---\n\n## Verified Test Results\n\nAll four drivers pass their full test suites against kernel\n`6.8.0-124-generic` (Ubuntu 24.04, aarch64 / QEMU `virt` or `q35`).\n\n### circbuf\n\n| Check | Result |\n|---|---|\n| `insmod` / `rmmod` (default 4096-byte buffer) | ✅ Pass |\n| `basic_test` — write → read → `ioctl` roundtrip | ✅ Pass |\n| `query_stats` — `ioctl` buffer introspection | ✅ `capacity=4096 used=0 available=4096` |\n| `stress` — 4 writers / 4 readers, 5 s | ✅ `total_written=13682240 == total_read=13682240` |\n| Reload with `buffer_size=16384` | ✅ `capacity=16384` confirmed |\n| `dmesg` | No panics, no lockups |\n\n### vblk\n\n| Check | Result |\n|---|---|\n| `insmod` / `rmmod` (default 16 MiB) | ✅ Pass |\n| `basic_test` — `O_DIRECT` `pwrite`/`pread`/`pwritev` + `ioctl` | ✅ `capacity_bytes=16777216 reads=3 writes=3` |\n| `stress` — 4 threads, disjoint regions, 5 s | ✅ `total_written=222857728`, zero corruption |\n| `mke2fs` + `mount -t ext2` + file I/O + `umount` | ✅ Pass |\n| Reload with `disk_size_mb=8` | ✅ `capacity_bytes=8388608` confirmed |\n| `dmesg` | No panics, no lockups |\n\n### netdrv\n\n| Check | Result |\n|---|---|\n| Module load — `vnet0` / `vnet1` registered | ✅ |\n| Carrier state on `open` / `stop` | ✅ |\n| `ping` across netns pair | ✅ 4/4 packets, 0% loss |\n| `tx_packets` / `rx_packets` symmetry | ✅ 11 == 11 |\n| Flood ping with `ring_size=4` | ✅ 2000/2000, 0% loss |\n| TX backpressure under `iperf3` UDP load | ✅ `tx_queue_stops/wakes = 2`, 0 packets lost (59670 == 59670) |\n| 10× load/unload loop | ✅ clean `dmesg` throughout |\n\n### pcie-edu-driver\n\n| Check | Result |\n|---|---|\n| `edu` device enumerated (`lspci -d 1234:11e8`) | ✅ Pass |\n| `probe()` — BAR0 mapped, ident register read, DMA buffer allocated | ✅ Pass |\n| MSI vector registered (`/proc/interrupts`) | ✅ Pass |\n| `/dev/pcie_edu` opens successfully | ✅ Pass |\n| Liveness register round-trip (`write_val` → `~write_val`) | ✅ Pass |\n| `PCIE_EDU_COMPUTE` — 0!, 1!, 5!, 10!, 12! via MSI | ✅ Pass (5/5) |\n| `PCIE_EDU_DMA_TRANSFER` — 4096-byte host→device→host | ✅ Pass |\n| `remove()` / `rmmod` — no leaked MMIO or IRQ | ✅ Pass |\n\n---\n\n## References\n\n- *Linux Device Drivers, 3rd Edition* — Corbet, Rubini, Kroah-Hartman (free at lwn.net)\n- *Linux Kernel Development, 3rd Edition* — Robert Love\n- Rosen, R. *Linux Kernel Networking: Implementation and Theory*\n- `Documentation/driver-api/`, `Documentation/block/`, `Documentation/networking/napi.rst`, `Documentation/PCI/pci.rst` in the Linux kernel source tree\n\n---\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fczhao-dev%2Flinux-device-drivers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fczhao-dev%2Flinux-device-drivers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fczhao-dev%2Flinux-device-drivers/lists"}