2020年01月24日
情報科学類 オペレーティングシステム II
筑波大学 システム情報系
新城 靖
<yas@cs.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~yas/coins/os2-2019/2020-01-24
あるいは、次のページから手繰っていくこともできます。
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-5.4.7/include/linux/fs.h
1821: struct file_operations {
1822: struct module *owner;
1823: loff_t (*llseek) (struct file *, loff_t, int);
1824: ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
1825: ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
1826: ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
1827: ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
1828: int (*iopoll)(struct kiocb *kiocb, bool spin);
1829: int (*iterate) (struct file *, struct dir_context *);
1830: int (*iterate_shared) (struct file *, struct dir_context *);
1831: __poll_t (*poll) (struct file *, struct poll_table_struct *);
1832: long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
1833: long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
1834: int (*mmap) (struct file *, struct vm_area_struct *);
1835: unsigned long mmap_supported_flags;
1836: int (*open) (struct inode *, struct file *);
1837: int (*flush) (struct file *, fl_owner_t id);
1838: int (*release) (struct inode *, struct file *);
1839: int (*fsync) (struct file *, loff_t, loff_t, int datasync);
1840: int (*fasync) (int, struct file *, int);
1841: int (*lock) (struct file *, int, struct file_lock *);
1842: ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
1843: unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
1844: int (*check_flags)(int);
1845: int (*flock) (struct file *, int, struct file_lock *);
1846: ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
1847: ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
1848: int (*setlease)(struct file *, long, struct file_lock **, void **);
1849: long (*fallocate)(struct file *file, int mode, loff_t offset,
1850: loff_t len);
1851: void (*show_fdinfo)(struct seq_file *m, struct file *f);
1852: #ifndef CONFIG_MMU
1853: unsigned (*mmap_capabilities)(struct file *);
1854: #endif
1855: ssize_t (*copy_file_range)(struct file *, loff_t, struct file *,
1856: loff_t, size_t, unsigned int);
1857: loff_t (*remap_file_range)(struct file *file_in, loff_t pos_in,
1858: struct file *file_out, loff_t pos_out,
1859: loff_t len, unsigned int remap_flags);
1860: int (*fadvise)(struct file *, loff_t, loff_t, int);
1861: } __randomize_layout;
主な手続きの意味
デバイス・ファイルでは、open() 等で自分のメジャー番号とマイナー番号を取 り出すために使われることがある。
int fd1 = open("file1");
int fd2 = open("file1");
ファイル名 "file1" で表現されるファイルの inode 構造体は、1 個でも、
file 構造体は、2 個割り当てられる。
例
int ioctl(int d, int request, ...);
# hwclock --show
2020-01-19 12:28:36.404807+0900
# date
2020年 1月 19日 日曜日 12:28:38 JST
#
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
2020-01-19 03:31:21
# ./rtc-read-time; hwclock --show; date
2020-01-19 03:31:27
2020-01-19 12:31:27.811063+0900
2020年 1月 19日 日曜日 12:31:28 JST
# ./rtc-read-time; hwclock --show; date
2020-01-19 03:31:29
2020-01-19 12:31:29.545443+0900
2020年 1月 19日 日曜日 12:31:30 JST
#
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.4.7/drivers/char/rtc.c
799: static const struct file_operations rtc_fops = {
800: .owner = THIS_MODULE,
801: .llseek = no_llseek,
802: .read = rtc_read,
803: #ifdef RTC_IRQ
804: .poll = rtc_poll,
805: #endif
806: .unlocked_ioctl = rtc_ioctl,
807: .open = rtc_open,
808: .release = rtc_release,
809: .fasync = rtc_fasync,
810: };
811:
812: static struct miscdevice rtc_dev = {
813: .minor = RTC_MINOR,
814: .name = "rtc",
815: .fops = &rtc_fops,
816: };
843: static int __init rtc_init(void)
844: {
...
947: if (misc_register(&rtc_dev)) {
..
953: rtc_release_region();
954: return -ENODEV;
955: }
...
1021: (void) init_sysctl();
1022:
1023: printk(KERN_INFO "Real Time Clock Driver v" RTC_VERSION "\n");
1024:
1025: return 0;
1026: }
linux-5.4.7/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-5.4.7/include/linux/miscdevice.h
15: #define PSMOUSE_MINOR 1
16: #define MS_BUSMOUSE_MINOR 2 /* unused */
...
27: #define RTC_MINOR 135
...
60: #define RFKILL_MINOR 242
61: #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
#
2020年
coins で動いている Linux では、別のドライバが動いている。
ソースは、drivers/rtc/rtc-cmos.c にある。
$ uname -a
Linux aloe39 4.15.0-72-generic #81-Ubuntu SMP Tue Nov 26 12:20:02 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
$ dmesg | grep Real
$ dmesg | grep cmos
[ 10.595681] rtc_cmos 00:01: RTC can wake from S4
[ 10.596432] rtc_cmos 00:01: rtc core: registered rtc_cmos as rtc0
[ 10.596573] rtc_cmos 00:01: alarms up to one month, y3k, 242 bytes nvram, hpet irqs
[ 10.955369] rtc_cmos 00:01: setting system clock to 2020-01-17 08:19:16 UTC (1579249156)
$
linux-5.4.7/drivers/char/rtc.c
187: static unsigned long rtc_status; /* bitmapped status byte. */
713: static int rtc_open(struct inode *inode, struct file *file)
714: {
715: spin_lock_irq(&rtc_lock);
716:
717: if (rtc_status & RTC_IS_OPEN)
718: goto out_busy;
719:
720: rtc_status |= RTC_IS_OPEN;
...
723: spin_unlock_irq(&rtc_lock);
724: return 0;
725:
726: out_busy:
727: spin_unlock_irq(&rtc_lock);
728: return -EBUSY;
729: }
linux-5.4.7/drivers/char/rtc.c
736: static int rtc_release(struct inode *inode, struct file *file)
737: {
...
766:
767: spin_lock_irq(&rtc_lock);
...
769: rtc_status &= ~RTC_IS_OPEN;
770: spin_unlock_irq(&rtc_lock);
771:
772: return 0;
773: }
rtc_open() で立てた rtc_status の RTC_IS_OPEN ビットは、close() システ
ム・コールで呼ばれる rtc_release() ( struct file_operations rtc_fops の
.release) で、落とされる。
linux-5.4.7/drivers/char/rtc.c
701: static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
702: {
703: long ret;
704: ret = rtc_do_ioctl(cmd, arg, 0);
705: return ret;
706: }
381: static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
382: {
383: struct rtc_time wtime;
...
401: switch (cmd) {
...
463: case RTC_ALM_READ: /* Read the present alarm time */
...
474: case RTC_ALM_SET: /* Store a time into the alarm */
...
523: case RTC_RD_TIME: /* Read the time/date from RTC */
524: {
525: memset(&wtime, 0, sizeof(struct rtc_time));
526: rtc_get_rtc_time(&wtime);
527: break;
528: }
529: case RTC_SET_TIME: /* Set the RTC */
530: {
531: struct rtc_time rtc_tm;
532: unsigned char mon, day, hrs, min, sec, leap_yr;
533: unsigned char save_control, save_freq_select;
534: unsigned int yrs;
...
542: if (copy_from_user(&rtc_tm, (struct rtc_time __user *)arg,
543: sizeof(struct rtc_time)))
544: return -EFAULT;
545:
546: yrs = rtc_tm.tm_year + 1900;
547: mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */
548: day = rtc_tm.tm_mday;
549: hrs = rtc_tm.tm_hour;
550: min = rtc_tm.tm_min;
551: sec = rtc_tm.tm_sec;
552:
553: if (yrs < 1970)
554: return -EINVAL;
555:
556: leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
557:
558: if ((mon > 12) || (day == 0))
559: return -EINVAL;
560:
561: if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
562: return -EINVAL;
563:
564: if ((hrs >= 24) || (min >= 60) || (sec >= 60))
565: return -EINVAL;
566:
567: yrs -= epoch;
568: if (yrs > 255) /* They are unsigned */
569: return -EINVAL;
570:
571: spin_lock_irq(&rtc_lock);
...
614: CMOS_WRITE(yrs, RTC_YEAR);
615: CMOS_WRITE(mon, RTC_MONTH);
616: CMOS_WRITE(day, RTC_DAY_OF_MONTH);
617: CMOS_WRITE(hrs, RTC_HOURS);
618: CMOS_WRITE(min, RTC_MINUTES);
619: CMOS_WRITE(sec, RTC_SECONDS);
...
624: spin_unlock_irq(&rtc_lock);
625: return 0;
626: }
...
694: default:
695: return -ENOTTY;
696: }
697: return copy_to_user((void __user *)arg,
698: &wtime, sizeof wtime) ? -EFAULT : 0;
699: }
カーネル空間とユーザ空間でデータをコピーする時には、次のような特殊な関 数を使う必要がある。
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.4.7/drivers/char/rtc.c
1178: static void rtc_get_rtc_time(struct rtc_time *rtc_tm)
1179: {
...
1206: spin_lock_irqsave(&rtc_lock, flags);
1207: rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
1208: rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
1209: rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
1210: rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
1211: rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
1212: rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
1213: /* Only set from 2.6.16 onwards */
1214: rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK);
...
1220: spin_unlock_irqrestore(&rtc_lock, flags);
...
1240: rtc_tm->tm_year += epoch - 1900;
1241: if (rtc_tm->tm_year <= 69)
1242: rtc_tm->tm_year += 100;
1243:
1244: rtc_tm->tm_mon--;
1245: }
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.4.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-5.4.7/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.4.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
...
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-5.4.7/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-5.4.7/arch/x86/include/asm/io.h
279: #define BUILDIO(bwl, bw, type) \
280: static inline void out##bwl(unsigned type value, int port) \
281: { \
282: asm volatile("out" #bwl " %" #bw "0, %w1" \
283: : : "a"(value), "Nd"(port)); \
284: } \
285: \
286: static inline unsigned type in##bwl(int port) \
287: { \
288: unsigned type value; \
289: asm volatile("in" #bwl " %w1, %" #bw "0" \
290: : "=a"(value) : "Nd"(port)); \
291: return value; \
292: } \
339: BUILDIO(b, b, char)
340: BUILDIO(w, w, short)
341: 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-5.4.7/drivers/char/rtc.c
101: static int rtc_has_irq = 1;
131: static DECLARE_WAIT_QUEUE_HEAD(rtc_wait);
843: static int __init rtc_init(void)
844: {
...
858: irq_handler_t rtc_int_handler_ptr;
...
930: rtc_int_handler_ptr = rtc_interrupt;
...
933: if (request_irq(RTC_IRQ, rtc_int_handler_ptr, 0, "rtc", NULL)) {
934: /* Yeah right, seeing as irq 8 doesn't even hit the bus. */
935: rtc_has_irq = 0;
936: printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ);
937: rtc_release_region();
938:
939: return -EIO;
940: }
...
1025: return 0;
1026: }
227: static irqreturn_t rtc_interrupt(int irq, void *dev_id)
228: {
236: spin_lock(&rtc_lock);
237: rtc_irq_data += 0x100;
238: rtc_irq_data &= ~0xff;
...
247: rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
...
253: spin_unlock(&rtc_lock);
254:
255: wake_up_interruptible(&rtc_wait);
...
259: return IRQ_HANDLED;
260: }
linux-5.4.7/arch/x86/kernel/traps.c
925: void __init trap_init(void)
926: {
..
930: idt_setup_traps();
...
951: }
linux-5.4.7/arch/x86/include/asm/irq_vectors.h
45: #define IA32_SYSCALL_VECTOR 0x80
...
109: #define NR_VECTORS 256
linux-5.4.7/arch/x86/kernel/idt.c
169: gate_desc idt_table[IDT_ENTRIES] __page_aligned_bss;
72: static const __initconst struct idt_data def_idts[] = {
73: INTG(X86_TRAP_DE, divide_error),
74: INTG(X86_TRAP_NMI, nmi),
75: INTG(X86_TRAP_BR, bounds),
76: INTG(X86_TRAP_UD, invalid_op),
77: INTG(X86_TRAP_NM, device_not_available),
...
103: SYSG(IA32_SYSCALL_VECTOR, entry_INT80_32),
105: };
263: void __init idt_setup_traps(void)
264: {
265: idt_setup_from_table(idt_table, def_idts, ARRAY_SIZE(def_idts), true);
266: }
linux-5.4.7/arch/x86/entry/entry_32.S
1352: ENTRY(divide_error)
1353: ASM_CLAC
1354: pushl $0 # no error code
1355: pushl $do_divide_error
1356: jmp common_exception
1357: END(divide_error)
1541: ENTRY(nmi)
...
1570: call do_nmi
...
909: ENTRY(entry_SYSENTER_32)
...
965: call do_fast_syscall_32
...
1104: INTERRUPT_RETURN
linux-5.4.7/arch/x86/include/asm/irqflags.h
155: #define INTERRUPT_RETURN iret
linux-5.4.7/arch/x86/entry/common.c
352: __visible void do_int80_syscall_32(struct pt_regs *regs)
353: {
...
356: do_syscall_32_irqs_on(regs);
357: }
311: static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs)
312: {
...
314: unsigned int nr = (unsigned int)regs->orig_ax;
...
330: if (likely(nr < IA32_NR_syscalls)) {
331: nr = array_index_nospec(nr, IA32_NR_syscalls);
...
341: regs->ax = ia32_sys_call_table[nr](
342: (unsigned int)regs->bx, (unsigned int)regs->cx,
343: (unsigned int)regs->dx, (unsigned int)regs->si,
344: (unsigned int)regs->di, (unsigned int)regs->bp);
...
346: }
...
349: }
linux-5.4.7/arch/x86/include/asm/syscall.h
27: extern const sys_call_ptr_t sys_call_table[];
...
30: #define ia32_sys_call_table sys_call_table
引数には、x86 のレジスタを表現した構造体へのポインタが渡される。これに より、割り込みが発生した時のレジスタの値がわかる。割り込みハンドラが有 効で、割り込み番号に登録されていれば、最終的には、handle_IRQ_event() と いう、CPU とは独立の割り込みハンドラが呼ばれる。
linux-5.4.7/kernel/irq/handle.c
198: irqreturn_t handle_irq_event(struct irq_desc *desc)
199: {
200: irqreturn_t ret;
...
206: ret = handle_irq_event_percpu(desc);
...
211: }
184: irqreturn_t handle_irq_event_percpu(struct irq_desc *desc)
185: {
186: irqreturn_t retval;
...
189: retval = __handle_irq_event_percpu(desc, &flags);
...
195: return retval;
196: }
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;
...
149: res = action->handler(irq, action->dev_id);
...
156: switch (res) {
...
170: case IRQ_HANDLED:
171: *flags |= action->flags;
172: break;
173:
174: default:
175: break;
176: }
177:
178: retval |= res;
179: }
180:
181: return retval;
182: }
linux-5.4.7/kernel/irq/internals.h
163: #define for_each_action_of_desc(desc, act) \
164: 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 day;
outb( /*空欄(a)*/, 0x70 );
day = inb( /*空欄(b)*/ );