[태그:] kernel

  • Essential Linux Device Drivers

    Essential Linux Device Drivers

    isbn: 9788960771499

    한글판 제목이 너무 길어 원서 제목을 썼다. 임베디드 개발자면 쉽게 이해하겠지만 배경 지식이 없는 나에게는 너무 어렵다. 그럼에도 기록을 남겨, 나중에 어떤 책이 좋은지 다시 판단하는 시간을 줄이고, 다시 보려 한다.

    책 내용에 코드가 많은데 독자가 실행시킬 수 없어 어떻게 돌아가는지 알 수 없다. 커널을 설명한 부분도 있는데, 이미 알고 있다면 안 읽어도 될 듯 하다.

    작가 꿈이 큰지 usb, i2c, 캐릭터 디바이스, 심지어 그래픽 드라이버까지 설명했다. 나같이 취미로 생각하는 사람이 이런 기술을 알 필요는 없다. 5~10년 사이에 사라질 수 도 있다. 다 읽기는 어렵고, 지루하고, 쓸모없어 대략 다음 장 개념 정도만 보면 될 듯 하다. 코드는 최신 리눅스 커널을 보는게 맞다.

    • 문자 드라이버
    • 직력 드라이버
    • 입력 드라이버
    • usb
    • 네트웍 인터페이스 카드

    Linux Device Drivers(isbn: 9780596005900)를 읽고 난 후 다시 봐야겠다. 이 분야 원탑 이라는데 인터넷에서 무료로 구할 수 있다. 절판이고 하고.

  • xbox 360 드라이버 만지기1

    xbox 360 드라이버 만지기1

    내 라즈베리 파이에 usb 타입 xbox360 패드를 붙여 보고싶다. 리눅스 커널 xpad.c에 마이크로소프트 거의 모든 제품 usb vendor, product id가 등록되어 있다. xpad.c가 조금 복작하여 usb 인터럽트 사용 방법을 잘 이해할 수 없다. 키 입력 설정을 어떻게 할지는 나중 문제고… usb-skeletion.c 문서 역시 어렵다. 여기는 인터럽트 대신 대용량 데이터 전송을 목표로 했다.

    그 중 가장 비슷한 usb 마우스 드라이버를 커널에서 찾았다. 커널이 성경과 같아 모든 물음에 대한 답을 한다. 200줄 약간 넘어가는 코드로 정말 인터럽트 핵심만 작성했다.

    대략 구성은 아래와 같이 된다.

    • usb 구조체 선언.
    • 사용가능한 usb 번호 찾음, 등록.
    • 입력 설정.
    • 인터럽트 설정.

    usb_fill_int_urb로 call 함수를 등록하여 인터럽트를 사용하면 된다. usb 인터럽트가 일정 주기로 발생한다. 계속 실행하기 위해 인터럽트로 실행할 함수 안에 usb_submit_urb를 넣는다. 알고보면 참 쉬운데 처음 이해하기 어렵다. xpad.c도 같은 방식이다. 처음에 왜 안보였는지…아직 키 입력을 설정하지 않았고, 커널에 test를 출력하도록 했다.

    usb 구조체는 여러 정보를 쉽게 사용하려 군더더기를 많이 붙이는 듯 하다.

    #include <linux/kernel.h>
    #include <linux/input.h>
    #include <linux/module.h>
    #include <linux/usb/input.h>
    #include <linux/init.h>
    #include <linux/device.h>
    #include <linux/usb/input.h>
    #include <linux/slab.h>
    #define USB_XBOX_MINOR_BASE	1
    		
    //구조체 선언.
    struct usb_xpad{
    	struct input_dev *dev;		/* input device interface */
    	struct usb_device *udev;	/* usb device */
    	struct usb_interface *intf;	/* usb interface */
    	__u8    irq_in_endpointAddr;    /* interrupt in address*/
    	__u8    irq_out_endpointAddr;   /* interrupt out address*/
    	struct usb_endpoint_descriptor *endpoint_in, *endpoint_out;
    	signed char *data;		/* input data */
    	struct urb *irq_in;		/* urb for interrupt in report*/
    	struct work_struct work;	/* init/remove device from callback */
    };
    static struct usb_xpad *myPad;
    static int xpad_init_input(struct usb_xpad *xpad);
    static void xpad_deinit_input(struct usb_xpad *xpad);
    static void usb_xpad_irq(struct urb *urb){
    	pr_info("test\n");
    	usb_submit_urb(urb, GFP_KERNEL);
    }
    static int xpad_init_urb(struct usb_interface *intf, struct usb_xpad *xpad);
    static ssize_t xbox_read(struct file *file, char *buffer, size_t count,
    			 loff_t *ppos)
    {
    	pr_info("device was read.\n");
    	return 0;
    }
    static ssize_t xbox_write(struct file *file, const char *user_buffer,
    			  size_t count, loff_t *ppos)
    {
    	return 0;
    }
    static int xbox_open(struct inode *inode, struct file *file)
    {
    	int retval;
    	struct urb *ptr_urb;
    	ptr_urb = usb_alloc_urb(0, GFP_KERNEL);
    	pr_info("device was opened.\n");
    	if (!ptr_urb) {
    		retval = -ENOMEM;
    		goto error;
    	}
    	return 0;
    error:
    	if(ptr_urb)
    	{
    		usb_free_urb(ptr_urb);
    	}
    	return retval;
    }
    static int xbox_release(struct inode *inode, struct file *file)
    {
    	pr_info("xbox was released\n");
    	return 0;
    }
    static int xbox_flush(struct file *file, fl_owner_t id)
    {
    	return 0;
    }
    static const struct file_operations xboxtest_fops = {
    	.owner =	THIS_MODULE,
    	.read =		xbox_read,
    	.write =	xbox_write,
    	.open =		xbox_open,
    	.release =	xbox_release,
    	.flush =	xbox_flush,
    	.llseek =	noop_llseek,
    };
    /*
     * usb class driver info in order to get a minor number from the usb core,
     * and to have the device registered with the driver core
     */
    static struct usb_class_driver xbox_class = {
    	.name =		"xbox%d",
    	.fops =		&xboxtest_fops,
    	.minor_base =	USB_XBOX_MINOR_BASE,
    };
    static struct usb_driver xpad_test_driver;
    static const struct usb_device_id xpad_table[] = {
    	//{ USB_INTERFACE_INFO('X', 'B', 0) },	/* X-Box USB-IF not approved class */
    	//XPAD_XBOX360_VENDOR(0x045e),		/* Microsoft X-Box 360 controllers */
    	{USB_DEVICE(0x045e, 0x028e)},
    	{ }
    };
    static const signed short xpad_common_btn[] = {
    	BTN_A, BTN_B, BTN_X, BTN_Y,			/* "analog" buttons */
    	BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR,	/* start/back/sticks */
    	-1						/* terminating entry */
    };
    MODULE_DEVICE_TABLE(usb, xpad_table);
    static int xpad_init_input(struct usb_xpad *xpad)
    {
    	struct input_dev *input_dev;
    	int i, error;
    	int pipe, maxp;
    	input_dev = input_allocate_device();
    	if (!input_dev)
    		return -ENOMEM;
    	xpad->dev = input_dev;
    	usb_to_input_id(xpad->udev, &input_dev->id);
    	input_set_drvdata(input_dev, xpad);
    	/* set up standard buttons */
    	for (i = 0; xpad_common_btn[i] >= 0; i++)
    		input_set_capability(input_dev, EV_KEY, xpad_common_btn[i]);
    	pipe = usb_rcvintpipe(xpad->udev, xpad->irq_in_endpointAddr);
    	maxp = usb_maxpacket(xpad->udev, pipe, usb_pipeout(pipe));
    	usb_fill_int_urb(xpad->irq_in, xpad->udev,
    			pipe, xpad->data,
    			(maxp > 8 ? 8 : maxp),
    			usb_xpad_irq, xpad, 
    			xpad->endpoint_in->bInterval);
    	error = input_register_device(input_dev);
    	if (error)
    		goto err_free_dev;
    	pr_info("usb input was registered\n");
    	usb_submit_urb(xpad->irq_in, GFP_KERNEL);
    	return 0;	//return ok;
    err_free_dev:
    	input_free_device(input_dev);
    	return error;
    }
    static void xpad_deinit_input(struct usb_xpad *xpad)
    {
    	pr_info("xpad is %p, ->dev is %p.\n",xpad, xpad->dev);
    	if(xpad->dev)
    		input_unregister_device(xpad->dev);
    }
    static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id)
    {
    	struct usb_xpad *xpad;
    	struct usb_device *udev;
    	struct usb_endpoint_descriptor *ep_irq_in,*ep_irq_out;
    	struct usb_host_interface *intf_tmp;
    	int retval;
    	udev = interface_to_usbdev(intf);
    	xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL);
    	if (!xpad)
    		return -ENOMEM;
    	//초기화
    	//kzallocd으로 0으로 초기화
    	//xpad->odata_serial = 0;
    	xpad->udev = udev;
    	xpad->intf = intf;
    	myPad = xpad;
    	pr_info("xpad is %p, myPad is %p\n", xpad->intf, myPad->intf);
    	pr_info("interface is %p\n", intf);
    	//if (intf->cur_altsetting->desc.bNumEndpoints != 2)
    	//	return -ENODEV;
    	intf_tmp = intf->cur_altsetting;
    	// find common usb endpoint helper 사용
    	//https://lkml.org/lkml/2020/9/21/1239
    	
    	/* set up the endpoint information */
    	/* use only the first bulk-in and bulk-out endpoints */
    	retval = usb_find_common_endpoints(intf_tmp,
    			NULL, NULL, &ep_irq_in, &ep_irq_out);
    	if (retval) {
    		dev_err(&intf->dev,
    			"Could not find both irq-in and irq-out endpoints\n");
    		goto error;
    	}
    	xpad->irq_in_endpointAddr = ep_irq_in->bEndpointAddress;
    	xpad->irq_out_endpointAddr = ep_irq_out->bEndpointAddress;
    	xpad->endpoint_in = ep_irq_in;
    	xpad->endpoint_out = ep_irq_out;
    	xpad->irq_in = usb_alloc_urb(0, GFP_KERNEL);
    	if (!xpad->irq_in) {
    		retval = -ENOMEM;
    		goto err_free_in_urb;
    	}
    	usb_set_intfdata(intf, xpad);
    	pr_info("[info]: found interrupt end point, in: %d, out: %d", ep_irq_in->bEndpointAddress, ep_irq_out->bEndpointAddress);
    	pr_info("probe \n");
    	//pr_info("%04X:%04X pluged \n", id->idVendor, id->idProduct);
    	retval = usb_register_dev(intf, &xbox_class);
    	if (retval< 0) {
    		pr_err("usb_register failed for the "__FILE__ "driver."
    				"Error number %d", retval);
    		usb_set_intfdata(intf, NULL);
    		goto error;
    	}
    	/* let the user know what node this device is now attached to */
    	dev_info(&intf->dev,
    		 "USB Skeleton device now attached to USBSkel-%d",
    		 intf->minor);
    	//input으로 등록.
    	xpad_init_input(xpad);
    	
    	return 0;
    error:
    	kfree(xpad);
    	return retval;
    err_free_in_urb:
    	usb_free_urb(xpad->irq_in);
    	return retval;
    }
    static void xpad_disconnect(struct usb_interface *intf)
    {
    	struct usb_xpad *xpad;
    	xpad = usb_get_intfdata(intf);
    	pr_info("xpad address is %p\n", xpad);
    	xpad_deinit_input(xpad);
    	usb_deregister_dev(intf, &xbox_class);
    	usb_set_intfdata(intf, NULL);
    	kfree(xpad);
    	pr_info("disconnected\n");
    }
    static int xpad_suspend(struct usb_interface *intf, pm_message_t message)
    {
    	pr_info("suspendes\n");
    	return 0;
    }
    static int xpad_resume(struct usb_interface *intf)
    {
    	pr_info("resumed\n");
    	return 0;
    }
    static struct usb_driver xpad_test_driver = {
    	.name		= "xbox360_test",
    	.probe		= xpad_probe,
    	.disconnect	= xpad_disconnect,
    	.suspend	= xpad_suspend,
    	.resume		= xpad_resume,
    	.id_table	= xpad_table,
    };
    static int xpad_init_urb(struct usb_interface *intf, struct usb_xpad *xpad)
    {
    	int retval;
    	xpad->irq_in= usb_alloc_urb(0, GFP_KERNEL);
    	if (!xpad->irq_in) {
    		retval = -ENOMEM;
    		goto error;
    	}
    	return 0;
    error:
    	return retval;
    }
    	
    // 모듈 loading, unloading 테스트를 위해 과거 방식으로 사용
    //module_init(usb_xboxtest_init);
    //module_exit(usb_xboxtest_exit);
    //Macro
    module_usb_driver(xpad_test_driver);
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("now0930");
    MODULE_DESCRIPTION("Hello, xbox pad!");
    
    [45180.903315] xpad is ea6ce566, myPad is ea6ce566
    [45180.903332] interface is ea6ce566
    [45180.903349] [info]: found interrupt end point, in: 129, out: 1
    [45180.903360] probe 
    [45180.903636] xbox360_test 1-1.2:1.0: USB Skeleton device now attached to USBSkel-1
    [45180.903815] input: Unspecified device as /devices/virtual/input/input8
    [45180.904290] usb input was registered
    [45180.904475] xpad is 50c63d58, myPad is 50c63d58
    [45180.904489] interface is 50c63d58
    [45180.904506] [info]: found interrupt end point, in: 130, out: 2
    [45180.904518] probe 
    [45180.904685] xbox360_test 1-1.2:1.1: USB Skeleton device now attached to USBSkel-2
    [45180.904841] input: Unspecified device as /devices/virtual/input/input9
    [45180.905155] usb input was registered
    [45180.905310] xpad is 3bfd76ed, myPad is 3bfd76ed
    [45180.905323] interface is 3bfd76ed
    [45180.905342] xbox360_test 1-1.2:1.2: Could not find both irq-in and irq-out endpoints
    [45180.905432] xpad is 07d8d175, myPad is 07d8d175
    [45180.905451] interface is 07d8d175
    [45180.905469] xbox360_test 1-1.2:1.3: Could not find both irq-in and irq-out endpoints
    [45180.905585] usbcore: registered new interface driver xbox360_test
    [45180.909177] test
    [45180.913170] test
    [45210.971462] test
    [45210.984592] test
    [45210.997466] test
    [45211.010595] test
    [45211.075485] test
    [45211.088606] test
    [45211.109483] test
    [45211.130612] test
    [45211.151488] test
    [45211.168617] test
    [45211.181493] test
    [45211.754713] test
    [45211.799598] test
    [45211.812711] test
    [45212.329679] test
    [45217.545918] usbcore: deregistering interface driver xbox360_test
    [45217.546248] test
    [45217.546378] xpad address is 99d70f22
    [45217.546411] xpad is 99d70f22, ->dev is 8784f33d.
    [45217.699130] disconnected
    [45217.699578] test
    [45217.699674] xpad address is 0764c1af
    [45217.699692] xpad is 0764c1af, ->dev is 379dff77.
    [45217.779137] disconnected
  • 4장 process 로그 확인

    책 “디버깅을 통해.. 리눅스 커널” 148 페이지 예제를 실행했다. 잘 따라 해야 한다. trace 를 죽이고 살리는 과정에 오타로 살짝 헷갈렸다. 책은 /sys/kernel/debug/tracing/trace를 복사하는 script를 만들었다. 디버그 메세지를 보려면 이벤트 발생 후 바로 복사해야지, 타이핑한다고 늦게 하면 이전 기록을 시스템이 지워버린다. trace 파일을 지울 수 없다. 초기화 하려면 tracing_on에 0을 다시 써줘야 한다. 아래와 같은 기록을 뽑아 냈다. 다 적을 수 없어, 중요한 부분만 추출했다. 생각이 맞는지 모르겠다.

    5825  => sys_clone+0x18/0x3c
    5826  => ret_fast_syscall+0x0/0x28
    5827  => 0xbed826b0
    5828             bash-1921  [002] .... 32848.024289: _do_fork+0x14/0x41c <-sys_clone+0x34/0x3c
    5829             bash-1921  [002] .... 32848.024299: <stack trace>
    5830  => _do_fork+0x18/0x41c
    5831  => sys_clone+0x34/0x3c
    5832  => ret_fast_syscall+0x0/0x28
    5833  => 0xbed826b0
    5834           <idle>-0     [000] dns. 32848.024300: sched_wakeup: comm=kworker/u8:3 pid=2958 prio=120 target_cpu=000
    5835             bash-1921  [002] .... 32848.024301: copy_process.part.0+0x14/0x1ac4 <-_do_fork+0xc4/0x41c
    5836           <idle>-0     [000] d... 32848.024307: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u8:3 next_pid=2958 next_prio=120
    5837             bash-1921  [002] .... 32848.024310: <stack trace>
    5838  => copy_process.part.0+0x18/0x1ac4
    5839  => _do_fork+0xc4/0x41c
    5840  => sys_clone+0x34/0x3c
    5841  => ret_fast_syscall+0x0/0x28
    5842  => 0xbed826b0
    5843     kworker/u8:3-2958  [000] d... 32848.024324: sched_switch: prev_comm=kworker/u8:3 prev_pid=2958 prev_prio=120 prev_state=I ==> next_comm=swapper/0 next_pid=0 next_prio=120
    5844             bash-1921  [002] .... 32848.024940: sched_process_fork: comm=bash pid=1921 child_comm=bash child_pid=3043
    5845           <idle>-0     [003] d... 32848.024981: sched_switch: prev_comm=swapper/3 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=bash next_pid=3043 next_prio=120
    5846    raspbian_proc-3043  [003] d... 32848.025568: sched_switch: prev_comm=bash prev_pid=3043 prev_prio=120 prev_state=S ==> next_comm=swapper/3 next_pid=0 next_prio=120
    5847           <idle>-0     [003] dnh. 32848.025595: sched_wakeup: comm=bash pid=3043 prio=120 target_cpu=003
    5848           <idle>-0     [003] d... 32848.025608: sched_switch: prev_comm=swapper/3 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=bash next_pid=3043 next_prio=120
    5849             bash-1921  [002] d... 32848.025727: sched_switch: prev_comm=bash prev_pid=1921 prev_prio=120 prev_state=S ==> next_comm=swapper/2 next_pid=0 next_prio=120
    5850           <idle>-0     [000] dnh. 32848.026664: sched_wakeup: comm=irq/36-mmc1 pid=82 prio=49 target_cpu=000
    5851           <idle>-0     [000] d... 32848.026684: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=irq/36-mmc1 next_pid=82 next_prio=49
    5852      irq/36-mmc1-82    [000] d.s. 32848.026720: sched_wakeup: comm=irq/36-mmc1 pid=82 prio=49 target_cpu=000
    5853      irq/36-mmc1-82    [000] d.s. 32848.026763: sched_wakeup: comm=irq/36-mmc1 pid=82 prio=49 target_cpu=000
    5854      irq/36-mmc1-82    [000] d.s. 32848.026806: sched_wakeup: comm=irq/36-mmc1 pid=82 prio=49 target_cpu=000
    5855      irq/36-mmc1-82    [000] d... 32848.026823: sched_wakeup: comm=kworker/u8:3 pid=2958 prio=120 target_cpu=000
    5856      irq/36-mmc1-82    [000] d... 32848.026840: sched_switch: prev_comm=irq/36-mmc1 prev_pid=82 prev_prio=49 prev_state=S ==> next_comm=kworker/u8:3 next_pid=2958 next_prio=120
    5857     kworker/u8:3-2958  [000] d.s. 32848.026900: sched_wakeup: comm=kworker/u8:3 pid=2958 prio=120 target_cpu=000
    5858     kworker/u8:3-2958  [000] d.s. 32848.026946: sched_wakeup: comm=kworker/u8:3 pid=2958 prio=120 target_cpu=000
    ...
    8445     kworker/u8:0-2918  [001] d... 32866.110752: sched_switch: prev_comm=kworker/u8:0 prev_pid=2918 prev_prio=120 prev_state=I ==> next_comm=bash next_pid=3013 next_prio=120
    8446             bash-3013  [001] d... 32866.110848: signal_generate: sig=9 errno=0 code=0 comm=raspbian_proc pid=3043 grp=1 res=0
    8447           <idle>-0     [003] dnh. 32866.110856: sched_wakeup: comm=raspbian_proc pid=3043 prio=120 target_cpu=003
    8448           <idle>-0     [003] d... 32866.110870: sched_switch: prev_comm=swapper/3 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=raspbian_proc next_pid=3043 next_prio=120
    8449    raspbian_proc-3043  [003] d... 32866.110880: signal_deliver: sig=9 errno=0 code=0 sa_handler=0 sa_flags=0
    8450    raspbian_proc-3043  [003] .... 32866.110883: do_exit+0x14/0xbd4 <-do_group_exit+0x50/0xe8
    8451    raspbian_proc-3043  [003] .... 32866.110909: <stack trace>
    8452  => do_exit+0x18/0xbd4
    8453  => do_group_exit+0x50/0xe8
    8454  => get_signal+0x160/0x85c
    8455  => do_signal+0x360/0x4a4
    8456  => do_work_pending+0xd4/0xec
    8457  => slow_work_pending+0xc/0x20
    8458  => 0xb6e1969c
    8459    raspbian_proc-3043  [003] .... 32866.111230: sched_process_exit: comm=raspbian_proc pid=3043 prio=120
    8460    raspbian_proc-3043  [003] d... 32866.111296: signal_generate: sig=17 errno=0 code=2 comm=bash pid=1921 grp=1 res=0
    8461           <idle>-0     [002] dnh. 32866.111311: sched_wakeup: comm=bash pid=1921 prio=120 target_cpu=002
    8462             bash-3013  [001] dn.. 32866.111313: sched_wakeup: comm=kworker/u8:0 pid=2918 prio=120 target_cpu=001
    8463           <idle>-0     [002] d... 32866.111327: sched_switch: prev_comm=swapper/2 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=bash next_pid=1921 next_prio=120
    8464    raspbian_proc-3043  [003] d... 32866.111330: sched_switch: prev_comm=raspbian_proc prev_pid=3043 prev_prio=120 prev_state=Z ==> next_comm=kworker/u8:0 next_pid=2918 next_prio=120
    8465           <idle>-0     [000] dnh. 32866.111359: sched_wakeup: comm=sshd pid=3010 prio=120 target_cpu=000
    8466             bash-3013  [001] d... 32866.111362: sched_switch: prev_comm=bash prev_pid=3013 prev_prio=120 prev_state=S ==> next_comm=swapper/1 next_pid=0 next_prio=120
    8467     kworker/u8:0-2918  [003] d... 32866.111364: sched_switch: prev_comm=kworker/u8:0 prev_pid=2918 prev_prio=120 prev_state=I ==> next_comm=swapper/3 next_pid=0 next_prio=120
    8468           <idle>-0     [000] d... 32866.111374: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=sshd next_pid=3010 next_prio=120
    8469           <idle>-0     [003] dnh. 32866.111531: sched_wakeup: comm=kworker/u8:0 pid=2918 prio=120 target_cpu=003
    8470           <idle>-0     [003] d... 32866.111539: sched_switch: prev_comm=swapper/3 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u8:0 next_pid=2918 next_prio=120
    8471             sshd-3010  [000] d... 32866.111572: sched_switch: prev_comm=sshd prev_pid=3010 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
    
    • bash pid는 1921이다.
    • 5844행에서 child_pid 3043으로 자식 프로세스를 만들었다.
    • 5846행에서 raspbian_proce를 볼 수 있다.
    • 이 전에 5836행에서 다음 프로세스 id 2958을 가지고 거꾸로 sys_clone -> _do-fork -> copy_process를 실행했다.
    • 5836 행에서 next pid 2958(5857행)로 넘어가야 하는데 fork 하느라 다음 행을 실행했다.

    Linux process states

    As in every Unix flavour, in Linux a process can be in a number of states. It’s easiest to observe it in tools like ps or top: it’s usually in the column named S. The documentation of ps describes the possible values:

    PROCESS STATE CODES
       R  running or runnable (on run queue)
       D  uninterruptible sleep (usually IO)
       S  interruptible sleep (waiting for an event to complete)
       Z  defunct/zombie, terminated but not reaped by its parent
       T  stopped, either by a job control signal or because
          it is being traced
       [...]
    

    A process starts its life in an R “running” state and finishes after its parent reaps it from the Z “zombie” state.

    • 8449행에서 signo 9번을 받았다.
    • 시그널 9번을 받아 시그널 17 발생 시켰다.
    • slow_work_pending -> do_work_pending -> do_signal -> get_signal -> do_group_exit -> do_exit 순으로 실행한다.
  • raspberry pi4 커널 컴파일

    삼국지도 다 끝났고, 남는 시간에 리눅스 커널을 배워 보기로 했다. 시간 남을 땐 이게 효과가 확실하지. 전에 샀던 “디버깅을 통해 배우는 리눅스 커널의 구조와 원리”를 따라 해보기로 했다. 커널이 리눅스 심장과 같아 꼭 배울 필요는 없지만, 알면 편하게 살 수 있다. 리눅스 역시 과거 서버를 벗어나 arm에 로딩되어 여러 임베디드 리눅스로 사용되고 있다. 라즈베리 파이 역시 미친 가격으로 집에서 누구나 쉽게 구할 수 있다. 지금 IoT가 뜨고 있는데 안 배울 이유가 없다.

    책에 나온 커널이 버전 4.19다. 2021. 5월 업데이트를 하면 커널 5.10을 사용한다. 일단 커널을 4.19 버전으로 강제로 맞춰야 한다.

    pi@raspberrypi:~ $ uname -a
    Linux raspberrypi 5.10.17-v7l+ #1414 SMP Fri Apr 30 13:20:47 BST 2021 armv7l GNU/Linux

    책 53 페이지에 나온대로 따라했다. 15년전에 비하면 정말 편해졌다. 그 때 컴파일 옵션이 너무 많아 하드웨어 지식이 없어 무엇을 선택할 지 몰랐다.

    #https://www.raspberrypi.org/documentation/linux/kernel/building.md
    
    #필요 모듈 설치.
    sudo apt install git bc bison flex libssl-dev make
    
    git clone --depth=1 --branch rpi-4.19.y https://github.com/raspberrypi/linux
    
    cd linux
    #KERNEL=kernel7
    KERNEL=kernel7l
    #make bcm2709_defconfig
    make bcm2711_defconfig

    책은 make bcm2709_defconfig로 컴파일 옵션을 설정했다. 아무 생각없이 따라하다 보면 usb를 하나도 인식하지 못하는 현상을 겪는다.

    pi@raspberrypi:~ $ lsusb
    pi@raspberrypi:~ $

    이거 때문에 한동안 고민했다. make menu로 usb를 설정하는 옵션을 찾아 켜주면 될 듯 한데, 내가 많이 몰라 다른 옵션을 어떻게 설정할지 판단 못하겠다. 옵션 하나 켜겠다고 그 짓을 해야되나… usb가 막혀 키보드도 연결되지 않고, usb 메모리, 카메라 등 아무것도 연결되지 않았다. usb 4포트가 모두 불량인 줄 알고 환불할 뻔 했다.

    pi@raspberrypi:~ $ cat /proc/cpuinfo
    processor	: 0
    model name	: ARMv7 Processor rev 3 (v7l)
    BogoMIPS	: 270.00
    Features	: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32 
    CPU implementer	: 0x41
    CPU architecture: 7
    CPU variant	: 0x0
    CPU part	: 0xd08
    CPU revision	: 3
    
    processor	: 1
    model name	: ARMv7 Processor rev 3 (v7l)
    BogoMIPS	: 270.00
    Features	: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32 
    CPU implementer	: 0x41
    CPU architecture: 7
    CPU variant	: 0x0
    CPU part	: 0xd08
    CPU revision	: 3
    
    processor	: 2
    model name	: ARMv7 Processor rev 3 (v7l)
    BogoMIPS	: 270.00
    Features	: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32 
    CPU implementer	: 0x41
    CPU architecture: 7
    CPU variant	: 0x0
    CPU part	: 0xd08
    CPU revision	: 3
    
    processor	: 3
    model name	: ARMv7 Processor rev 3 (v7l)
    BogoMIPS	: 270.00
    Features	: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm crc32 
    CPU implementer	: 0x41
    CPU architecture: 7
    CPU variant	: 0x0
    CPU part	: 0xd08
    CPU revision	: 3
    
    Hardware	: BCM2711
    Revision	: b03114
    Serial		: 100000003d82cd51
    Model		: Raspberry Pi 4 Model B Rev 1.4
    

    책에 없지만, 웹 사이트와 여기 보드 정보를 보면 bcm2711을 사용했다. 이 옵션이 맞다. 이게 customized 제품과 대량 생산품 차이다. 이 옵션을 개인이 일일히 다 넣어주려면 힘들겠다. 표준화된 하드웨어를 사용함이 훨씬 낫다. 아무리 많이 판대도 raspberry pi 만큼 팔릴 수 있을 지 모르겠다. 단가에서 경쟁하기 어렵다고 본다.

    make -j4 zImage modules dtbs
    sudo make modules_install
    sudo cp arch/arm/boot/dts/*.dtb /boot/
    sudo cp arch/arm/boot/dts/overlays/*.dtb* /boot/overlays/
    sudo cp arch/arm/boot/dts/overlays/README /boot/overlays/
    sudo cp arch/arm/boot/zImage /boot/$KERNEL.img

    나머지를 실행한다. boot 디렉토리 파일을 덮어쓰기 전에 기존 파일을 꼭 백업해야 한다. 그냥 날려 버리면 나처럼 다시 이미지를 구워야 한다.

    pi@raspberrypi:~ $ lsusb
    Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
    Bus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub
    Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
    pi@raspberrypi:~ $ uname -a
    Linux raspberrypi 4.19.127-v7l+ #2 SMP Thu May 13 15:17:29 BST 2021 armv7l GNU/Linux

    1.5시간 컴파일 후 정상적으로 부팅했음을 확인했다.

    cross compile을 하기로 했다. 1.5 시간이 10분으로 줄어드는 마법을 보았다. https://www.raspberrypi.org/documentation/linux/kernel/building.md 사이트에 가면 cross compile 하는 방법이 나와 있다. 그대로 따라하면 된다.

    /boot 디렉토리 내용을 통째로 날렸는데, 그러면 안된다. start.elf 파일이 없다고 부팅되지 않는다.

    pi@raspberrypi:/boot $ ls -l
    total 27721
    -rwxr-xr-x 1 root root   24270 May 15  2021 bcm2708-rpi-b-plus.dtb
    -rwxr-xr-x 1 root root   24007 May 15  2021 bcm2708-rpi-b.dtb
    -rwxr-xr-x 1 root root   23788 May 15  2021 bcm2708-rpi-cm.dtb
    -rwxr-xr-x 1 root root   24448 May 15  2021 bcm2708-rpi-zero-w.dtb
    -rwxr-xr-x 1 root root   23712 May 15  2021 bcm2708-rpi-zero.dtb
    -rwxr-xr-x 1 root root   25334 May 15  2021 bcm2709-rpi-2-b.dtb
    -rwxr-xr-x 1 root root   25483 May 15  2021 bcm2710-rpi-2-b.dtb
    -rwxr-xr-x 1 root root   27143 May 15  2021 bcm2710-rpi-3-b-plus.dtb
    -rwxr-xr-x 1 root root   26524 May 15  2021 bcm2710-rpi-3-b.dtb
    -rwxr-xr-x 1 root root   25338 May 15  2021 bcm2710-rpi-cm3.dtb
    -rwxr-xr-x 1 root root   41185 May 15  2021 bcm2711-rpi-4-b.dtb
    -rwxr-xr-x 1 root root   18695 May 15  2021 bcm2835-rpi-a-plus.dtb
    -rwxr-xr-x 1 root root   18579 May 15  2021 bcm2835-rpi-a.dtb
    -rwxr-xr-x 1 root root   18982 May 15  2021 bcm2835-rpi-b-plus.dtb
    -rwxr-xr-x 1 root root   18858 May 15  2021 bcm2835-rpi-b-rev2.dtb
    -rwxr-xr-x 1 root root   18725 May 15  2021 bcm2835-rpi-b.dtb
    -rwxr-xr-x 1 root root   18690 May 15  2021 bcm2835-rpi-cm1-io1.dtb
    -rwxr-xr-x 1 root root   19173 May 15  2021 bcm2835-rpi-zero-w.dtb
    -rwxr-xr-x 1 root root   18647 May 15  2021 bcm2835-rpi-zero.dtb
    -rwxr-xr-x 1 root root   19558 May 15  2021 bcm2836-rpi-2-b.dtb
    -rwxr-xr-x 1 root root   21027 May 15  2021 bcm2837-rpi-3-b-plus.dtb
    -rwxr-xr-x 1 root root   20238 May 15  2021 bcm2837-rpi-3-b.dtb
    -rwxr-xr-x 1 root root   52456 May 15  2021 bootcode.bin
    -rwxr-xr-x 1 root root     121 May 15  2021 cmdline.txt
    -rwxr-xr-x 1 root root    1809 May 15  2021 config.txt
    -rwxr-xr-x 1 root root    7314 May 15  2021 fixup.dat
    -rwxr-xr-x 1 root root    5446 May 15  2021 fixup4.dat
    -rwxr-xr-x 1 root root    3191 May 15  2021 fixup4cd.dat
    -rwxr-xr-x 1 root root    8454 May 15  2021 fixup4db.dat
    -rwxr-xr-x 1 root root    8452 May 15  2021 fixup4x.dat
    -rwxr-xr-x 1 root root    3191 May 15  2021 fixup_cd.dat
    -rwxr-xr-x 1 root root   10298 May 15  2021 fixup_db.dat
    -rwxr-xr-x 1 root root   10298 May 15  2021 fixup_x.dat
    -rwxr-xr-x 1 root root     145 May 15  2021 issue.txt
    -rwxr-xr-x 1 root root 5773448 May 15  2021 kernel7l.img
    drwxr-xr-x 2 root root   16384 May 15  2021 overlays
    -rwxr-xr-x 1 root root 2952928 May 15  2021 start.elf
    -rwxr-xr-x 1 root root 2228768 May 15  2021 start4.elf
    -rwxr-xr-x 1 root root  793084 May 15  2021 start4cd.elf
    -rwxr-xr-x 1 root root 3722504 May 15  2021 start4db.elf
    -rwxr-xr-x 1 root root 2981160 May 15  2021 start4x.elf
    -rwxr-xr-x 1 root root  793084 May 15  2021 start_cd.elf
    -rwxr-xr-x 1 root root 4794472 May 15  2021 start_db.elf
    -rwxr-xr-x 1 root root 3704712 May 15  2021 start_x.elf
    

    overlays 내용을 날리고, 새로 컴파일 버전으로 설치했고, start.elf, *.dat, bootcode.bin, *.txt를 전에 받았던 백업에서 복사했다. 다행히 잘 된다. 두 번은 하지만, 세 번은 못 하겠다. 책이 왜 스크립트를 설명했는지 이해된다.