2018年01月26日 情報科学類 オペレーティングシステム II 筑波大学 システム情報系 新城 靖 <yas@cs.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~yas/coins/os2-2017/2018-01-26
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~yas/
http://www.cs.tsukuba.ac.jp/~yas/
/dev
以下のファイルをアクセスする。
$ df /
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda2 232431456 13088380 207345736 6% /
$ ls -l /dev/sda2
brw-r----- 1 root disk 8, 2 Jan 24 12:00 /dev/sda2
$
ls -l で見ると、ブロック型は、b
、文字型は、c
で始まる。メ
ジャー番号は、デバイスの種類、マイナー番号は、同じ種類で、細かい違い
(上の例では、パーティション)等を意味する。
メジャー番号は、静的に決めうちにすることもあるが、
alloc_chrdev_region() を呼び、動的に割り当てられることもできる。
使われているメジャー番号は、/proc/devices
に現れる。
/dev/ の下にあるブロック型と文字型のファイルは、mknod コマンド (make
node) で作ることができる。
# mknod b /dev/ファイル名 メジャー番号 マイナー番号
# mknod c /dev/ファイル名 メジャー番号 マイナー番号
最近の
Linux では、起動時に自動的に mknod が行われるので、手で mknod コマンド
を打つ必要性はあまりない。
struct file_operations my_fops = { .... }; struct cdev *my_cdevp = cdev_alloc(); my_cdev->ops = &my_fops; my_cdev->owner = &my_fops;
struct file_operations my_fops = { .... }; struct cdev my_cdev ; cdev_init(&my_cdev,&my_fops); cdev_add(&my_cdev,num, count)register_chrdev() という関数で登録することもできる。以前はこの方法が主。
int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);
linux-4.14.12/include/linux/fs.h 1692: struct file_operations { 1693: struct module *owner; 1694: loff_t (*llseek) (struct file *, loff_t, int); 1695: ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); 1696: ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); 1697: ssize_t (*read_iter) (struct kiocb *, struct iov_iter *); 1698: ssize_t (*write_iter) (struct kiocb *, struct iov_iter *); 1699: int (*iterate) (struct file *, struct dir_context *); 1700: int (*iterate_shared) (struct file *, struct dir_context *); 1701: unsigned int (*poll) (struct file *, struct poll_table_struct *); 1702: long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); 1703: long (*compat_ioctl) (struct file *, unsigned int, unsigned long); 1704: int (*mmap) (struct file *, struct vm_area_struct *); 1705: int (*open) (struct inode *, struct file *); 1706: int (*flush) (struct file *, fl_owner_t id); 1707: int (*release) (struct inode *, struct file *); 1708: int (*fsync) (struct file *, loff_t, loff_t, int datasync); 1709: int (*fasync) (int, struct file *, int); 1710: int (*lock) (struct file *, int, struct file_lock *); 1711: ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); 1712: unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); 1713: int (*check_flags)(int); 1714: int (*flock) (struct file *, int, struct file_lock *); 1715: ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); 1716: ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); 1717: int (*setlease)(struct file *, long, struct file_lock **, void **); 1718: long (*fallocate)(struct file *file, int mode, loff_t offset, 1719: loff_t len); 1720: void (*show_fdinfo)(struct seq_file *m, struct file *f); 1721: #ifndef CONFIG_MMU 1722: unsigned (*mmap_capabilities)(struct file *); 1723: #endif 1724: ssize_t (*copy_file_range)(struct file *, loff_t, struct file *, 1725: loff_t, size_t, unsigned int); 1726: int (*clone_file_range)(struct file *, loff_t, struct file *, loff_t, 1727: u64); 1728: ssize_t (*dedupe_file_range)(struct file *, u64, u64, struct file *, 1729: u64); 1730: } __randomize_layout;主な手続きの意味
デバイス・ファイルでは、open() 等で自分のメジャー番号とマイナー番号を取 り出すために使われることがある。
int fd1 = open("file1"); int fd2 = open("file1");ファイル名 "file1" で表現されるファイルの inode 構造体は、1 個でも、 file 構造体は、2 個割り当てられる。
例
int ioctl(int d, int request, ...);
# date
Wed Jan 24 15:21:51 JST 2018
# hwclock --show
Wed Jan 24 15:21:54 2018 -0.391294 seconds
#
1: 2: /* 3: ~yas/syspro/time/rtc-read-time.c -- Read CMOS Realtime Clock in Linux 4: Created on: 2011/01/28 17:12:36 5: */ 6: 7: 8: #include <sys/types.h> /* open() */ 9: #include <sys/stat.h> /* open() */ 10: #include <fcntl.h> /* open() */ 11: #include <sys/ioctl.h> /* ioctl() */ 12: #include <unistd.h> /* close() */ 13: #include <stdio.h> /* printf() */ 14: #include <stdlib.h> /* exit() */ 15: #include <linux/rtc.h> /* RTC_RD_TIME */ 16: 17: #define RTC_DEVICE_FILE "/dev/rtc" 18: 19: main() 20: { 21: int fd; 22: struct rtc_time t1 ; 23: if( (fd = open( RTC_DEVICE_FILE, O_RDONLY ))< 0 ) 24: { 25: perror("open"); 26: exit( 1 ); 27: } 28: if( ioctl( fd, RTC_RD_TIME, &t1 ) < 0 ) 29: { 30: perror("ioctl(RTC_RD_TIME)"); 31: exit( 2 ); 32: } 33: printf("%04d-%02d-%02d %02d:%02d:%02d\n", 34: t1.tm_year+1900, t1.tm_mon+1, t1.tm_mday, 35: t1.tm_hour, t1.tm_min, t1.tm_sec ); 36: close( fd ); 37: }
$ ls -l /dev/rtc
crw-r--r-- 1 root root 10, 135 Oct 29 18:22 /dev/rtc
$
$ make rtc-read-time
cc rtc-read-time.c -o rtc-read-time
$ su
Password:
# ./rtc-read-time
2018-01-24 15:24:39
# ./rtc-read-time ; hwclock --show; date
2018-01-24 15:24:41
Wed Jan 24 15:24:42 2018 -0.938181 seconds
Wed Jan 24 15:24:41 JST 2018
# ./rtc-read-time ; hwclock --show; date
2018-01-24 15:24:47
Wed Jan 24 15:24:48 2018 -0.047507 seconds
Wed Jan 24 15:24:47 JST 2018
#
RTC_RD_TIME を含めて、/dev/rtc に対する ioctl() では、次のようなコマン
ドが使える。詳しくは、man rtc を参照。
コマンド | 説明 |
---|---|
RTC_RD_TIME | RTCのTODを読む(read) |
RTC_SET_TIME | RTCのTODに値をセットする |
RTC_ALM_READ,RTC_ALM_SET | RTCのalarmを読む/セットする |
RTC_IRQP_READ | alarmによる定期的な割り込みの(periodic interrupt)の周波数を読む/セットする |
RTC_AIE_ON, RTC_AIE_OFF | alarmの割り込みを許可する/禁止する |
RTC_UIE_ON, RTC_UIE_OFF | clockの更新後との割り込みを許可する/禁止する |
RTC_PIE_ON, RTC_PIE_OFF | 定期的な割り込みを許可する/禁止する |
RTC_EPOCH_READ, RTC_EPOCH_SET | RTCのepoch (起点となる年月日) を読む/書く |
linux-4.14.12/drivers/char/rtc.c 899: static const struct file_operations rtc_fops = { 900: .owner = THIS_MODULE, 901: .llseek = no_llseek, 902: .read = rtc_read, 903: #ifdef RTC_IRQ 904: .poll = rtc_poll, 905: #endif 906: .unlocked_ioctl = rtc_ioctl, 907: .open = rtc_open, 908: .release = rtc_release, 909: .fasync = rtc_fasync, 910: }; 911: 912: static struct miscdevice rtc_dev = { 913: .minor = RTC_MINOR, 914: .name = "rtc", 915: .fops = &rtc_fops, 916: }; 953: static int __init rtc_init(void) 954: { ... 1057: if (misc_register(&rtc_dev)) { ... 1064: return -ENODEV; 1065: } ... 1131: (void) init_sysctl(); 1132: 1133: printk(KERN_INFO "Real Time Clock Driver v" RTC_VERSION "\n"); 1134: 1135: return 0; 1136: } linux-4.14.12/include/uapi/linux/major.h 10: #define UNNAMED_MAJOR 0 11: #define MEM_MAJOR 1 12: #define RAMDISK_MAJOR 1 13: #define FLOPPY_MAJOR 2 14: #define PTY_MASTER_MAJOR 2 15: #define IDE0_MAJOR 3 16: #define HD_MAJOR IDE0_MAJOR 17: #define PTY_SLAVE_MAJOR 3 18: #define TTY_MAJOR 4 19: #define TTYAUX_MAJOR 5 20: #define LP_MAJOR 6 21: #define VCS_MAJOR 7 22: #define LOOP_MAJOR 7 23: #define SCSI_DISK0_MAJOR 8 24: #define SCSI_TAPE_MAJOR 9 25: #define MD_MAJOR 9 26: #define MISC_MAJOR 10 ... linux-4.14.12/include/linux/miscdevice.h 15: #define PSMOUSE_MINOR 1 16: #define MS_BUSMOUSE_MINOR 2 /* unused */ ... 27: #define RTC_MINOR 135 ... 58: #define VHOST_VSOCK_MINOR 241 59: #define MISC_DYNAMIC_MINOR 255
$ dmesg | grep Real
Real Time Clock Driver v1.12ac
$
dmesg コマンドの古いものは、(syslogd の働きで) /var/log/messages* 等の
ファイルに保存される。
# grep Real /var/log/messages.2
...
Jan 24 12:00:40 windell50 kernel: Real Time Clock Driver v1.12ac
#
2018年
coins で動いている Linux では、別のドライバが動いている。
ソースは、drivers/rtc/rtc-cmos.c にある。
$ date
2018年 1月 24日 水曜日 15:26:44 JST
$ dmesg | grep Real
$ dmesg | grep cmos
rtc_cmos 00:06: RTC can wake from S4
rtc_cmos 00:06: rtc core: registered rtc_cmos as rtc0
rtc_cmos 00:06: setting system clock to 2018-01-22 15:11:37 UTC (1516633897)
$
linux-4.14.12/drivers/char/rtc.c 191: static unsigned long rtc_status; /* bitmapped status byte. */ 730: static int rtc_open(struct inode *inode, struct file *file) 731: { 732: spin_lock_irq(&rtc_lock); 733: 734: if (rtc_status & RTC_IS_OPEN) 735: goto out_busy; 736: 737: rtc_status |= RTC_IS_OPEN; ... 740: spin_unlock_irq(&rtc_lock); 741: return 0; 742: 743: out_busy: 744: spin_unlock_irq(&rtc_lock); 745: return -EBUSY; 746: }
linux-4.14.12/drivers/char/rtc.c 753: static int rtc_release(struct inode *inode, struct file *file) 754: { ... 784: spin_lock_irq(&rtc_lock); ... 786: rtc_status &= ~RTC_IS_OPEN; 787: spin_unlock_irq(&rtc_lock); 788: 789: return 0; 790: }rtc_open() で立てた rtc_status の RTC_IS_OPEN ビットは、close() システ ム・コールで呼ばれる rtc_release() ( struct file_operations rtc_fops の .release) で、落とされる。
linux-4.14.12/drivers/char/rtc.c 718: static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 719: { 720: long ret; 721: ret = rtc_do_ioctl(cmd, arg, 0); 722: return ret; 723: } 398: static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) 399: { 400: struct rtc_time wtime; ... 418: switch (cmd) { ... 480: case RTC_ALM_READ: /* Read the present alarm time */ ... 491: case RTC_ALM_SET: /* Store a time into the alarm */ ... 540: case RTC_RD_TIME: /* Read the time/date from RTC */ 541: { 542: memset(&wtime, 0, sizeof(struct rtc_time)); 543: rtc_get_rtc_time(&wtime); 544: break; 545: } 546: case RTC_SET_TIME: /* Set the RTC */ 547: { 548: struct rtc_time rtc_tm; 549: unsigned char mon, day, hrs, min, sec, leap_yr; 550: unsigned char save_control, save_freq_select; 551: unsigned int yrs; ... 559: if (copy_from_user(&rtc_tm, (struct rtc_time __user *)arg, 560: sizeof(struct rtc_time))) 561: return -EFAULT; 562: 563: yrs = rtc_tm.tm_year + 1900; 564: mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ 565: day = rtc_tm.tm_mday; 566: hrs = rtc_tm.tm_hour; 567: min = rtc_tm.tm_min; 568: sec = rtc_tm.tm_sec; ... 569: 570: if (yrs < 1970) 571: return -EINVAL; 572: 573: leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); 574: 575: if ((mon > 12) || (day == 0)) 576: return -EINVAL; 577: 578: if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) 579: return -EINVAL; 580: 581: if ((hrs >= 24) || (min >= 60) || (sec >= 60)) 582: return -EINVAL; 583: 584: yrs -= epoch; 585: if (yrs > 255) /* They are unsigned */ 586: return -EINVAL; 587: 588: spin_lock_irq(&rtc_lock); ... 631: CMOS_WRITE(yrs, RTC_YEAR); 632: CMOS_WRITE(mon, RTC_MONTH); 633: CMOS_WRITE(day, RTC_DAY_OF_MONTH); 634: CMOS_WRITE(hrs, RTC_HOURS); 635: CMOS_WRITE(min, RTC_MINUTES); 636: CMOS_WRITE(sec, RTC_SECONDS); ... 641: spin_unlock_irq(&rtc_lock); 642: return 0; 643: } ... 711: default: 712: return -ENOTTY; 713: } 714: return copy_to_user((void __user *)arg, 715: &wtime, sizeof wtime) ? -EFAULT : 0; 716: }
カーネル空間とユーザ空間でデータをコピーする時には、次のような特殊な関 数を使う必要がある。
unsigned long copy_to_user(void __user *to, const void *from, unsigned long n)
unsigned long copy_from_user(void *to, const void __user *from, unsigned long n)
これらの関数は、コピーの途中でページフォールトが発生した時にもうまくコ ピーできる(ページインの処理でプロセスがスリープすることがある)。また、 引数の番地が有効かどうかをチェックする。
Linux x86 アーキテクチャでは、カーネル空間とユーザ空間が一部重なってい ることがある。この場合、カーネルでmemcpy() を使ったり、直接ポインタを操 作してもユーザ空間がアクセスできてしまうが、それは誤りである。
linux-4.14.12/drivers/char/rtc.c 1294: static void rtc_get_rtc_time(struct rtc_time *rtc_tm) 1295: { 1296: unsigned long uip_watchdog = jiffies, flags; ... 1322: spin_lock_irqsave(&rtc_lock, flags); 1323: rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); 1324: rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); 1325: rtc_tm->tm_hour = CMOS_READ(RTC_HOURS); 1326: rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); 1327: rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); 1328: rtc_tm->tm_year = CMOS_READ(RTC_YEAR); 1329: /* Only set from 2.6.16 onwards */ 1330: rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK); ... 1336: spin_unlock_irqrestore(&rtc_lock, flags); ... 1356: rtc_tm->tm_year += epoch - 1900; 1357: if (rtc_tm->tm_year <= 69) 1358: rtc_tm->tm_year += 100; 1359: 1360: rtc_tm->tm_mon--; 1361: }
void outb(unsigned char value, unsigned short port) ポート番号 port に 1 バイトの value を出力する unsigned char inb(unsigned short port) ポート番号 port から 1 バイトの value を入力してその値を返す1 バイト 8 ビットではなくて 2 バイト 16 ビット 単位のもの (inw(), outw()) や4 バイト 32 ビット単位のもの( inl(), outl() ) もある。
linux-4.14.12/arch/x86/include/asm/mc146818rtc.h 12: #define RTC_PORT(x) (0x70 + (x)) ... 93: #define CMOS_READ(addr) rtc_cmos_read(addr) 94: #define CMOS_WRITE(val, addr) rtc_cmos_write(val, addr) linux-4.14.12/arch/x86/kernel/rtc.c 126: unsigned char rtc_cmos_read(unsigned char addr) 127: { 128: unsigned char val; 129: 130: lock_cmos_prefix(addr); 131: outb(addr, RTC_PORT(0)); 132: val = inb(RTC_PORT(1)); 133: lock_cmos_suffix(addr); 134: 135: return val; 136: } ... 139: void rtc_cmos_write(unsigned char val, unsigned char addr) 140: { 141: lock_cmos_prefix(addr); 142: outb(addr, RTC_PORT(0)); 143: outb(val, RTC_PORT(1)); 144: lock_cmos_suffix(addr); 145: } linux-4.14.12/include/linux/mc146818rtc.h 50: #define RTC_SECONDS 0 51: #define RTC_SECONDS_ALARM 1 52: #define RTC_MINUTES 2 53: #define RTC_MINUTES_ALARM 3 54: #define RTC_HOURS 4 55: #define RTC_HOURS_ALARM 5 ... 59: #define RTC_DAY_OF_WEEK 6 60: #define RTC_DAY_OF_MONTH 7 61: #define RTC_MONTH 8 62: #define RTC_YEAR 9 ... 66: #define RTC_REG_A 10 67: #define RTC_REG_B 11 68: #define RTC_REG_C 12 ... 104: #define RTC_INTR_FLAGS RTC_REG_C
linux-4.14.12/arch/x86/boot/boot.h 43: static inline void outb(u8 v, u16 port) 44: { 45: asm volatile("outb %0,%1" : : "a" (v), "dN" (port)); 46: } 47: static inline u8 inb(u16 port) 48: { 49: u8 v; 50: asm volatile("inb %1,%0" : "=a" (v) : "dN" (port)); 51: return v; 52: }
asm ( "アセンブラの命令列" : 出力オペランド(省略可) : 入力オペランド(省略可) : 破壊するレジスタ(省略可) )
"制約"(Cの値)
=
があると、書き込み専用になる。
linux-4.14.12/arch/x86/include/asm/io.h 269: #define BUILDIO(bwl, bw, type) \ 270: static inline void out##bwl(unsigned type value, int port) \ 271: { \ 272: asm volatile("out" #bwl " %" #bw "0, %w1" \ 273: : : "a"(value), "Nd"(port)); \ 274: } \ 275: \ 276: static inline unsigned type in##bwl(int port) \ 277: { \ 278: unsigned type value; \ 279: asm volatile("in" #bwl " %w1, %" #bw "0" \ 280: : "=a"(value) : "Nd"(port)); \ 281: return value; \ 282: } \ ... 309: BUILDIO(b, b, char) 310: BUILDIO(w, w, short) 311: BUILDIO(l, , int)
id1##id2
」 は、
識別子(関数名、変数名等)の結合を意味する。
たとえば、マクロ定義の引数 bwl
が値 b
を持っていれば、out##bwl
は、outb
となる。
(「#
」がなければ、「out bwl
」 は、「out b
」と間に空白が残る)。
#var
」 は、文字列化。
たとえば、マクロ定義の引数 bwl が値 b を持っていれば、#bwl は、"b" となる。
(「#」がなければ、bwl は、b )。
static inline unsigned char inb(int port) { unsigned char value; asm volatile("inb %w1, %b0" : "=a"(value) : "Nd"(port)); return value; } static inline void outb(unsigned char value, int port) { asm volatile("outb %b0, %w1" : : "a"(value), "Nd"(port)); }
$ cat /proc/ioports
0000-001f : dma1
0020-0021 : pic1
0040-0043 : timer0
0050-0053 : timer1
0060-0060 : keyboard
0064-0064 : keyboard
0070-0077 : rtc
0080-008f : dma page reg
...
ff80-ff9f : 0000:00:1d.0
ff80-ff9f : uhci_hcd
$
図? x86 の Intel 8259
図? x86 の APIC
例:
例:
図? 割り込み記述子テーブルと割り込みハンドラ
typedef void (*funcp_t)(void); funcp_t idt[256];
old_pc = pc; old_flags = flags;
n = 割り込みベクタ; handler = idt[n];
push old_pc; push old_flags; pc = handler; // (*handler)();ただし、単純な call 命令とは違い、スタック上にプログラムカウンタの他に、 プロセッサの状態を示すフラグ等も積む。
図? PICの線が不足した時の対応
include/linux/interrupt.h typedef irqreturn_t (*irq_handler_t)(int, void *); request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev)
void free_irq(unsigned int, void *dev)
irqreturn_t handler(int irq, void *dev)
$ cat /proc/interrupts
CPU0 CPU1
0: 4208761 38584 IO-APIC-edge timer
1: 0 3 IO-APIC-edge i8042
7: 0 0 IO-APIC-edge parport0
8: 1 2 IO-APIC-edge rtc
9: 0 0 IO-APIC-level acpi
12: 3 1 IO-APIC-edge i8042
50: 5380 86508 PCI-MSI ahci
74: 346 0 PCI-MSI HDA Intel
98: 294 28232 PCI-MSI eth1
169: 130 57006 IO-APIC-level uhci_hcd:usb3
177: 0 0 IO-APIC-level uhci_hcd:usb4, uhci_hcd:usb7
217: 358 149530 IO-APIC-level ehci_hcd:usb1, uhci_hcd:usb5
225: 0 0 IO-APIC-level ehci_hcd:usb2, uhci_hcd:usb6
233: 0 0 IO-APIC-level uhci_hcd:usb8
NMI: 0 0
LOC: 4246864 4246863
ERR: 0
MIS: 0
$
linux-4.14.12/include/linux/rtc.h 91: typedef struct rtc_task { 92: void (*func)(void *private_data); 93: void *private_data; 94: } rtc_task_t; linux-4.14.12/drivers/char/rtc.c 96: static unsigned long rtc_port; 97: static int rtc_irq; ... 191: static unsigned long rtc_status; /* bitmapped status byte. */ 192: static unsigned long rtc_freq; /* Current periodic IRQ rate */ 193: static unsigned long rtc_irq_data; /* our output to the world */ ... 200: static DEFINE_SPINLOCK(rtc_task_lock); 201: static rtc_task_t *rtc_callback; ... 953: static int __init rtc_init(void) 954: { ... 1000: if (request_irq(rtc_irq, rtc_interrupt, IRQF_SHARED, "rtc", 1001: (void *)&rtc_port)) { 1002: rtc_has_irq = 0; 1003: printk(KERN_ERR "rtc: cannot register IRQ %d\n", rtc_irq); 1004: return -EIO; 1005: } ... 1136: } 239: static irqreturn_t rtc_interrupt(int irq, void *dev_id) 240: { ... 248: spin_lock(&rtc_lock); 249: rtc_irq_data += 0x100; 250: rtc_irq_data &= ~0xff; ... 259: rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); ... 265: spin_unlock(&rtc_lock); ... 268: spin_lock(&rtc_task_lock); 269: if (rtc_callback) 270: rtc_callback->func(rtc_callback->private_data); 271: spin_unlock(&rtc_task_lock); ... 276: return IRQ_HANDLED; 277: }
linux-4.14.12/arch/x86/kernel/traps.c 942: void __init trap_init(void) 943: { 947: idt_setup_traps(); ... 968: } linux-4.14.12/arch/x86/include/asm/irq_vectors.h 50: #define IA32_SYSCALL_VECTOR 0x80 ... 112: #define NR_VECTORS 256 linux-4.14.12/arch/x86/kernel/idt.c 168: gate_desc idt_table[IDT_ENTRIES] __page_aligned_bss; 73: static const __initdata struct idt_data def_idts[] = { 74: INTG(X86_TRAP_DE, divide_error), 75: INTG(X86_TRAP_NMI, nmi), ... 104: SYSG(IA32_SYSCALL_VECTOR, entry_INT80_32), ... 106: }; 263: void __init idt_setup_traps(void) 264: { 265: idt_setup_from_table(idt_table, def_idts, ARRAY_SIZE(def_idts), true); 266: } linux-4.14.12/arch/x86/entry/entry_32.S 770: ENTRY(divide_error) 771: ASM_CLAC 772: pushl $0 # no error code 773: pushl $do_divide_error 774: jmp common_exception ... 971: ENTRY(nmi) 972: ASM_CLAC ... 995: call do_nmi ... 520: ENTRY(entry_INT80_32) ... 532: call do_int80_syscall_32 ... 556: INTERRUPT_RETURN linux-4.14.12/arch/x86/include/asm/irqflags.h 149: #define INTERRUPT_RETURN iret linux-4.14.12/arch/x86/entry/common.c 338: /* Handles int $0x80 */ 339: __visible void do_int80_syscall_32(struct pt_regs *regs) 340: { ... 343: do_syscall_32_irqs_on(regs); 344: } 303: static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs) 304: { ... 306: unsigned int nr = (unsigned int)regs->orig_ax; ... 322: if (likely(nr < IA32_NR_syscalls)) { ... 329: regs->ax = ia32_sys_call_table[nr]( 330: (unsigned int)regs->bx, (unsigned int)regs->cx, 331: (unsigned int)regs->dx, (unsigned int)regs->si, 332: (unsigned int)regs->di, (unsigned int)regs->bp); 333: } ... 336: } linux-4.14.12/arch/x86/include/asm/syscall.h 29: #define ia32_sys_call_table sys_call_table
引数には、x86 のレジスタを表現した構造体へのポインタが渡される。これに より、割り込みが発生した時のレジスタの値がわかる。割り込みハンドラが有 効で、割り込み番号に登録されていれば、最終的には、handle_IRQ_event() と いう、CPU とは独立の割り込みハンドラが呼ばれる。
linux-4.14.12/kernel/irq/handle.c 196: irqreturn_t handle_irq_event(struct irq_desc *desc) 197: { 198: irqreturn_t ret; ... 204: ret = handle_irq_event_percpu(desc); ... 208: return ret; 209: } 182: irqreturn_t handle_irq_event_percpu(struct irq_desc *desc) 183: { 184: irqreturn_t retval; ... 187: retval = __handle_irq_event_percpu(desc, &flags); ... 193: return retval; 194: } 135: irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags) 136: { 137: irqreturn_t retval = IRQ_NONE; 138: unsigned int irq = desc->irq_data.irq; 139: struct irqaction *action; ... 143: for_each_action_of_desc(desc, action) { 144: irqreturn_t res; ... 147: res = action->handler(irq, action->dev_id); ... 154: switch (res) { ... 168: case IRQ_HANDLED: 169: *flags |= action->flags; 170: break; 171: 172: default: 173: break; 174: } 175: 176: retval |= res; 177: } 178: 179: return retval; 180: } linux-4.14.12/kernel/irq/internals.h 154: #define for_each_action_of_desc(desc, act) \ 155: for (act = desc->action; act; act = act->next)
struct irqaction *action
は、
action->next
でリスト構造を作っている。
プロセス・コンテキストでできること。
割り込みコンテキストでは、このうようなことはできない。 速やかに終了すべきである。busy loop はできるが、あまり やらない方がよい。他の割り込みは、実行される可能性もある。
unsigned long flags; local_irq_save(flags); /* 割り込み禁止 */ ... local_irq_restore(flags); /* 割り込み許可 (save の時の状態にもどる) */単一CPUの x86 では、cli() と sti() で割り込みの禁止と許可を設定する方法 があった。それそれ同名の CPU の命令を実行して、全ての割り込みを禁止/許 可する。マルチプロセッサ(マルチコア含む)では、1つのCPU で割り込みを禁止 しても、他の CPU では許可されていることがあるので、cli()/sti() の方法は 使えない。
特定の割り込み番号の割り込みを禁止する方法もある。
void disable_irq(unsigned ing irq); // 全CPUの割り込みを禁止する void disable_irq_nosync(unsigned ing irq); // 同上。ただし、割り込みハンドラの終了を待たない。 void enable_irq(unsigned ing irq); // 割り込みを許可する。 void synchronize_irq(unsigned ing irq); // 割り込みハンドラの終了を待つ。
memcpy( /*空欄(a)*/,/*空欄(b)*/,/*空欄(c)*/ ); return 0;なお、memcpy() のインタフェースは、次のようになっている。
void * memcpy(void *destination, const void *source, size_t len);sourceは、コピー元、destination は、コピー先、len は長さ(バイト数)であ る。結果として destination を返す。
C言語の 3 項演算子(?と:)は、次のような意味である。
条件 ? 式1 : 式2「条件」が成り立つ(非0)なら、「式1」の値、成り立たな ければ、「式2」の値になる。この課題では、「間違ったプログラム」 を書く課題であり、
return 0;
と常に 0 (成功) を返すようにしている。
なお、__user は、ユーザ空間のアドレスを意味し、エラー・チェックに使われ る、Cプリプロセッサで空の文字列に展開されることもある。この問題では空の 文字列に展開されると考えなさい。
unsigned char year; outb( /*空欄(a)*/, 0x70 ); year = inb( /*空欄(b)*/ );