一个内核的helloworld

本文介绍了一个简易操作系统的实现过程,包括使用QEMU作为模拟器、编写内核代码,并通过具体的汇编和C语言代码示例展示了如何显示字符串到屏幕上。
项目代码 https://github.com/killinux/mkernel

下载qemu,模拟器http://qemu.weilnetz.de/w32/qemu-20130616-w32.exe
安装后使用
E:\Program Files (x86)\qemu>qemu-system-i386.exe
代码如下
kernel.asm


bits 32
section .text
;multiboot spec
align 4
dd 0x1BADB002 ;magic
dd 0x00 ;flags
dd - (0x1BADB002 + 0x00) ;checksum. m+f+c should be zero

global start
extern kmain ;this is defined in the c file

start:
cli ;block interrupts
call kmain
hlt ;halt the CPU


kernel.c

void kmain(void)
{
char *str = "my first kernel";
//video memory begins at address 0xb8000
char *vidptr = (char*)0xb8000;
unsigned int i = 0;
unsigned int j = 0;

//this loops clears the screen
//there are 25 lines each of 80 columns; each element takes 2 bytes
while(j < 80 * 25 * 2) {
//blank character
vidptr[j] = ' ';
//attribute-byte
vidptr[j+1] = 0x07;
j = j + 2;
}

j = 0;

//this loop write the string to video memory
while(str[j] != '\0') {
//the character's ascii
vidptr[i] = str[j];
//attribute-byte: give character black bg and-light grey fg
vidptr[i+1] = 0x07;
++j;
i = i + 2;
}
return;
}


link.ld

OUTPUT_FORMAT(elf32-i386)
ENTRY(start)
SECTIONS
{
. = 0x100000;
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss) }
}



nasm -f elf32 kernel.asm -o kasm.o
gcc -m32 -c kernel.c -o kc.o
ld -m elf_i386 -T link.ld -o kernel kasm.o kc.o
sz kernel

E:\Program Files (x86)\qemu>qemu-system-i386.exe -kernel kernel

参考
http://www.geekfan.net/8663/
<think>我们使用C语言编写一个简单的Linux内核模块,它将在加载时打印"Hello, World!",在卸载时打印"Goodbye, World!"。 注意:内核模块的编写需要特定的环境(Linux系统,安装了对应版本的内核头文件)和编译方式(使用kbuild系统)。 以下是代码示例: 文件:hello_world.c 内容: ```c #include <linux/init.h> // 包含宏定义,如 module_init, module_exit #include <linux/module.h> // 包含内核模块相关的函数和宏,如 MODULE_LICENSE // 模块加载函数 static int __init hello_init(void) { printk(KERN_INFO "Hello, World!\n"); // 注意:内核中使用printk,而不是printf return 0; } // 模块卸载函数 static void __exit hello_exit(void) { printk(KERN_INFO "Goodbye, World!\n"); } // 指定模块加载和卸载的函数 module_init(hello_init); module_exit(hello_exit); // 模块的许可证声明(必须) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); // 可选 MODULE_DESCRIPTION("A simple Hello World kernel module"); // 可选 ``` 编译这个模块需要一个Makefile,内容如下(假设你的内核源代码目录在/lib/modules/$(shell uname -r)/build): ```makefile obj-m := hello_world.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean ``` 编译和使用的步骤: 1. 将上述两个文件放在同一目录。 2. 执行 `make` 命令编译模块,生成 hello_world.ko 文件。 3. 加载模块:`sudo insmod hello_world.ko`,此时会打印"Hello, World!"(但不会显示在终端,而是记录在内核日志中) 4. 查看内核日志:`dmesg | tail -n 1` 可以看到输出。 5. 卸载模块:`sudo rmmod hello_world`,然后再次查看内核日志:`dmesg | tail -n 1` 可以看到"Goodbye, World!"。 注意:由于printk输出的日志级别,有时可能不会在控制台显示,但一定会在系统日志中记录(可通过dmesg查看)。 §§相关问题§§ 1. 如何在内核模块中传递参数(例如在加载模块时指定打印的字符串)? 2. 在内核模块中,除了printk,还有哪些常用的日志输出函数或机制? 3. 编写内核模块时,为什么必须指定模块许可证(如GPL)? 4. 如何在内核模块中创建/proc文件接口与用户空间进行通信? 5. 如果多个源文件组成一个内核模块,Makefile应该如何编写?</think>以下是用C语言编写的Linux内核模块"Hello World"示例,包含模块加载/卸载函数和必要的Makefile: ### 1. 内核模块代码 (hello_world.c) ```c #include <linux/module.h> // 所有内核模块必需的头文件 #include <linux/kernel.h> // 包含printk函数声明 #include <linux/init.h> // 包含__init和__exit宏 // 模块加载函数(insmod时调用) static int __init hello_init(void) { printk(KERN_INFO "Hello, World! Kernel module loaded.\n"); return 0; // 返回0表示成功 } // 模块卸载函数(rmmod时调用) static void __exit hello_exit(void) { printk(KERN_INFO "Goodbye, World! Kernel module unloaded.\n"); } // 注册模块加载/卸载函数 module_init(hello_init); module_exit(hello_exit); // 模块元信息 MODULE_LICENSE("GPL"); // 许可证声明(必需) MODULE_AUTHOR("Your Name"); // 作者信息 MODULE_DESCRIPTION("Simple Hello World Kernel Module"); // 模块描述 MODULE_VERSION("0.1"); // 模块版本 ``` ### 2. Makefile (编译内核模块) ```makefile obj-m := hello_world.o # 指定编译目标 # 内核源代码路径(根据你的系统修改) KERNEL_DIR ?= /lib/modules/$(shell uname -r)/build all: $(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules clean: $(MAKE) -C $(KERNEL_DIR) M=$(PWD) clean ``` ### 3. 编译和使用步骤 1. **编译模块**: ```bash make ``` 生成文件:`hello_world.ko` (内核模块) 2. **加载模块**: ```bash sudo insmod hello_world.ko ``` 3. **查看输出**: ```bash dmesg | tail -n 2 # 输出示例: # [ 1234.567890] Hello, World! Kernel module loaded. ``` 4. **卸载模块**: ```bash sudo rmmod hello_world dmesg | tail -n 1 # 输出示例: # [ 1234.678901] Goodbye, World! Kernel module unloaded. ``` ### 关键点说明: 1. **printk vs printf**:内核模块使用`printk`(不是`printf`)输出日志 2. **__init/__exit宏**:标记初始化/清理函数,释放内存占用 3. **模块签名**:`MODULE_LICENSE`是必需声明(通常用GPL) 4. **内核API**:只能使用内核提供的API,不能使用标准C库 5. **安全考虑**:操作内核空间需要root权限(sudo)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值