首页
关于
Search
1
开发环境搭建(FTP、VSCode、交叉编译器、SSH、NFS、TFTP)
33 阅读
2
linux内核编译报错(gcc: not found + fatal error curses.h)
26 阅读
3
安装WMware Tools选项显示灰色解决方法及WMware Tools安装笔记
17 阅读
4
ubuntu24.2下解压.tar.bz2报错(bzip2: 无法exec:没有那个文件或目录)
14 阅读
5
linux内核编译报错(usr/bin/ld: scripts/dtc/dtc-parser.tab.o:(.bss+0x50): multiple definition of 'yylloc';)
14 阅读
学习笔记
linux学习笔记
文件系统
FreeRTOS
资源分享
小作品
登录
/
注册
Search
Warren
累计撰写
37
篇文章
累计收到
1
条评论
首页
栏目
学习笔记
linux学习笔记
文件系统
FreeRTOS
资源分享
小作品
页面
关于
搜索到
37
篇与
的结果
2024-11-07
Linux内核定时器实验
定时器简介内核时间管理简介Linux内核使用定时器中断来计时。中断周期性产生的频率就是系统频率,也叫做节拍率(tick rate)(有的资料也叫系统频率)。系统节拍率是可以设置的,单位是 Hz,在编译 Linux 内核的时候可以通过图形化界面设置系统节拍率,按照如下路径打开配置界面。 -> Kernel Features -> Timer frequency (<choice> [=y])高节拍率会提高系统时间精度,但是高节拍率会导致中断的产生更加频繁,频繁的中断会加剧系统的负担。一般来说,使用100M的系统节拍率就基本满足日常需求了。Linux内核使用全局变量jiffies来记录系统启动以来的系统节拍数,系统启动的时候会将 jiffies 初始化为 0。在64位的系统中使用的是jiffies_64。表示的范围更广了。jiffies是jiffies_64的低32bit。不管是 32 位的系统还是 64 位系统,都可以使用 jiffies。32位的jiffies有绕回风险,为此linux内核提高了如下函数来处理绕回。下面两个相比于上面上个增加了等于的条件。如果 unkown 超过 known 的话, time_after 函数返回真,否则返回假为了方便开发, Linux 内核还提供了几个 jiffies 和 ms、 us、 ns 之间的转换函数内核定时器简介Linux 内核定时器采用系统时钟来实现,并不是硬件定时器。使用很简单,只需要提供超时时间(相当于定时值)和定时处理函数即可。当超时时间到了以后设置的定时处理函数就会执行。内核定时器并不是周期性运行的,超时以后就会自动关闭,因此如果想要实现周期性定时,那么就需要在定时处理函数中重新开启定时器。Linux 内核使用 timer_list 结构体表示内核定时器, timer_list 定义在文件include/linux/timer.h 中,定义如下 struct timer_list { struct list_head entry; unsigned long expires; /* 定时器超时时间,单位是节拍数 */ struct tvec_base *base; void (*function)(unsigned long); /* 定时处理函数 */ unsigned long data; /* 要传递给 function 函数的参数 */ int slack; };要使用内核定时器首先要先定义一个 timer_list 变量,表示定时器。定义好定时器以后还需要通过一系列的 API 函数来初始化此定时器 { } init_timer 函数 init_timer 函数负责初始化 timer_list 类型变量,当我们定义了一个 timer_list 变量以后一定要先用 init_timer 初始化一下。函数原型如下://timer:要初始化定时器 void init_timer(struct timer_list *timer){ } add_timer 函数 add_timer 函数用于向 Linux 内核注册定时器,使用 add_timer 函数向内核注册定时器以后,定时器就会开始运行。函数原型如下://timer:要注册的定时器 void add_timer(struct timer_list *timer){ } del_timer 函数 del_timer 函数用于删除一个定时器,不管定时器有没有被激活,都可以使用此函数删除。在多处理器系统上,定时器可能会在其他的处理器上运行,因此在调用 del_timer 函数删除定时器之前要先等待其他处理器的定时处理器函数退出。也就是说,管你有没有用直接干掉。函数原型如下://timer:要删除的定时器 //返回值: 0,定时器还没被激活; 1,定时器已经激活。 int del_timer(struct timer_list * timer){ } del_timer_sync 函数 del_timer_sync 函数是 del_timer 函数的同步版,等到定时器没有使用状态下,才删除。函数原型如下: //timer:要删除的定时器。 //返回值: 0,定时器还没被激活; 1,定时器已经激活。 int del_timer_sync(struct timer_list *timer){ } mod_timer 函数 mod_timer 函数用于修改定时值,如果定时器还没有激活的话, mod_timer 函数会激活定时器,函数原型如下: //timer:要修改超时时间(定时值)的定时器。 //expires:修改后的超时时间。 //返回值: 0,调用 mod_timer 函数前定时器未被激活; 1,调用 mod_timer 函数前定时器已被激活 int mod_timer(struct timer_list *timer, unsigned long expires)Linux内核短延时函数Linux 内核提供了毫秒、微秒和纳秒延时函数。API如下所示程序编写设备树修改{alert type="info"}设备树与LED实验一致{/alert}驱动程序编写#include "linux/types.h" #include "linux/kernel.h" #include "linux/delay.h" #include "linux/ide.h" #include "linux/init.h" #include "linux/module.h" #include "linux/errno.h" #include "linux/gpio.h" #include "linux/cdev.h" #include "linux/device.h" #include "linux/of.h" #include "linux/of_address.h" #include "linux/of_gpio.h" #include "linux/semaphore.h" #include "linux/timer.h" #include "asm/mach/map.h" #include "asm/uaccess.h" #include "asm/io.h" #define TIMER_CNT 1 #define TIMER_NAME "timer" #define CLOSE_CMD (_IO(0xEF, 0x01)) #define OPEN_CMD (_IO(0xEF, 0x02)) #define SETPERIOD_CMD (_IO(0xEF, 0x03)) #define LEDON 1 #define LEDOFF 0 struct timer_dev{ dev_t devid; struct cdev cdev; struct class *class; struct device *device; int major; int minor; struct device_node *nd; int led_gpio; int timeperiod; struct timer_list timer; spinlock_t lock; }; struct timer_dev timerdev; static int led_init(void) { int retvalue = 0; timerdev.nd = of_find_node_by_path("/led"); if(timerdev.nd == NULL){ return -EINVAL; } timerdev.led_gpio = of_get_named_gpio(timerdev.nd, "led-gpio", 0); if(timerdev.led_gpio < 0){ printk("can't get led\r\n"); return -EINVAL; } gpio_request(timerdev.led_gpio, "led"); retvalue = gpio_direction_output(timerdev.led_gpio, 1); if(retvalue < 0){ printk("can't set gpio\r\n"); return -EINVAL; } return 0; } static void led_deinit(void) { gpio_free(timerdev.led_gpio); } static int timer_open(struct inode *node, struct file *filp) { int retvalue = 0; retvalue = led_init(); if(retvalue < 0){ printk("led init failed\r\n"); return retvalue; } filp->private_data = &timerdev; timerdev.timeperiod = 1000; return 0; } static long timer_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct timer_dev *dev = (struct timer_dev *)filp->private_data; int timerperiod; unsigned long flags; switch(cmd){ case CLOSE_CMD :{ del_timer_sync(&dev->timer); break; } case OPEN_CMD :{ spin_lock_irqsave(&dev->lock, flags); timerperiod = dev->timeperiod; spin_unlock_irqrestore(&dev->lock, flags); mod_timer(&dev->timer, jiffies + msecs_to_jiffies(timerperiod)); break; } case SETPERIOD_CMD :{ spin_lock_irqsave(&dev->lock, flags); dev->timeperiod = arg; spin_unlock_irqrestore(&dev->lock, flags); mod_timer(&dev->timer, jiffies + msecs_to_jiffies(arg)); break; } default :{ break; } } return 0; } static struct file_operations timer_fops = { .owner = THIS_MODULE, .open = timer_open, .unlocked_ioctl = timer_unlocked_ioctl, }; void timer_function(unsigned long arg) { struct timer_dev *dev = (struct timer_dev *)arg; static int sta = 1; int timerperod; unsigned long flags; sta = !sta; gpio_set_value(dev->led_gpio, sta); spin_lock_irqsave(&dev->lock, flags); timerperod = dev->timeperiod; spin_unlock_irqrestore(&dev->lock, flags); mod_timer(&dev->timer, jiffies + msecs_to_jiffies(timerperod)); } static int __init timer_init(void) { spin_lock_init(&timerdev.lock); if(timerdev.major){ timerdev.devid = MKDEV(timerdev.major, 0); register_chrdev_region(timerdev.devid, TIMER_CNT, TIMER_NAME); }else{ alloc_chrdev_region(&timerdev.devid, 0, TIMER_CNT, TIMER_NAME); timerdev.major = MAJOR(timerdev.devid); timerdev.minor = MINOR(timerdev.devid); } timerdev.cdev.owner = THIS_MODULE; cdev_init(&timerdev.cdev, &timer_fops); cdev_add(&timerdev.cdev, timerdev.devid, TIMER_CNT); timerdev.class = class_create(THIS_MODULE, TIMER_NAME); if(IS_ERR(timerdev.class)){ return PTR_ERR(timerdev.class); } timerdev.device = device_create(timerdev.class, NULL, timerdev.devid, NULL, TIMER_NAME); if(IS_ERR(timerdev.device)){ return PTR_ERR(timerdev.device); } init_timer(&timerdev.timer); timerdev.timer.function = timer_function; timerdev.timer.data = (unsigned long)&timerdev; return 0; } static void __exit timer_exit(void) { gpio_set_value(timerdev.led_gpio, 1); del_timer_sync(&timerdev.timer); // led_deinit(); cdev_del(&timerdev.cdev); unregister_chrdev_region(timerdev.devid, TIMER_CNT); device_destroy(timerdev.class, timerdev.devid); class_destroy(timerdev.class); } module_init(timer_init); module_exit(timer_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("warren");应用程序编写#include "stdio.h" #include "unistd.h" #include "sys/types.h" #include "sys/stat.h" #include "fcntl.h" #include "stdlib.h" #include "string.h" #include "linux/ioctl.h" #define CLOSE_CMD (_IO(0xEF, 0x01)) #define OPEN_CMD (_IO(0xEF, 0x02)) #define SETPERIOD_CMD (_IO(0xEF, 0x03)) int main(int argc, int *argv[]) { int fd, retvalue; char *filename; unsigned int cmd; unsigned int arg; unsigned char str[100]; if(argc != 2){ printf("error usage\r\n"); return -1; } filename = argv[1]; fd = open(filename, O_RDWR); if(fd < 0){ printf("can't open %s\r\n", filename); return -1; } while(1){ printf("input cmd:"); retvalue = scanf("%d", &cmd); if(retvalue != 1){ gets(str); } if(cmd == 1) cmd = CLOSE_CMD; else if (cmd == 2){ cmd = OPEN_CMD; }else if(cmd == 3){ cmd = SETPERIOD_CMD; printf("input timer period:"); retvalue = scanf("%d", &arg); if(retvalue != 1){ gets(str); } }else{ continue; } ioctl(fd, cmd, arg); } close(fd); return 0; }
2024年11月07日
3 阅读
0 评论
0 点赞
2024-11-07
Linux按键输入实验
原理分析按键驱动和LED驱动一样,都是GPIO驱动。一个是读取GPIO的电平,一个是从GPIO输出高低电平。另外还有个区别,LED实验中,led资源只有驱动程序访问;但按键实验中,键值信息不但需要更新而且需要供应用程序读取。所以键值信息就需要用信号量来保护起来。程序编写设备树文件修改添加pinctrl节点 pinctrl_key: keygrp { fsl,pins = < MX6UL_PAD_UART1_CTS_B__GPIO1_IO18 0xF080 /* KEY0 */ >; };添加key设备节点 key{ #address-cell = <1>; #size-cells = <1>; compatible = "warren-key"; pinctrl-name = "default"; pinctrl-0 = <&pinctrl_key>; key-gpio = <&gpio1 18 GPIO_ACTIVE_HIGH>; status = "okay"; };驱动程序编写#include "linux/types.h" #include "linux/kernel.h" #include "linux/delay.h" #include "linux/ide.h" #include "linux/init.h" #include "linux/module.h" #include "linux/errno.h" #include "linux/gpio.h" #include "linux/cdev.h" #include "linux/device.h" #include "linux/of.h" #include "linux/of_address.h" #include "linux/of_gpio.h" #include "linux/semaphore.h" #include "asm/mach/map.h" #include "asm/uaccess.h" #include "asm/io.h" #define KEY_CNT 1 #define KEY_NAME "key" #define KEY0VALUE 0xF0 #define INVAKEY 0x00 struct key_dev{ dev_t devid; struct cdev cdev; struct class *class; struct device *device; int major; int minor; struct device_node *nd; int key_gpio; atomic_t keyvalue; }; struct key_dev keydev; static int keyio_init(void) { int ret = 0; keydev.nd = of_find_node_by_path("/key"); if(keydev.nd == NULL){ return -EINVAL; } keydev.key_gpio = of_get_named_gpio(keydev.nd, "key-gpio", 0); if(keydev.key_gpio < 0){ printk("can't get key0\r\n"); return -EINVAL; } printk("key_gpio=%d\r\n", keydev.key_gpio); ret = gpio_request(keydev.key_gpio, "key0"); gpio_direction_input(keydev.key_gpio); return 0; } static int key_open(struct inode *inode, struct file *filp) { int ret = 0; filp->private_data = &keydev; ret = keyio_init(); if(ret < 0){ return ret; } return 0; } static ssize_t key_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt) { int ret = 0; unsigned char value; struct key_dev *dev = filp->private_data; if(gpio_get_value(dev->key_gpio)==0){ while(gpio_get_value(dev->key_gpio) != 0); atomic_set(&dev->keyvalue, KEY0VALUE); }else{ atomic_set(&dev->keyvalue, INVAKEY); } value = atomic_read(&dev->keyvalue); ret = copy_to_user(buf, &value, sizeof(value)); return ret; } static struct file_operations key_fops = { .owner = THIS_MODULE, .open = key_open, .read = key_read, }; static int __init mykey_init(void) { atomic_set(&keydev.keyvalue, INVAKEY); if(keydev.major){ keydev.devid = MKDEV(keydev.major, 0); register_chrdev_region(keydev.devid, KEY_CNT, KEY_NAME); }else{ alloc_chrdev_region(&keydev.devid, 0, KEY_CNT, KEY_NAME); keydev.major = MAJOR(keydev.devid); keydev.minor = MINOR(keydev.devid); } keydev.cdev.owner = THIS_MODULE; cdev_init(&keydev.cdev, &key_fops); cdev_add(&keydev.cdev, keydev.devid, KEY_CNT); keydev.class = class_create(THIS_MODULE, KEY_NAME); if(IS_ERR(keydev.class)){ return PTR_ERR(keydev.class); } keydev.device = device_create(keydev.class, NULL, keydev.devid, NULL, KEY_NAME); if(IS_ERR(keydev.device)){ return PTR_ERR(keydev.device); } return 0; } static void __exit mykey_exit(void) { cdev_del(&keydev.cdev); unregister_chrdev_region(keydev.devid, KEY_CNT); device_destroy(keydev.class, keydev.devid); class_destroy(keydev.class); } module_init(mykey_init); module_exit(mykey_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("warren");测试程序编写#include "stdio.h" #include "unistd.h" #include "sys/types.h" #include "sys/stat.h" #include "fcntl.h" #include "stdlib.h" #include "string.h" #define KEY0VALUE 0xF0 int main(int argc, int *argv[]) { int fd; char *filename = NULL; char keyvalue = 0; int retvalue = 0; if(argc != 2){ printf("error usage!\r\n"); return -1; } filename = (char*)argv[1]; fd = open(filename, O_RDWR); if(fd < 0){ printf("file %s open failed\r\n", filename); return -1; } while(1) { read(fd, &keyvalue, sizeof(keyvalue)); if(keyvalue == KEY0VALUE){ usleep(1); if(keyvalue == KEY0VALUE){ printf("key 0 press, value = %#x\r\n", keyvalue); while(1){ read(fd, &keyvalue, sizeof(keyvalue)); if(keyvalue != KEY0VALUE){ break; } } } } } retvalue = close(fd); if(retvalue < 0){ printf("file %s close failed\r\n", filename); return -1; } return 0; }
2024年11月07日
3 阅读
0 评论
0 点赞
2024-11-02
Linux并发与竞争-原子操作
并发与竞争并发与竞争简介因为Linux系统是个多任务操作系统,会存在多个任务同时使用一个资源的问题。就会导致系统奔溃。原因有如下几点:① 多线程并发访问② 抢占式并发访问③ 中断程序并发访问④ 多核见并发访问总的来说就是多个程序并发访问同一个资源的问题,解决办法就是阻止多个程序同时访问同一个资源。就是说A程序在访问这个资源时候,B程序访问不了这个资源。需要用到下面4个东东(原子操作、自旋锁、信号量、互斥体)原子操作简介原子操作就是指不能再进一步分割的操作。就是CPU只需要一条指向就可以执行完的操作原子整形操作API函数Linux 内核定义了叫做 atomic_t 的结构体来完成整形数据的原子操作。此结构体定义在 include/linux/types.h 文件中,定义如下: /*32bit*/ typedef struct { int counter; } atomic_t; /*64bit*/ typedef struct { long long counter; } atomic64_t;如果要使用原子操作 API 函数,首先要先定义一个 atomic_t 的变量 atomic_t a;也可以在定义原子变量的时候给原子变量赋初值 atomic_t b = ATOMIC_INIT(0);关于原子操作API函数如下相应的也提供了 64 位原子变量的操作 API 函数; API 函数用法一样,只是将“atomic_”前缀换为“atomic64_”,将 int 换为 long long。关于原子位操作API函数如下原子位操作是直接对内存进行操作,不像原子整形变量那样有个 atomic_t 的数据结构。API 函数如下;原子操作实验设备树文件修改在iomuxc节点下的imx6ul-evk节点下创建pinctrl_led节点 pinctrl_led : ledgrp{ fsl,pins< IMX6UL_PAD_GPIO01_IO03__GPIO1_IO03 0x10B0 >; };在根节点/下创建LED节点 gpioled : { #address-cells = <1>; #size-cells = <1>; compatible = "warren-gpioled"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_led>; led-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>; };驱动程序#include "linux/types.h" #include "linux/kernel.h" #include "linux/delay.h" #include "linux/ide.h" #include "linux/init.h" #include "linux/module.h" #include "linux/errno.h" #include "linux/gpio.h" #include "linux/cdev.h" #include "linux/device.h" #include "linux/of.h" #include "linux/of_address.h" #include "linux/of_gpio.h" #include "asm/mach/map.h" #include "asm/uaccess.h" #include "asm/io.h" #define GPIOLED_CNT 1 #define GPIOLED_NAME "led" #define LEDON 1 #define LEDOFF 0 struct gpioled_dev{ dev_t devid; struct cdev cdev; struct class *class; struct device *device; int major; int minor; struct device_node *nd; int led_gpio; atomic_t lock; }; struct gpioled_dev gpioled; static int led_open(struct inode *inode, struct file *filp) { if(!atomic_dec_and_test(&gpioled.lock)){ atomic_inc(&gpioled.lock); return -EBUSY; } filp->private_data = &gpioled; return 0; } static int led_release(struct inode *inode, struct file *filp) { struct gpioled_dev *dev = filp->private_data; atomic_inc(&dev->lock); return 0; } static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt) { return 0; } static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) { int retvalue; unsigned char databuf[1]; unsigned char ledstat; struct gpioled_dev *dev = filp->private_data; retvalue = copy_from_user(databuf, buf, cnt); if(retvalue < 0){ printk("kernel write failed!\r\n"); return -EFAULT; } ledstat = databuf[0]; if(ledstat == LEDON){ gpio_set_value(dev->led_gpio, 0); }else if(ledstat == LEDOFF){ gpio_set_value(dev->led_gpio, 1); } return 0; } static struct file_operations gpioled_fops = { .owner = THIS_MODULE, .open = led_open, .release = led_release, .write = led_write, .read = led_read, }; static int __init led_init(void) { int ret = 0; atomic_set(&gpioled.lock, 1); gpioled.nd = of_find_node_by_path("/led"); if(gpioled.nd == NULL){ printk("gpioled node find failed!\r\n"); return -EINVAL; }else{ printk("gpioled node find success!\r\n"); } gpioled.led_gpio = of_get_named_gpio(gpioled.nd, "led-gpio", 0); if(gpioled.led_gpio < 0){ printk("can't get led-gpio\r\n"); return -EINVAL; } printk("led-gpio num = %d\r\n", gpioled.led_gpio); ret = gpio_direction_output(gpioled.led_gpio, 1); if(ret < 0){ printk("can't set gpio!\r\n"); } if(gpioled.major){ gpioled.devid = MKDEV(gpioled.major, 0); register_chrdev_region(gpioled.devid, GPIOLED_CNT, GPIOLED_NAME); }else{ alloc_chrdev_region(&gpioled.devid, 0, GPIOLED_CNT, GPIOLED_NAME); gpioled.major = MAJOR(gpioled.devid); gpioled.minor = MINOR(gpioled.devid); } printk("gpioled major = %d, minor = %d\r\n", gpioled.major, gpioled.minor); gpioled.cdev.owner = THIS_MODULE; cdev_init(&gpioled.cdev, &gpioled_fops); cdev_add(&gpioled.cdev, gpioled.devid, GPIOLED_CNT); gpioled.class = class_create(THIS_MODULE, GPIOLED_NAME); if(IS_ERR(gpioled.class)){ return PTR_ERR(gpioled.class); } gpioled.device = device_create(gpioled.class, NULL, gpioled.devid, NULL, GPIOLED_NAME); if(IS_ERR(gpioled.device)){ return PTR_ERR(gpioled.device); } return 0; } static void __exit led_exit(void) { cdev_del(&gpioled.cdev); unregister_chrdev_region(gpioled.devid, GPIOLED_CNT); device_destroy(gpioled.class, gpioled.devid); class_destroy(gpioled.class); } module_init(led_init); module_exit(led_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("warren");应用程序#include "stdio.h" #include "unistd.h" #include "sys/types.h" #include "sys/stat.h" #include "fcntl.h" #include "stdlib.h" #include "string.h" int main(int argc, int *argv[]) { int fd; char *filename = NULL; char data = 0; int retvalue = 0; int cnt = 0; if(argc != 3){ printf("error usage!\r\n"); return -1; } filename = (char*)argv[1]; fd = open(filename, O_RDWR); if(fd < 0){ printf("file %s open failed\r\n", filename); return -1; } data = atoi(argv[2]); retvalue = write(fd, &data, 1); if(retvalue < 0){ printf("write %s failed\r\n", filename); close(fd); return -1; } while(1){ sleep (1); cnt++; printf("App runing times : %d\r\n", cnt); if(cnt > 5){ break; } } printf("App runing finished\r\n"); retvalue = close(fd); if(retvalue < 0){ printf("file %s close failed\r\n", filename); return -1; } return 0; }自旋锁简介原子操作只能保护一个变量的值,并不能保护结构体变量。或者说原子操作的进一步使用就是自旋锁。自旋锁的缺点:那就等待自旋锁的线程会一直处于自旋状态,这样会浪费处理器时间,降低系统性能,所以自旋锁的持有时间不能太长。Linux 内核使用结构体 spinlock_t 表示自旋锁,结构体定义如下所示:typedef struct spinlock { union { struct raw_spinlock rlock; #ifdef CONFIG_DEBUG_LOCK_ALLOC # define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map)) struct { u8 __padding[LOCK_PADSIZE]; struct lockdep_map dep_map; }; #endif }; } spinlock_t;在使用自旋锁之前,肯定要先定义一个自旋锁变量,定义方法如下spinlock_t lock;自旋锁API函数 被自旋锁保护的临界区一定不能调用任何能够引起睡眠和阻塞的API 函数,否则的话会可能会导致死锁现象的发生。 比如有两个线程AB。A线程加锁后进入睡眠了。B线程因为获取不到锁,导致B线程一直死等。就会导致锁死现象。 还有种情况就是在中断里面加锁,假设在中断A中加锁,还没来得及解锁就被新中断打断或者被抢占。导致锁死。所以说在中断中使用自旋锁时候需要在获取锁之前先禁止本地中断。在释放锁之后使能本地中断。Linux内核提供了相应的API函数,如下。 不推荐使用spin_lock_irq/spin_unlock_irq。建议使用 spin_lock_irqsave/ spin_unlock_irqrestore,因为这一组函数会保存中断状态,在释放锁的时候会恢复中断状态。一般在线程中使用 spin_lock_irqsave/spin_unlock_irqrestore,在中断中使用 spin_lock/spin_unlock。 在Linux中,中断处理被分为两个主要部分:顶半部(上半部,Top Half)和下半部(Bottom Half)。这种设计是为了解决中断处理程序执行时间过长和中断丢失的问题,同时确保关键任务能够迅速得到响应。 顶半部的主要任务是快速处理中断,并暂时关闭中断请求。它主要处理与硬件紧密相关或时间敏感的事情,比如对硬件的读取寄存器中的中断状态并清除中断标志。当一个中断发生时,顶半部会进行相应的硬件操作,并将中断例程的下半部挂到该设备的下半部执行队列中。由于顶半部的执行速度很快,它可以服务更多的中断请求 下半部用于延迟处理顶半部未完成的工作。与顶半部不同,下半部是可以被中断的,这意味着它可以在执行过程中被新的中断打断。下半部几乎执行了中断处理程序的所有任务,但它并不是非常紧急的,通常比较耗时。因此,它的执行时机由系统自行安排,并不在中断服务上下文中执行。 下半部(BH)也会竞争共享资源,如果要在下半部里面使用自旋锁,可以使用下列API函数自旋锁实验设备树文件修改{alert type="info"}与原子锁一致{/alert}驱动程序编写#include "linux/types.h" #include "linux/kernel.h" #include "linux/delay.h" #include "linux/ide.h" #include "linux/init.h" #include "linux/module.h" #include "linux/errno.h" #include "linux/gpio.h" #include "linux/cdev.h" #include "linux/device.h" #include "linux/of.h" #include "linux/of_address.h" #include "linux/of_gpio.h" #include "asm/mach/map.h" #include "asm/uaccess.h" #include "asm/io.h" #define GPIOLED_CNT 1 #define GPIOLED_NAME "led" #define LEDON 1 #define LEDOFF 0 struct gpioled_dev{ dev_t devid; struct cdev cdev; struct class *class; struct device *device; int major; int minor; struct device_node *nd; int led_gpio; int dev_stats; spinlock_t lock; }; struct gpioled_dev gpioled; static int led_open(struct inode *inode, struct file *filp) { unsigned long flags; filp->private_data = &gpioled; spin_lock_irqsave(&gpioled.lock, flags); //加锁 if(gpioled.dev_stats){ //设备正在使用 spin_unlock_irqrestore(&gpioled.lock, flags); //解锁 return -EBUSY; } gpioled.dev_stats++; spin_unlock_irqrestore(&gpioled.lock, flags); //解锁 return 0; } static int led_release(struct inode *inode, struct file *filp) { struct gpioled_dev *dev = filp->private_data; unsigned long flags; spin_lock_irqsave(&dev->lock, flags); //加锁 if(gpioled.dev_stats){ gpioled.dev_stats--; } spin_unlock_irqrestore(&dev->lock, flags); //解锁 return 0; } static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt) { return 0; } static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) { int retvalue; unsigned char databuf[1]; unsigned char ledstat; struct gpioled_dev *dev = filp->private_data; retvalue = copy_from_user(databuf, buf, cnt); if(retvalue < 0){ printk("kernel write failed!\r\n"); return -EFAULT; } ledstat = databuf[0]; if(ledstat == LEDON){ gpio_set_value(dev->led_gpio, 0); }else if(ledstat == LEDOFF){ gpio_set_value(dev->led_gpio, 1); } return 0; } static struct file_operations gpioled_fops = { .owner = THIS_MODULE, .open = led_open, .release = led_release, .write = led_write, .read = led_read, }; static int __init led_init(void) { int ret = 0; spin_lock_init(&gpioled.lock); gpioled.nd = of_find_node_by_path("/led"); if(gpioled.nd == NULL){ printk("gpioled node find failed!\r\n"); return -EINVAL; }else{ printk("gpioled node find success!\r\n"); } gpioled.led_gpio = of_get_named_gpio(gpioled.nd, "led-gpio", 0); if(gpioled.led_gpio < 0){ printk("can't get led-gpio\r\n"); return -EINVAL; } printk("led-gpio num = %d\r\n", gpioled.led_gpio); ret = gpio_direction_output(gpioled.led_gpio, 1); if(ret < 0){ printk("can't set gpio!\r\n"); } if(gpioled.major){ gpioled.devid = MKDEV(gpioled.major, 0); register_chrdev_region(gpioled.devid, GPIOLED_CNT, GPIOLED_NAME); }else{ alloc_chrdev_region(&gpioled.devid, 0, GPIOLED_CNT, GPIOLED_NAME); gpioled.major = MAJOR(gpioled.devid); gpioled.minor = MINOR(gpioled.devid); } printk("gpioled major = %d, minor = %d\r\n", gpioled.major, gpioled.minor); gpioled.cdev.owner = THIS_MODULE; cdev_init(&gpioled.cdev, &gpioled_fops); cdev_add(&gpioled.cdev, gpioled.devid, GPIOLED_CNT); gpioled.class = class_create(THIS_MODULE, GPIOLED_NAME); if(IS_ERR(gpioled.class)){ return PTR_ERR(gpioled.class); } gpioled.device = device_create(gpioled.class, NULL, gpioled.devid, NULL, GPIOLED_NAME); if(IS_ERR(gpioled.device)){ return PTR_ERR(gpioled.device); } return 0; } static void __exit led_exit(void) { cdev_del(&gpioled.cdev); unregister_chrdev_region(gpioled.devid, GPIOLED_CNT); device_destroy(gpioled.class, gpioled.devid); class_destroy(gpioled.class); } module_init(led_init); module_exit(led_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("warren");实验程序编写{alert type="info"}与原子锁一致{/alert}实验现象{alert type="info"}与原子锁一致{/alert}信号量信号量简介信号量就是自旋锁的升级版本,自旋锁在解锁失败时候会死等,直到解锁成功为止。信号量则在获取不到时候进入到休眠状态。可以看到信号量的开销要比自旋锁大,因为信号量使线程进入休眠状态以后会切换线程,切换线程就会有开销。 信号量的特点:.因为信号量可以使等待资源线程进入休眠状态,因此适用于那些占用资源比较久的场合因此信号量不能用于中断中,因为信号量会引起休眠,中断不能休眠如果共享资源的持有时间比较短,那就不适合使用信号量了,因为频繁的休眠、切换线程引起的开销要远大于信号量带来的那点优势 信号量就是生产者与消费者的关系,因为它允许多个线程同时访问共享资源。 Linux 内核使用 semaphore 结构体表示信号量,结构体内容如下所示 struct semaphore { raw_spinlock_t lock; unsigned int count; struct list_head wait_list; };信号量API函数信号量的使用如下: struct semaphore sem; /*定义信号量*/ sema_init(&sem, 1); /*初始化信号量*/ down(&sem); /*申请信号量, 申请不到会进入到睡眠但睡眠可以被信号打断*/ down_trylock(&sem);/*申请信号量, 申请不到立即返回非0,不会进入到睡眠*/ dowm_interruptible(&sem);/*申请信号量, 申请不到会进入到睡眠, 但睡眠可以被信号打断*/ up(&sem); /*释放信号量*/驱动程序编写#include "linux/types.h" #include "linux/kernel.h" #include "linux/delay.h" #include "linux/ide.h" #include "linux/init.h" #include "linux/module.h" #include "linux/errno.h" #include "linux/gpio.h" #include "linux/cdev.h" #include "linux/device.h" #include "linux/of.h" #include "linux/of_address.h" #include "linux/of_gpio.h" #include "asm/mach/map.h" #include "asm/uaccess.h" #include "asm/io.h" #include "linux/semaphore.h" #define GPIOLED_CNT 1 #define GPIOLED_NAME "led" #define LEDON 1 #define LEDOFF 0 struct gpioled_dev{ dev_t devid; struct cdev cdev; struct class *class; struct device *device; int major; int minor; struct device_node *nd; int led_gpio; struct semaphore sem; }; struct gpioled_dev gpioled; static int led_open(struct inode *inode, struct file *filp) { filp->private_data = &gpioled; if(down_interruptible(&gpioled.sem)){ return -ERESTARTSYS; } return 0; } static int led_release(struct inode *inode, struct file *filp) { struct gpioled_dev *dev = filp->private_data; up(&dev->sem); return 0; } static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt) { return 0; } static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) { int retvalue; unsigned char databuf[1]; unsigned char ledstat; struct gpioled_dev *dev = filp->private_data; retvalue = copy_from_user(databuf, buf, cnt); if(retvalue < 0){ printk("kernel write failed!\r\n"); return -EFAULT; } ledstat = databuf[0]; if(ledstat == LEDON){ gpio_set_value(dev->led_gpio, 0); }else if(ledstat == LEDOFF){ gpio_set_value(dev->led_gpio, 1); } return 0; } static struct file_operations gpioled_fops = { .owner = THIS_MODULE, .open = led_open, .release = led_release, .write = led_write, .read = led_read, }; static int __init led_init(void) { int ret = 0; sema_init(&gpioled.sem, 1); gpioled.nd = of_find_node_by_path("/led"); if(gpioled.nd == NULL){ printk("gpioled node find failed!\r\n"); return -EINVAL; }else{ printk("gpioled node find success!\r\n"); } gpioled.led_gpio = of_get_named_gpio(gpioled.nd, "led-gpio", 0); if(gpioled.led_gpio < 0){ printk("can't get led-gpio\r\n"); return -EINVAL; } printk("led-gpio num = %d\r\n", gpioled.led_gpio); ret = gpio_direction_output(gpioled.led_gpio, 1); if(ret < 0){ printk("can't set gpio!\r\n"); } if(gpioled.major){ gpioled.devid = MKDEV(gpioled.major, 0); register_chrdev_region(gpioled.devid, GPIOLED_CNT, GPIOLED_NAME); }else{ alloc_chrdev_region(&gpioled.devid, 0, GPIOLED_CNT, GPIOLED_NAME); gpioled.major = MAJOR(gpioled.devid); gpioled.minor = MINOR(gpioled.devid); } printk("gpioled major = %d, minor = %d\r\n", gpioled.major, gpioled.minor); gpioled.cdev.owner = THIS_MODULE; cdev_init(&gpioled.cdev, &gpioled_fops); cdev_add(&gpioled.cdev, gpioled.devid, GPIOLED_CNT); gpioled.class = class_create(THIS_MODULE, GPIOLED_NAME); if(IS_ERR(gpioled.class)){ return PTR_ERR(gpioled.class); } gpioled.device = device_create(gpioled.class, NULL, gpioled.devid, NULL, GPIOLED_NAME); if(IS_ERR(gpioled.device)){ return PTR_ERR(gpioled.device); } return 0; } static void __exit led_exit(void) { cdev_del(&gpioled.cdev); unregister_chrdev_region(gpioled.devid, GPIOLED_CNT); device_destroy(gpioled.class, gpioled.devid); class_destroy(gpioled.class); } module_init(led_init); module_exit(led_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("warren");应用程序编写{alert type="info"}与原子锁一致{/alert}实验现象互斥体互斥体简介互斥体就是信号量的特殊化,一次只允许一个线程拥有资源的所有权。将信号量的值设置为 1 就可以使用信号量进行互斥访问了。Linux 内核使用 mutex 结构体表示互斥体,定义如下。struct mutex { /* 1: unlocked, 0: locked, negative: locked, possible waiters */ atomic_t count; spinlock_t wait_lock; };mutex 之前要先定义一个 mutex 变量 struct mutex lock;使用 mutex 的时候要注意如下几点 {mutex 可以导致休眠,因此不能在中断中使用 mutex,中断中只能使用自旋锁} {和信号量一样, mutex 保护的临界区可以调用引起阻塞的 API 函数} {因为一次只有一个线程可以持有 mutex,因此,必须由 mutex 的持有者释放 mutex。并且 mutex 不能递归上锁和解锁}互斥体API函数互斥体的使用如下 struct mutex lock; /*互斥体定义*/ mutex_init(&lock); /*互斥体初始化*/ mutex_lock(&lock); /*获取互斥锁, 获取不到就睡觉且不能被打断*/ mutex_trylock(&lock);/*获取互斥锁,获取不到直接返回0*/ mutex_is_locked(&lock);/*查看互斥锁是否被获取,是返回1 否返回0*/ mutex_lock_interruptible(&lock);/*获取互斥锁,获取不到就睡觉,且可以被信号打断*/ mutex_unlock(&lock);驱动程序编写#include "linux/types.h" #include "linux/kernel.h" #include "linux/delay.h" #include "linux/ide.h" #include "linux/init.h" #include "linux/module.h" #include "linux/errno.h" #include "linux/gpio.h" #include "linux/cdev.h" #include "linux/device.h" #include "linux/of.h" #include "linux/of_address.h" #include "linux/of_gpio.h" #include "asm/mach/map.h" #include "asm/uaccess.h" #include "asm/io.h" #include "linux/mutex.h" #define GPIOLED_CNT 1 #define GPIOLED_NAME "led" #define LEDON 1 #define LEDOFF 0 struct gpioled_dev{ dev_t devid; struct cdev cdev; struct class *class; struct device *device; int major; int minor; struct device_node *nd; int led_gpio; struct mutex lock; }; struct gpioled_dev gpioled; static int led_open(struct inode *inode, struct file *filp) { filp->private_data = &gpioled; if(mutex_lock_interruptible(&gpioled.lock)){ return -ERESTARTSYS; } return 0; } static int led_release(struct inode *inode, struct file *filp) { struct gpioled_dev *dev = filp->private_data; mutex_unlock(&dev->lock); return 0; } static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt) { return 0; } static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) { int retvalue; unsigned char databuf[1]; unsigned char ledstat; struct gpioled_dev *dev = filp->private_data; retvalue = copy_from_user(databuf, buf, cnt); if(retvalue < 0){ printk("kernel write failed!\r\n"); return -EFAULT; } ledstat = databuf[0]; if(ledstat == LEDON){ gpio_set_value(dev->led_gpio, 0); }else if(ledstat == LEDOFF){ gpio_set_value(dev->led_gpio, 1); } return 0; } static struct file_operations gpioled_fops = { .owner = THIS_MODULE, .open = led_open, .release = led_release, .write = led_write, .read = led_read, }; static int __init led_init(void) { int ret = 0; mutex_init(&gpioled.lock); gpioled.nd = of_find_node_by_path("/led"); if(gpioled.nd == NULL){ printk("gpioled node find failed!\r\n"); return -EINVAL; }else{ printk("gpioled node find success!\r\n"); } gpioled.led_gpio = of_get_named_gpio(gpioled.nd, "led-gpio", 0); if(gpioled.led_gpio < 0){ printk("can't get led-gpio\r\n"); return -EINVAL; } printk("led-gpio num = %d\r\n", gpioled.led_gpio); ret = gpio_direction_output(gpioled.led_gpio, 1); if(ret < 0){ printk("can't set gpio!\r\n"); } if(gpioled.major){ gpioled.devid = MKDEV(gpioled.major, 0); register_chrdev_region(gpioled.devid, GPIOLED_CNT, GPIOLED_NAME); }else{ alloc_chrdev_region(&gpioled.devid, 0, GPIOLED_CNT, GPIOLED_NAME); gpioled.major = MAJOR(gpioled.devid); gpioled.minor = MINOR(gpioled.devid); } printk("gpioled major = %d, minor = %d\r\n", gpioled.major, gpioled.minor); gpioled.cdev.owner = THIS_MODULE; cdev_init(&gpioled.cdev, &gpioled_fops); cdev_add(&gpioled.cdev, gpioled.devid, GPIOLED_CNT); gpioled.class = class_create(THIS_MODULE, GPIOLED_NAME); if(IS_ERR(gpioled.class)){ return PTR_ERR(gpioled.class); } gpioled.device = device_create(gpioled.class, NULL, gpioled.devid, NULL, GPIOLED_NAME); if(IS_ERR(gpioled.device)){ return PTR_ERR(gpioled.device); } return 0; } static void __exit led_exit(void) { cdev_del(&gpioled.cdev); unregister_chrdev_region(gpioled.devid, GPIOLED_CNT); device_destroy(gpioled.class, gpioled.devid); class_destroy(gpioled.class); } module_init(led_init); module_exit(led_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("warren");应用程序编写{alert type="info"}与原子锁一致{/alert}实验现象{alert type="info"}与信号量一致{/alert}{lamp/}完结 ::(狗头)
2024年11月02日
2 阅读
0 评论
1 点赞
2024-11-02
蜂鸣器实验
蜂鸣器实验是对pinctrl和gpio的复习。设备树修改添加pinctrl节点在设备树文件的iomuxc节点的imx6ul-evk子节点下创建一个pinctrl_beep子节点 pinctrl_beep: beepgrp{ fsl,pins = < MUX6ULL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x10B0 >; };添加beep节点在设备树文件的/节点下创建一个beep节点 beep :{ #address-cells = <1>; #size-cells = <1>; compatible = "warren-beep"; pinctrl-name = "default";/*添加pinctrl信息*/ pinctrl-0 = <&pinctrl_beep>; beep-gpio = <&gpio5 1 GPIO_ACTIVE_HIGHT>; /*添加GPIO属性信息*/ status = "okay"; };驱动程序编写#include "linux/types.h" #include "linux/kernel.h" #include "linux/delay.h" #include "linux/ide.h" #include "linux/init.h" #include "linux/module.h" #include "linux/errno.h" #include "linux/errno.h" #include "linux/gpio.h" #include "linux/cdev.h" #include "linux/device.h" #include "linux/of.h" #include "linux/of_address.h" #include "linux/of_gpio.h" #include "asm/mach/map.h" #include "asm/uaccess.h" #include "asm/io.h" #define BEEP_CNT 1 /* 设备号个数 */ #define BEEP_NAME "beep" /* 名字 */ #define BEEPOFF 0 /* 关蜂鸣器 */ #define BEEPON 1 /* 开蜂鸣器 */ struct beep_dev{ dev_t devid; /*设备号*/ struct cdev cdev; /*字符设备cdev*/ struct class *class; /*类*/ struct device *device; /*设备*/ int major; /*主设备号*/ int minor; /*次设备号*/ struct device_node *nd; /*设备节点*/ int beep_gpio; /*beep所使用的GPIO编号*/ }; struct beep_dev beep; static int beep_open(struct inode *inode, struct file *filp) { filp->private_data = &beep; return 0; } static ssize_t beep_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) { int retvalue; unsigned char databuf[4]; unsigned char beepstat; struct beep_dev *dev = filp->private_data; retvalue = copy_from_user(databuf, buf, cnt); if(retvalue < 0){ printk("kernel write failed!\r\n"); return -EFAULT; } beepstat = databuf[0]; if(beepstat == BEEPON){ gpio_set_value(dev->beep_gpio, 0); }else{ gpio_set_value(dev->beep_gpio, 1); } return 0; } static int beep_release(struct inode *inode, struct file *filp) { return 0; } static struct file_operations beep_fops = { .owner = THIS_MODULE, .write = beep_write, .open = beep_open, .release = beep_release, }; static int __init beep_init(void) { int ret = 0; /*1. 从设备数文件中获取beep节点信息*/ beep.nd = of_find_node_by_path("/beep"); if(beep.nd == NULL){ printk("beep node not find!\r\n"); return -EINVAL; }else{ printk("beep node find success!\r\n"); } /*根据beep节点信息来获取BEEP所使用的GPIO编号*/ beep.beep_gpio = of_get_named_gpio(beep.nd, "beep-gpio", 0); if(beep.beep_gpio < 0){ printk("can't get beep-gpio"); return -EINVAL; } printk("led-gpio num = %d\r\n", beep.beep_gpio); /*配置beep-gpio为输出高电平,默认关闭BEEP*/ ret = gpio_direction_output(beep.beep_gpio, 1); if(ret < 0){ printk("can't set beep gpio!\r\n"); } /*创建设备号*/ if(beep.major){ beep.devid = MKDEV(beep.major, 0); register_chrdev_region(beep.devid, BEEP_CNT, BEEP_NAME); }else{ alloc_chrdev_region(&beep.devid, 0, BEEP_CNT, BEEP_NAME); beep.major = MAJOR(beep.devid); beep.minor = MINOR(beep.devid); } printk("beep major=%d,minor=%d\r\n", beep.major, beep.minor); /*初始化cdev*/ beep.cdev.owner = THIS_MODULE; cdev_init(&beep.cdev, &beep_fops); /*添加cdev*/ cdev_add(&beep.cdev, beep.devid, BEEP_CNT); /*创建类*/ beep.class = class_create(THIS_MODULE, BEEP_NAME); if(IS_ERR(beep.class)){ return PTR_ERR(beep.class); } /*创建设备*/ beep.device = device_create(beep.class, NULL, beep.devid, NULL, BEEP_NAME); if(IS_ERR(beep.device)){ return PTR_ERR(beep.device); } return 0; } static void __exit beep_exit(void) { cdev_del(&beep.cdev); unregister_chrdev_region(beep.devid, BEEP_CNT); device_destroy(beep.class, beep.devid); class_destroy(beep.class); } module_init(beep_init); module_exit(beep_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("warren");测试程序编写#include "stdio.h" #include "unistd.h" #include "sys/types.h" #include "sys/stat.h" #include "fcntl.h" #include "stdlib.h" #include "string.h" int main(int argc, int *argv[]) { int fd = 0; int retvalue = 0; char *filename=NULL; unsigned char buff[4]; if(argc != 3){ printf("Error Usage!\r\n"); return -1; } filename = (char *)argv[1]; fd = open(filename, O_RDWR); if(fd < 0){ printf("file %s open failed!\r\n", filename); return -1; }else{ printf("file %s open success!\r\n", filename); } buff[0] = atoi((char *)argv[2]); retvalue = write(fd, buff, 1); if(retvalue < 0){ printf("beep control failed!\r\n"); } retvalue = close(fd); if(retvalue < 0){ printf("file close failed!\r\n"); return -1; } return 0; }实验现象
2024年11月02日
2 阅读
0 评论
0 点赞
2024-10-09
QEMU安装笔记
下载及构建QEMU9.1.01.获取源码wget https://download.qemu.org/qemu-9.1.0.tar.xz2.解压源码tar xvJf qemu-9.1.0.tar.xz3.进入到源码文件夹,并进行配置cd qemu-9.1.0./configure --enable-kvm --enable-debug此时会报一个错原因是虚拟机没有安装C编译器使用 sudo apt-get install gcc安装一个安装gcc后会报另外一个错。使用 sudo apt-get install python3-venv安装一个安装python后会报另外一个错。使用 sudo apt-get install ninja-build安装一个安装ninja后会报另外一个错。使用 sudo apt-get install bzip2安装一个安装bzip2后会报另外一个错。使用 sudo apt-get install pkg-config安装一个安装pkg-config后会报另外一个错。使用 sudo apt-get install libsdl2-dev安装一个安装libsdl2-dev后会报另外一个错。使用 sudo apt-get install git安装一个安装git后会报另外一个错。使用 sudo apt-get install flex安装一个安装flex后会报另外一个错。使用 sudo apt-get install bison安装一个配置流程到此结束。下来开始编译直接敲入make(sudo apt-get install make)编译完成后,使用sudo make install,将QEMU安装到系统中。安装好后,如图所示{lamp/}创建虚拟机镜像文件并通过 CDROM 安装 Ubuntu使用build目录下的qemu-img来完成构建//-f 使用参数 //qcow2: 镜像格式,这里使用 QEMU 最通用的格式 qcow2 //第二个参数为文件路径 //第三个参数为镜像大小 ./build/qemu-img create -f qcow2 test.qcow2 20G //格式化创建出来的这个磁盘镜像(下面命令不用敲) Formatting 'test.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=21474836480 lazy_refcounts=off refcount_bits=16然后使用命令来启动sudo ./build/qemu-system-x86_64 -m 2G -drive format=qcow2,file=test.qcow2 -enable-kvm -cdrom /home/warren/qemu/ubuntu_image/ubuntu-22.04.4-desktop-amd64.iso此时会报错,如图这是因为在vmware中没有启动虚拟化。将如下位置打勾即可然后就可以使用上述命令来启动虚拟机但是还是可以看到两个错误error: XDG_RUNTIME_DIR is invalid or not set in the environment.MESA: error: ZINK: failed to choose pdevglx: failed to create drisw screen这是因为没有图像界面相关环境,所以也导致了启动启动后只能使能命令行,不能使用图像界面。
2024年10月09日
4 阅读
0 评论
0 点赞
1
...
3
4
5
...
8