2022年01月21日
情報科学類 オペレーティングシステム II
筑波大学 システム情報系
新城 靖
<yas@cs.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~yas/coins/os2-2021/2022-01-21
あるいは、次のページから手繰っていくこともできます。
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 = THIS_MODULE;
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);
cdev_device_add() でも良い。device_add() すると、/sys の sysfs からもアクセス可能になる。
linux-5.15.12/fs/char_dev.c
537: int cdev_device_add(struct cdev *cdev, struct device *dev)
538: {
...
544: rc = cdev_add(cdev, dev->devt, 1);
...
549: rc = device_add(dev);
..
553: return rc;
554: }
linux-5.15.12/include/linux/fs.h
2071: struct file_operations {
2072: struct module *owner;
2073: loff_t (*llseek) (struct file *, loff_t, int);
2074: ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
2075: ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
2076: ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
2077: ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
2078: int (*iopoll)(struct kiocb *kiocb, bool spin);
2079: int (*iterate) (struct file *, struct dir_context *);
2080: int (*iterate_shared) (struct file *, struct dir_context *);
2081: __poll_t (*poll) (struct file *, struct poll_table_struct *);
2082: long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
2083: long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
2084: int (*mmap) (struct file *, struct vm_area_struct *);
2085: unsigned long mmap_supported_flags;
2086: int (*open) (struct inode *, struct file *);
2087: int (*flush) (struct file *, fl_owner_t id);
2088: int (*release) (struct inode *, struct file *);
2089: int (*fsync) (struct file *, loff_t, loff_t, int datasync);
2090: int (*fasync) (int, struct file *, int);
2091: int (*lock) (struct file *, int, struct file_lock *);
2092: ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
2093: unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
2094: int (*check_flags)(int);
2095: int (*flock) (struct file *, int, struct file_lock *);
2096: ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
2097: ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
2098: int (*setlease)(struct file *, long, struct file_lock **, void **);
2099: long (*fallocate)(struct file *file, int mode, loff_t offset,
2100: loff_t len);
2101: void (*show_fdinfo)(struct seq_file *m, struct file *f);
2102: #ifndef CONFIG_MMU
2103: unsigned (*mmap_capabilities)(struct file *);
2104: #endif
2105: ssize_t (*copy_file_range)(struct file *, loff_t, struct file *,
2106: loff_t, size_t, unsigned int);
2107: loff_t (*remap_file_range)(struct file *file_in, loff_t pos_in,
2108: struct file *file_out, loff_t pos_out,
2109: loff_t len, unsigned int remap_flags);
2110: int (*fadvise)(struct file *, loff_t, loff_t, int);
2111: } __randomize_layout;
主な手続きの意味
デバイス・ファイルでは、open() 等で自分のメジャー番号とマイナー番号を取 り出すために使われることがある。
int fd1 = open("file1");
int fd2 = open("file1");
ファイル名 "file1" で表現されるファイルの inode 構造体は、1 個でも、
file 構造体は、2 個割り当てられる。
例
int ioctl(int d, int request, ...);
# hwclock --show
Fri Jan 14 20:38:37 2022 -0.834124 seconds
# date
Fri Jan 14 20:38:38 JST 2022
#
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
lrwxrwxrwx 1 root root 4 Oct 26 09:53 /dev/rtc -> rtc0
$ ls -l /dev/rtc0
crw------- 1 root root 252, 0 Oct 26 09:53 /dev/rtc0
$ ls -lL /dev/rtc
crw------- 1 root root 252, 0 Oct 26 09:53 /dev/rtc
$
$ make rtc-read-time
cc rtc-read-time.c -o rtc-read-time
$ su
Password:
# ./rtc-read-time
2022-01-14 11:54:19
# ./rtc-read-time ; hwclock --show; date
2022-01-14 11:54:21
Fri Jan 14 20:54:22 2022 -0.833925 seconds
Fri Jan 14 20:54:22 JST 2022
# ./rtc-read-time ; hwclock --show; date
2022-01-14 11:54:23
Fri Jan 14 20:54:24 2022 -0.454304 seconds
Fri Jan 14 20:54:24 JST 2022
#
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-5.15.12/include/linux/types.h
13: typedef u32 __kernel_dev_t;
...
16: typedef __kernel_dev_t dev_t;
linux-5.15.12/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-5.15.12/drivers/rtc/dev.c
19: static dev_t rtc_devt;
linux-5.15.12/drivers/rtc/dev.c
459: static const struct file_operations rtc_dev_fops = {
460: .owner = THIS_MODULE,
461: .llseek = no_llseek,
462: .read = rtc_dev_read,
463: .poll = rtc_dev_poll,
464: .unlocked_ioctl = rtc_dev_ioctl,
465: #ifdef CONFIG_COMPAT
466: .compat_ioctl = rtc_dev_compat_ioctl,
467: #endif
468: .open = rtc_dev_open,
469: .release = rtc_dev_release,
470: .fasync = rtc_dev_fasync,
471: };
linux-5.15.12/drivers/rtc/dev.c
496: void __init rtc_dev_init(void)
497: {
...
500: err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc");
503: }
linux-5.15.12/drivers/rtc/class.c
376: int __devm_rtc_register_device(struct module *owner, struct rtc_device *rtc)
377: {
...
397: rtc_dev_prepare(rtc);
398:
399: err = cdev_device_add(&rtc->char_dev, &rtc->dev);
...
419: }
linux-5.15.12/drivers/rtc/dev.c
475: void rtc_dev_prepare(struct rtc_device *rtc)
476: {
...
485: rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id);
...
492: cdev_init(&rtc->char_dev, &rtc_dev_fops);
493: rtc->char_dev.owner = rtc->owner;
494: }
linux-5.15.12/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-5.15.12/drivers/rtc/dev.c
437: static int rtc_dev_release(struct inode *inode, struct file *file)
438: {
439: struct rtc_device *rtc = file->private_data;
...
455: clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags);
456: return 0;
457: }
rtc_dev_open() でセットした変数 &rtc->flagsの
RTC_DEV_BUSY ビットは、close() システム・コールで呼ばれる
rtc_dev_release() ( struct file_operations rtc_fops の.release) で、ク
リアされる。
linux-5.15.12/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;
...
254: switch (cmd) {
...
255: case RTC_ALM_READ:
...
266: case RTC_ALM_SET:
...
318: case RTC_RD_TIME:
...
321: err = rtc_read_time(rtc, &tm);
322: if (err < 0)
323: return err;
324:
325: if (copy_to_user(uarg, &tm, sizeof(tm)))
326: err = -EFAULT;
327: return err;
328:
329: case RTC_SET_TIME:
...
332: if (copy_from_user(&tm, uarg, sizeof(tm)))
333: return -EFAULT;
334:
335: return rtc_set_time(rtc, &tm);
336:
395: }
...
400: }
カーネル空間とユーザ空間でデータをコピーする時には、次のような特殊な関 数を使う必要がある。
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-5.15.12/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-5.15.12/drivers/rtc/rtc-cmos.c
562: static const struct rtc_class_ops cmos_rtc_ops = {
563: .read_time = cmos_read_time,
564: .set_time = cmos_set_time,
565: .read_alarm = cmos_read_alarm,
566: .set_alarm = cmos_set_alarm,
567: .proc = cmos_procfs,
568: .alarm_irq_enable = cmos_alarm_irq_enable,
569: };
223: static int cmos_read_time(struct device *dev, struct rtc_time *t)
224: {
...
232: mc146818_get_time(t);
233: return 0;
234: }
linux-5.15.12/drivers/rtc/rtc-mc146818-lib.c
11: unsigned int mc146818_get_time(struct rtc_time *time)
12: {
...
23: spin_lock_irqsave(&rtc_lock, flags);
...
40: time->tm_sec = CMOS_READ(RTC_SECONDS);
...
60: time->tm_min = CMOS_READ(RTC_MINUTES);
61: time->tm_hour = CMOS_READ(RTC_HOURS);
62: time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
63: time->tm_mon = CMOS_READ(RTC_MONTH);
64: time->tm_year = CMOS_READ(RTC_YEAR);
...
87: spin_unlock_irqrestore(&rtc_lock, flags);
...
114: if (time->tm_year <= 69)
115: time->tm_year += 100;
116:
117: time->tm_mon--;
...
120: }
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-5.15.12/arch/x86/include/asm/mc146818rtc.h
11: #ifndef RTC_PORT
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-5.15.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-5.15.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
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-5.15.12/arch/x86/include/asm/io.h
274: #define BUILDIO(bwl, bw, type) \
275: static inline void out##bwl(unsigned type value, int port) \
276: { \
277: asm volatile("out" #bwl " %" #bw "0, %w1" \
278: : : "a"(value), "Nd"(port)); \
279: } \
280: \
281: static inline unsigned type in##bwl(int port) \
282: { \
283: unsigned type value; \
284: asm volatile("in" #bwl " %w1, %" #bw "0" \
285: : "=a"(value) : "Nd"(port)); \
286: return value; \
287: } \
...
334: BUILDIO(b, b, char)
335: BUILDIO(w, w, short)
336: 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-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

