2025年01月24日 情報科学類 オペレーティングシステム II 筑波大学 システム情報系 新城 靖 <yas@cs.tsukuba.ac.jp>
このページは、次の URL にあります。
https://www.coins.tsukuba.ac.jp/~yas/coins/os2-2024/2025-01-24
あるいは、次のページから手繰っていくこともできます。
https://www.coins.tsukuba.ac.jp/~yas/
https://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 /dev/console
crw------- 1 root root 5, 1 Feb 6 15:22 /dev/console
$
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 = THIS_MODULE; dev = MKDEV(major, minor); cdev_add(&my_cdev, dev, count);count は、同じ major 番号のドライバで扱うデバイスの数。
struct file_operations my_fops = { .... }; struct cdev my_cdev ; cdev_init(&my_cdev, &my_fops); dev = MKDEV(major, minor); cdev_add(&my_cdev, dev, count);register_chrdev() という関数で登録することもできる。以前はこの方法が主。
int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);cdev_device_add() でも良い。device_add() すると、/sys の sysfs からもアクセス可能になる。
linux-6.12.7/fs/char_dev.c 544: int cdev_device_add(struct cdev *cdev, struct device *dev) 545: { ... 551: rc = cdev_add(cdev, dev->devt, 1); ... 556: rc = device_add(dev); ... 560: return rc; 561: }
linux-6.12.7/include/linux/fs.h 2062: struct file_operations { 2063: struct module *owner; 2064: fop_flags_t fop_flags; 2065: loff_t (*llseek) (struct file *, loff_t, int); 2066: ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); 2067: ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); 2068: ssize_t (*read_iter) (struct kiocb *, struct iov_iter *); 2069: ssize_t (*write_iter) (struct kiocb *, struct iov_iter *); 2070: int (*iopoll)(struct kiocb *kiocb, struct io_comp_batch *, 2071: unsigned int flags); 2072: int (*iterate_shared) (struct file *, struct dir_context *); 2073: __poll_t (*poll) (struct file *, struct poll_table_struct *); 2074: long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); 2075: long (*compat_ioctl) (struct file *, unsigned int, unsigned long); 2076: int (*mmap) (struct file *, struct vm_area_struct *); 2077: int (*open) (struct inode *, struct file *); 2078: int (*flush) (struct file *, fl_owner_t id); 2079: int (*release) (struct inode *, struct file *); 2080: int (*fsync) (struct file *, loff_t, loff_t, int datasync); 2081: int (*fasync) (int, struct file *, int); 2082: int (*lock) (struct file *, int, struct file_lock *); 2083: unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); 2084: int (*check_flags)(int); 2085: int (*flock) (struct file *, int, struct file_lock *); 2086: ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); 2087: ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); 2088: void (*splice_eof)(struct file *file); 2089: int (*setlease)(struct file *, int, struct file_lease **, void **); 2090: long (*fallocate)(struct file *file, int mode, loff_t offset, 2091: loff_t len); 2092: void (*show_fdinfo)(struct seq_file *m, struct file *f); 2093: #ifndef CONFIG_MMU 2094: unsigned (*mmap_capabilities)(struct file *); 2095: #endif 2096: ssize_t (*copy_file_range)(struct file *, loff_t, struct file *, 2097: loff_t, size_t, unsigned int); 2098: loff_t (*remap_file_range)(struct file *file_in, loff_t pos_in, 2099: struct file *file_out, loff_t pos_out, 2100: loff_t len, unsigned int remap_flags); 2101: int (*fadvise)(struct file *, loff_t, loff_t, int); 2102: int (*uring_cmd)(struct io_uring_cmd *ioucmd, unsigned int issue_flags); 2103: int (*uring_cmd_iopoll)(struct io_uring_cmd *, struct io_comp_batch *, 2104: unsigned int poll_flags); 2105: } __randomize_layout;主な手続きの意味
デバイス・ファイルでは、open() 等で自分のメジャー番号とマイナー番号を取 り出すために使われることがある。
int fd1 = open("file1"); int fd2 = open("file1");ファイル名 "file1" で表現されるファイルの inode 構造体は、1 個でも、 file 構造体は、2 個割り当てられる。
例
int ioctl(int d, int request, ...);
# hwclock --show
2025-01-17 16:18:04.054004+09:00
# date
Fri Jan 17 16:18:05 JST 2025
#
参考: https://docs.redhat.com/ja/documentation/red_hat_enterprise_linux/7/html/system_administrators_guide/s1-configuring_the_hardware_clock_update,Red Hat Enterprise Linux システム管理者のガイド/19.18. ハードウェアクロック更新の設定
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: int 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: return( 0 ); 38: }
$ ls -l /dev/rtc
lrwxrwxrwx 1 root root 4 Jan 10 15:31 /dev/rtc -> rtc0
$ ls -l /dev/rtc0
crw------- 1 root root 251, 0 Jan 10 15:31 /dev/rtc0
$ ls -Ll /dev/rtc
crw------- 1 root root 251, 0 Jan 10 15:31 /dev/rtc
$
$ make rtc-read-time
cc rtc-read-time.c -o rtc-read-time
$ su
Password:
# ./rtc-read-time
2025-01-17 07:21:54
# ./rtc-read-time; hwclock --show; date
2025-01-17 07:21:56
2025-01-17 16:21:56.932726+09:00
Fri Jan 17 16:21:56 JST 2025
# ./rtc-read-time; hwclock --show; date
2025-01-17 07:21:58
2025-01-17 16:21:58.212869+09:00
Fri Jan 17 16:21:58 JST 2025
#
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 | 定期的な割り込みの(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-6.12.7/include/linux/types.h 18: typedef u32 __kernel_dev_t; ... 21: typedef __kernel_dev_t dev_t; linux-6.12.7/include/linux/kdev_t.h 7: #define MINORBITS 20 8: #define MINORMASK ((1U << MINORBITS) - 1) 9: 10: #define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS)) 11: #define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) 12: #define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi)) linux-6.12.7/include/linux/rtc.h 87: struct rtc_device { ... 91: int id; ... 96: struct cdev char_dev; ... 164: }; linux-6.12.7/drivers/rtc/dev.c 524: static const struct file_operations rtc_dev_fops = { 525: .owner = THIS_MODULE, 526: .read = rtc_dev_read, 527: .poll = rtc_dev_poll, 528: .unlocked_ioctl = rtc_dev_ioctl, 529: #ifdef CONFIG_COMPAT 530: .compat_ioctl = rtc_dev_compat_ioctl, 531: #endif 532: .open = rtc_dev_open, 533: .release = rtc_dev_release, 534: .fasync = rtc_dev_fasync, 535: }; 19: static dev_t rtc_devt; 560: void __init rtc_dev_init(void) 561: { 562: int err; 563: 564: err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc"); 565: if (err < 0) 566: pr_err("failed to allocate char dev region\n"); 567: } 539: void rtc_dev_prepare(struct rtc_device *rtc) 540: { ... 549: rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id); ... 556: cdev_init(&rtc->char_dev, &rtc_dev_fops); 557: rtc->char_dev.owner = rtc->owner; 558: } linux-6.12.7/drivers/rtc/class.c 393: int __devm_rtc_register_device(struct module *owner, struct rtc_device *rtc) 394: { ... 417: rtc_dev_prepare(rtc); ... 419: err = cdev_device_add(&rtc->char_dev, &rtc->dev); ... 441: }
linux-6.12.7/drivers/rtc/dev.c 23: static int rtc_dev_open(struct inode *inode, struct file *file) 24: { 25: struct rtc_device *rtc = container_of(inode->i_cdev, 26: struct rtc_device, char_dev); 27: 28: if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags)) 29: return -EBUSY; 30: 31: file->private_data = rtc; ... 37: return 0; 38: }
&rtc->flags
の
RTC_DEV_BUSY
ビットをテストする。
それがセットされていれば、
どれかのプロセスにより open("/dev/rtc",) がされていて、
close() はされていない状態である。
その場合は、EBUSY というエラーにして open() が失敗する。
&rtc->flags
の
RTC_DEV_BUSY
ビットは、
test_and_set の結果、自動的にセットされる。
linux-6.12.7/drivers/rtc/dev.c 502: static int rtc_dev_release(struct inode *inode, struct file *file) 503: { 504: struct rtc_device *rtc = file->private_data; ... 520: clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags); 521: return 0; 522: }rtc_dev_open() でセットした変数
&rtc->flags
の
RTC_DEV_BUSY ビットは、close() システム・コールで呼ばれる
rtc_dev_release() ( struct file_operations rtc_fops の.release) で、ク
リアされる。
linux-6.12.7/drivers/rtc/dev.c 203: static long rtc_dev_ioctl(struct file *file, 204: unsigned int cmd, unsigned long arg) 205: { 206: int err = 0; 207: struct rtc_device *rtc = file->private_data; 208: const struct rtc_class_ops *ops = rtc->ops; 209: struct rtc_time tm; ... 212: void __user *uarg = (void __user *)arg; ... 256: switch (cmd) { 257: case RTC_ALM_READ: ... 268: case RTC_ALM_SET: ... 320: case RTC_RD_TIME: ... 323: err = rtc_read_time(rtc, &tm); 324: if (err < 0) 325: return err; 326: 327: if (copy_to_user(uarg, &tm, sizeof(tm))) 328: err = -EFAULT; 329: return err; 330: 331: case RTC_SET_TIME: ... 334: if (copy_from_user(&tm, uarg, sizeof(tm))) 335: return -EFAULT; 336: 337: return rtc_set_time(rtc, &tm); ... 460: } ... 465: }
カーネル空間とユーザ空間でデータをコピーする時には、次のような特殊な関 数を使う必要がある。
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-6.12.7/drivers/rtc/interface.c 110: int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) 111: { ... 118: err = __rtc_read_time(rtc, tm); ... 123: } 84: static int __rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) 85: { 86: int err; ... 93: memset(tm, 0, sizeof(struct rtc_time)); 94: err = rtc->ops->read_time(rtc->dev.parent, tm); ... 101: rtc_add_offset(rtc, tm); ... 103: err = rtc_valid_tm(tm); 107: return err; 108: } linux-6.12.7/drivers/rtc/rtc-cmos.c 623: static const struct rtc_class_ops cmos_rtc_ops = { 624: .read_time = cmos_read_time, 625: .set_time = cmos_set_time, 626: .read_alarm = cmos_read_alarm, 627: .set_alarm = cmos_set_alarm, 628: .proc = cmos_procfs, 629: .alarm_irq_enable = cmos_alarm_irq_enable, 630: }; 223: static int cmos_read_time(struct device *dev, struct rtc_time *t) 224: { ... 234: ret = mc146818_get_time(t); ... 240: return 0; 241: } linux-6.12.7/drivers/rtc/rtc-mc146818-lib.c 154: int mc146818_get_time(struct rtc_time *time, int timeout) 155: { 156: struct mc146818_get_time_callback_param p = { 157: .time = time 158: }; 159: 160: if (!mc146818_avoid_UIP(mc146818_get_time_callback, timeout, &p)) { ... 163: } ... 191: if (time->tm_year <= 69) 192: time->tm_year += 100; 193: 194: time->tm_mon--; 195: 196: return 0; 197: } 21: bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param), 22: int timeout, 23: void *param) 24: { ... 30: spin_lock_irqsave(&rtc_lock, flags); ... 41: seconds = CMOS_READ(RTC_SECONDS); ... 50: if (seconds != CMOS_READ(RTC_SECONDS)) { ... 53: } ... 55: if (callback) 56: callback(seconds, param); ... 78: spin_unlock_irqrestore(&rtc_lock, flags); ... 87: } 111: static void mc146818_get_time_callback(unsigned char seconds, void *param_in) 112: { 113: struct mc146818_get_time_callback_param *p = param_in; 114: 115: /* 116: * Only the values that we read from the RTC are set. We leave 117: * tm_wday, tm_yday and tm_isdst untouched. Even though the 118: * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated 119: * by the RTC when initially set to a non-zero value. 120: */ 121: p->time->tm_sec = seconds; 122: p->time->tm_min = CMOS_READ(RTC_MINUTES); 123: p->time->tm_hour = CMOS_READ(RTC_HOURS); 124: p->time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); 125: p->time->tm_mon = CMOS_READ(RTC_MONTH); 126: p->time->tm_year = CMOS_READ(RTC_YEAR); ... 140: }
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-6.12.7/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-6.12.7/arch/x86/kernel/rtc.c 80: unsigned char rtc_cmos_read(unsigned char addr) 81: { 82: unsigned char val; 83: 84: lock_cmos_prefix(addr); 85: outb(addr, RTC_PORT(0)); 86: val = inb(RTC_PORT(1)); 87: lock_cmos_suffix(addr); 88: 89: return val; 90: } 93: void rtc_cmos_write(unsigned char val, unsigned char addr) 94: { 95: lock_cmos_prefix(addr); 96: outb(addr, RTC_PORT(0)); 97: outb(val, RTC_PORT(1)); 98: lock_cmos_suffix(addr); 99: } linux-6.12.7/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
linux-5.15.12/arch/x86/boot/boot.h 39: static inline void outb(u8 v, u16 port) 40: { 41: asm volatile("outb %0,%1" : : "a" (v), "dN" (port)); 42: } 43: static inline u8 inb(u16 port) 44: { 45: u8 v; 46: asm volatile("inb %1,%0" : "=a" (v) : "dN" (port)); 47: return v; 48: }
asm ( "アセンブラの命令列" : 出力オペランド(省略可) : 入力オペランド(省略可) : 破壊するレジスタ(省略可) )
=
があると、書き込み専用になる。
linux-6.12.7/arch/x86/include/asm/shared/io.h 7: #define BUILDIO(bwl, bw, type) \ 8: static inline void __out##bwl(type value, u16 port) \ 9: { \ 10: asm volatile("out" #bwl " %" #bw "0, %w1" \ 11: : : "a"(value), "Nd"(port)); \ 12: } \ 13: \ 14: static inline type __in##bwl(u16 port) \ 15: { \ 16: type value; \ 17: asm volatile("in" #bwl " %w1, %" #bw "0" \ 18: : "=a"(value) : "Nd"(port)); \ 19: return value; \ 20: } 21: 22: BUILDIO(b, b, u8) 23: BUILDIO(w, w, u16) 24: BUILDIO(l, , u32) ... 27: #define inb __inb 28: #define inw __inw 29: #define inl __inl 30: #define outb __outb 31: #define outw __outw 32: #define outl __outl
id1##id2
」 は、
識別子(関数名、変数名等)の結合を意味する。
たとえば、マクロ定義の引数 bwl
が値 b
を持っていれば、out##bwl
は、outb
となる。
(「#
」がなければ、「out bwl
」 は、「out b
」と間に空白が残る)。
#var
」 は、文字列化。
たとえば、マクロ定義の引数 bwl が値 b を持っていれば、#bwl は、"b" となる。
(「#」がなければ、bwl は、b )。
static inline void __outb(u8 value, u16 port) { asm volatile("outb %b0, %w1" : : "a"(value), "Nd"(port)); } static inline u8 __inb(u16 port) { u8 value; asm volatile("inb %w1, %b0" : "=a"(value) : "Nd"(port)); return value; }
$ cat /proc/ioports
0000-0cf7 : PCI Bus 0000:00
0000-001f : dma1
0020-0021 : PNP0001:00
0020-0021 : pic1
0040-0043 : timer0
0050-0053 : timer1
0060-0060 : keyboard
0061-0061 : PNP0800:00
0064-0064 : keyboard
0070-0073 : rtc0
0080-008f : dma page reg
...
0d00-feff : PCI Bus 0000:00
...
e000-efff : PCI Bus 0000:19
$
図? x86 の Intel 8259
https://wiki.osdev.org/Interrupts
)。
番号 | 説明 |
---|---|
0 | PIT (Programmable Interval Timer) |
1 | キーボード |
2 | (カスケード) |
3 | COM2 |
4 | COM1 |
5 | LP2 |
6 | フロッピディスク |
7 | LP1 |
8 | CMOS RTC (後述) |
9 | 空き (SCSI, NIC) |
10 | 空き (SCSI, NIC) |
11 | 空き (SCSI, NIC) |
12 | PS2 マウス |
13 | FPU, コプロセッサ、プロセッサ間 |
14 | Primary ATA HDD |
15 | Seconday ATA HDD |
図? 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-6.12.7/arch/x86/include/asm/mc146818rtc.h 101: #define RTC_IRQ 8 linux-6.12.7/drivers/rtc/rtc-cmos.c 73: struct cmos_rtc { 74: struct rtc_device *rtc; 75: struct device *dev; 76: int irq; .... 92: }; 694: static struct cmos_rtc cmos_rtc; 1389: static int cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) 1390: { 1391: int irq; ... 1401: irq = RTC_IRQ; ... 1407: return cmos_do_probe(&pnp->dev, pnp_get_resource(pnp, IORESOURCE_IO, 0), irq); 1408: } 923: static int INITSECTION 924: cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) 925: { ... 1023: cmos_rtc.rtc = devm_rtc_allocate_device(dev); ... 1077: irq_handler_t rtc_cmos_int_handler; ... 1089: rtc_cmos_int_handler = cmos_interrupt; 1090: 1091: retval = request_irq(rtc_irq, rtc_cmos_int_handler, 1092: 0, dev_name(&cmos_rtc.rtc->dev), 1093: cmos_rtc.rtc); ... 1104: retval = devm_rtc_register_device(cmos_rtc.rtc); ... 1143: return retval; 1144: } 696: static irqreturn_t cmos_interrupt(int irq, void *p) 697: { 698: u8 irqstat; ... 710: irqstat = CMOS_READ(RTC_INTR_FLAGS); ... 737: if (is_intr(irqstat)) { 738: rtc_update_irq(p, 1, irqstat); 739: return IRQ_HANDLED; 740: } else 741: return IRQ_NONE; 742: }
linux-6.12.7/arch/x86/kernel/traps.c 1454: void __init trap_init(void) 1455: { ... 1467: idt_setup_traps(); ... 1470: } linux-6.12.7/arch/x86/include/asm/trapnr.h 19: #define X86_TRAP_DE 0 /* Divide-by-zero */ 20: #define X86_TRAP_DB 1 /* Debug */ 21: #define X86_TRAP_NMI 2 /* Non-maskable Interrupt */ 22: #define X86_TRAP_BP 3 /* Breakpoint */ 23: #define X86_TRAP_OF 4 /* Overflow */ 24: #define X86_TRAP_BR 5 /* Bound Range Exceeded */ 25: #define X86_TRAP_UD 6 /* Invalid Opcode */ 26: #define X86_TRAP_NM 7 /* Device Not Available */ linux-6.12.7/arch/x86/include/asm/irq_vectors.h 38: #define IA32_SYSCALL_VECTOR 0x80 ... 106: #define NR_VECTORS 256 linux-6.12.7/arch/x86/kernel/idt.c 173: static gate_desc idt_table[IDT_ENTRIES] __page_aligned_bss; ... 84: static const __initconst struct idt_data def_idts[] = { 85: INTG(X86_TRAP_DE, asm_exc_divide_error), 86: ISTG(X86_TRAP_NMI, asm_exc_nmi, IST_INDEX_NMI), 87: INTG(X86_TRAP_BR, asm_exc_bounds), 88: INTG(X86_TRAP_UD, asm_exc_invalid_op), 89: INTG(X86_TRAP_NM, asm_exc_device_not_available), ... 128: }; 232: void __init idt_setup_traps(void) 233: { 234: idt_setup_from_table(idt_table, def_idts, ARRAY_SIZE(def_idts), true); ... 238: } linux-6.12.7/arch/x86/include/asm/idtentry.h 34: #define DECLARE_IDTENTRY(vector, func) \ 35: asmlinkage void asm_##func(void); \ 36: asmlinkage void xen_asm_##func(void); \ 37: void fred_##func(struct pt_regs *regs); \ 38: __visible void func(struct pt_regs *regs) 601: DECLARE_IDTENTRY(X86_TRAP_DE, exc_divide_error); 602: DECLARE_IDTENTRY(X86_TRAP_OF, exc_overflow); 603: DECLARE_IDTENTRY(X86_TRAP_BR, exc_bounds); 604: DECLARE_IDTENTRY(X86_TRAP_NM, exc_device_not_available); linux-6.12.7/arch/x86/kernel/traps.c 237: DEFINE_IDTENTRY(exc_divide_error) 238: { 239: do_error_trap(regs, 0, "divide error", X86_TRAP_DE, SIGFPE, 240: FPE_INTDIV, error_get_trap_addr(regs)); 241: } linux-6.12.7/arch/x86/kernel/idt.c 133: static const __initconst struct idt_data apic_idts[] = { ... 142: INTG(THERMAL_APIC_VECTOR, asm_sysvec_thermal), ... 154: INTG(LOCAL_TIMER_VECTOR, asm_sysvec_apic_timer_interrupt), 155: INTG(X86_PLATFORM_IPI_VECTOR, asm_sysvec_x86_platform_ipi), ... 170: }; linux-6.12.7/arch/x86/include/asm/idtentry.h 551: SYM_CODE_START(irq_entries_start) 552: vector=FIRST_EXTERNAL_VECTOR 553: .rept NR_EXTERNAL_VECTORS ... 558: jmp asm_common_interrupt ... 561: vector = vector+1 562: .endr 563: SYM_CODE_END(irq_entries_start) 693: DECLARE_IDTENTRY_IRQ(X86_TRAP_OTHER, common_interrupt); linux-6.12.7/arch/x86/entry/entry_64.S 1088: SYM_CODE_START_LOCAL(error_return) ... 1092: jz restore_regs_and_return_to_kernel ... 619: SYM_INNER_LABEL(restore_regs_and_return_to_kernel, SYM_L_GLOBAL) ... 659: iretq 87: SYM_CODE_START(entry_SYSCALL_64) ... 121: call do_syscall_64 /* returns with IRQs disabled */ ... 166: sysretq linux-6.12.7/arch/x86/kernel/cpu/common.c 2042: static inline void idt_syscall_init(void) 2043: { 2044: wrmsrl(MSR_LSTAR, (unsigned long)entry_SYSCALL_64); ... 2075: }
linux-6.12.7/arch/x86/kernel/irq.c 278: DEFINE_IDTENTRY_IRQ(common_interrupt) 279: { ... 285: if (unlikely(call_irq_handler(vector, regs))) 286: apic_eoi(); ... 289: } 252: static __always_inline int call_irq_handler(int vector, struct pt_regs *regs) 253: { 254: struct irq_desc *desc; ... 257: desc = __this_cpu_read(vector_irq[vector]); ... 259: handle_irq(desc, regs); ... 272: } 243: static __always_inline void handle_irq(struct irq_desc *desc, 244: struct pt_regs *regs) 245: { ... 247: generic_handle_irq_desc(desc); ... 250: }
linux-6.12.7/kernel/irq/handle.c 139: irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc) 140: { 141: irqreturn_t retval = IRQ_NONE; 142: unsigned int irq = desc->irq_data.irq; 143: struct irqaction *action; ... 147: for_each_action_of_desc(desc, action) { 148: irqreturn_t res; ... 158: res = action->handler(irq, action->dev_id); ... 183: retval |= res; 184: } 185: 186: return retval; 187: } linux-6.12.7/kernel/irq/internals.h 172: #define for_each_action_of_desc(desc, act) \ 173: for (act = desc->action; act; act = act->next) linux-6.12.7/include/linux/irqreturn.h 11: enum irqreturn { 12: IRQ_NONE = (0 << 0), 13: IRQ_HANDLED = (1 << 0), ... 15: }; 16: 17: typedef enum irqreturn irqreturn_t;
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 int irq); // 全CPUの割り込みを禁止する void disable_irq_nosync(unsigned int irq); // 同上。ただし、割り込みハンドラの終了を待たない。 void enable_irq(unsigned int irq); // 割り込みを許可する。 void synchronize_irq(unsigned int irq); // 割り込みハンドラの終了を待つ。
if( memcpy( /*空欄(a)*/,/*空欄(b)*/,/*空欄(c)*/ ), 0 ) return -EFAULT;なお、memcpy() のインタフェースは、次のようになっている。
void * memcpy(void *destination, const void *source, size_t len);sourceは、コピー元、destination は、コピー先、len は長さ(バイト数)であ る。結果として destination を返す。
C言語の「,」演算子は、次のような意味である。
式1 , 式2「式1」を評価し、次に「式2」を評価し、 全体としては、「式2」の値を返す。 この課題は、常に 0 (成功) を返すようにしている。
なお、__user は、ユーザ空間のアドレスを意味し、エラー・チェックに使われ る、Cプリプロセッサで空の文字列に展開されることもある。この問題では空の 文字列に展開されると考えなさい。
unsigned char x; outb( /*空欄(a)*/, /*空欄(b)*/); x = inb( /*空欄(c)*/ );
そのような割り込みハンドラが、デバイスからの割り込みを処理した時に返す 値を答えなさい。
drivers/rtc/class.c で定義されて、このページで説明している関数のうち、 次のものを1つ上げなさい。