図? 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-5.15.12/arch/x86/include/asm/mc146818rtc.h
101: #define RTC_IRQ 8
linux-5.15.12/drivers/rtc/rtc-cmos.c
73: struct cmos_rtc {
74: struct rtc_device *rtc;
75: struct device *dev;
76: int irq;
....
92: };
636: static struct cmos_rtc cmos_rtc;
693: static int INITSECTION
694: cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
695: {
...
785: cmos_rtc.rtc = devm_rtc_allocate_device(dev);
...
846: rtc_cmos_int_handler = cmos_interrupt;
...
848: retval = request_irq(rtc_irq, rtc_cmos_int_handler,
849: 0, dev_name(&cmos_rtc.rtc->dev),
850: cmos_rtc.rtc);
...
861: retval = devm_rtc_register_device(cmos_rtc.rtc);
...
894: }
638: static irqreturn_t cmos_interrupt(int irq, void *p)
639: {
640: u8 irqstat;
...
652: irqstat = CMOS_READ(RTC_INTR_FLAGS);
...
679: if (is_intr(irqstat)) {
680: rtc_update_irq(p, 1, irqstat);
681: return IRQ_HANDLED;
682: } else
683: return IRQ_NONE;
684: }
linux-5.15.12/arch/x86/kernel/traps.c
1190: void __init trap_init(void)
1191: {
...
1201: idt_setup_traps();
...
1203: }
linux-5.15.12/arch/x86/include/asm/trapnr.h
7: #define X86_TRAP_DE 0 /* Divide-by-zero */
8: #define X86_TRAP_DB 1 /* Debug */
9: #define X86_TRAP_NMI 2 /* Non-maskable Interrupt */
10: #define X86_TRAP_BP 3 /* Breakpoint */
11: #define X86_TRAP_OF 4 /* Overflow */
12: #define X86_TRAP_BR 5 /* Bound Range Exceeded */
13: #define X86_TRAP_UD 6 /* Invalid Opcode */
14: #define X86_TRAP_NM 7 /* Device Not Available */
linux-5.15.12/arch/x86/include/asm/irq_vectors.h
45: #define IA32_SYSCALL_VECTOR 0x80
...
109: #define NR_VECTORS 256
linux-5.15.12/arch/x86/kernel/idt.c
159: static gate_desc idt_table[IDT_ENTRIES] __page_aligned_bss;
79: static const __initconst struct idt_data def_idts[] = {
80: INTG(X86_TRAP_DE, asm_exc_divide_error),
81: ISTG(X86_TRAP_NMI, asm_exc_nmi, IST_INDEX_NMI),
82: INTG(X86_TRAP_BR, asm_exc_bounds),
83: INTG(X86_TRAP_UD, asm_exc_invalid_op),
84: INTG(X86_TRAP_NM, asm_exc_device_not_available),
...
114: SYSG(IA32_SYSCALL_VECTOR, entry_INT80_32),
...
116: };
218: void __init idt_setup_traps(void)
219: {
220: idt_setup_from_table(idt_table, def_idts, ARRAY_SIZE(def_idts), true);
221: }
linux-5.15.12/arch/x86/include/asm/idtentry.h
29: #define DECLARE_IDTENTRY(vector, func) \
30: asmlinkage void asm_##func(void); \
31: asmlinkage void xen_asm_##func(void); \
32: __visible void func(struct pt_regs *regs)
546: DECLARE_IDTENTRY(X86_TRAP_DE, exc_divide_error);
547: DECLARE_IDTENTRY(X86_TRAP_OF, exc_overflow);
548: DECLARE_IDTENTRY(X86_TRAP_BR, exc_bounds);
549: DECLARE_IDTENTRY(X86_TRAP_NM, exc_device_not_available);
linux-5.15.12/arch/x86/kernel/traps.c
201: DEFINE_IDTENTRY(exc_divide_error)
202: {
203: do_error_trap(regs, 0, "divide error", X86_TRAP_DE, SIGFPE,
204: FPE_INTDIV, error_get_trap_addr(regs));
205: }
969: SYM_FUNC_START(entry_INT80_32)
...
971: pushl %eax /* pt_regs->orig_ax */
972:
973: SAVE_ALL pt_regs_ax=$-ENOSYS switch_stacks=1 /* save rest */
974:
975: movl %esp, %eax
976: call do_int80_syscall_32
...
997: iret
linux-5.15.12/arch/x86/entry/common.c
118: /* Handles int $0x80 */
119: __visible noinstr void do_int80_syscall_32(struct pt_regs *regs)
120: {
...
132: do_syscall_32_irqs_on(regs, nr);
...
136: }
linux-5.15.12/arch/x86/entry/common.c
102: static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs, int nr)
103: {
108: unsigned int unr = nr;
...
112: regs->ax = ia32_sys_call_table[unr](regs);
116: }
linux-5.15.12/kernel/irq/handle.c
137: irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags)
138: {
139: irqreturn_t retval = IRQ_NONE;
140: unsigned int irq = desc->irq_data.irq;
141: struct irqaction *action;
...
145: for_each_action_of_desc(desc, action) {
146: irqreturn_t res;
...
156: res = action->handler(irq, action->dev_id);
..
163: switch (res) {
...
177: case IRQ_HANDLED:
178: *flags |= action->flags;
179: break;
180:
181: default:
182: break;
183: }
184:
185: retval |= res;
186: }
187:
188: return retval;
189: }
linux-5.15.12/kernel/irq/internals.h
161: #define for_each_action_of_desc(desc, act) \
162: 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);
// 割り込みハンドラの終了を待つ。
なるべく授業時間中に次の問題を解き、Manaba の「レポート」で回答しなさい。
unsigned char month;
outb( /*空欄(a)*/, 0x70 );
month = inb( /*空欄(b)*/ );
drivers/rtc/{class.c,dev.c,rtc-cmos.c} で定義されて、このページで説明し ている関数のうち、次のものを1つ上げなさい。