kern
changeset 90:7ff2b4971216
started work on the filesystem
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Fri, 09 Dec 2011 13:44:15 +0200 |
parents | 2f555c81ae67 |
children | f83f50c17c3b |
files | fstools/mkfs/Makefile fstools/mkfs/mkfs.c include/kdef.h src/ata.c src/ata.h src/bdev.c src/bdev.h src/file.h src/fs.c src/fs.h src/proc.c src/proc.h src/syscall.c |
diffstat | 13 files changed, 455 insertions(+), 20 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/fstools/mkfs/Makefile Fri Dec 09 13:44:15 2011 +0200 1.3 @@ -0,0 +1,23 @@ 1.4 +ksrc = ../../src 1.5 + 1.6 +obj = mkfs.o fs.o 1.7 +dep = $(obj:.o=.d) 1.8 +bin = mkfs 1.9 + 1.10 +CC = gcc 1.11 +CFLAGS = -pedantic -Wall -g -I$(ksrc) 1.12 + 1.13 +$(bin): $(obj) 1.14 + $(CC) -o $@ $(obj) $(LDFLAGS) 1.15 + 1.16 +-include $(dep) 1.17 + 1.18 +fs.o: $(ksrc)/fs.c 1.19 + $(CC) $(CFLAGS) -c $< -o $@ 1.20 + 1.21 +%.d: %.c 1.22 + @$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@ 1.23 + 1.24 +.PHONY: clean 1.25 +clean: 1.26 + rm -f $(obj) $(bin) $(dep)
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/fstools/mkfs/mkfs.c Fri Dec 09 13:44:15 2011 +0200 2.3 @@ -0,0 +1,147 @@ 2.4 +#include <stdio.h> 2.5 +#include <stdlib.h> 2.6 +#include <string.h> 2.7 +#include <errno.h> 2.8 +#include <inttypes.h> 2.9 +#include <unistd.h> 2.10 +#include <fcntl.h> 2.11 +#include <sys/ioctl.h> 2.12 +#include <sys/stat.h> 2.13 +#ifdef __linux__ 2.14 +#include <linux/fs.h> 2.15 +#endif 2.16 +#ifdef __darwin__ 2.17 +#include <dev/disk.h> 2.18 +#endif 2.19 +#include "fs.h" 2.20 + 2.21 +int mkfs(int fd, int blksize, uint32_t nblocks); 2.22 +uint32_t get_block_count(int fd, int blksize); 2.23 +int user_readblock(int dev, uint32_t blk, void *buf); 2.24 +int user_writeblock(int dev, uint32_t blk, void *buf); 2.25 +int parse_args(int argc, char **argv); 2.26 + 2.27 +int fd; 2.28 +uint32_t num_blocks; 2.29 + 2.30 +int main(int argc, char **argv) 2.31 +{ 2.32 + if(parse_args(argc, argv) == -1) { 2.33 + return 1; 2.34 + } 2.35 + 2.36 + if((num_blocks = get_block_count(fd, BLKSZ)) == 0) { 2.37 + fprintf(stderr, "could not determine the number of blocks\n"); 2.38 + return 1; 2.39 + } 2.40 + printf("total blocks: %u\n", (unsigned int)num_blocks); 2.41 + 2.42 + if(mkfs(fd, num_blocks) == -1) { 2.43 + return 1; 2.44 + } 2.45 + 2.46 + return 0; 2.47 +} 2.48 + 2.49 +int mkfs(int fd, int blksize, uint32_t nblocks) 2.50 +{ 2.51 + struct superblock *sb; 2.52 + 2.53 + if(!(sb = malloc(BLKSZ))) { 2.54 + perror("failed to allocate memory"); 2.55 + return -1; 2.56 + } 2.57 +} 2.58 + 2.59 +uint32_t get_block_count(int fd, int blksize) 2.60 +{ 2.61 + unsigned long sz = 0; 2.62 + uint64_t sz64 = 0; 2.63 + struct stat st; 2.64 + 2.65 +#ifdef BLKGETSIZE64 2.66 + if(ioctl(fd, BLKGETSIZE64, &sz64) != -1) { 2.67 + return sz64 / blksize; 2.68 + } 2.69 +#endif 2.70 + 2.71 +#ifdef BLKGETSIZE 2.72 + if(ioctl(fd, BLKGETSIZE, &sz) != -1) { 2.73 + return sz / (blksize / 512); 2.74 + } 2.75 +#endif 2.76 + 2.77 +#ifdef DKIOCGETBLOCKCOUNT 2.78 + if(ioctl(fd, DKIOCGETBLOCKCOUNT, &sz64) != -1) { 2.79 + return sz64 / (blksize / 512); 2.80 + } 2.81 +#endif 2.82 + 2.83 + if(fstat(fd, &st) != -1 && S_ISREG(st.st_mode)) { 2.84 + return st.st_size / blksize; 2.85 + } 2.86 + 2.87 + return 0; 2.88 +} 2.89 + 2.90 +int user_readblock(int dev, uint32_t blk, void *buf) 2.91 +{ 2.92 + if(lseek(fd, blk * BLKSZ, SEEK_SET) == -1) { 2.93 + return -1; 2.94 + } 2.95 + if(read(fd, buf, BLKSZ) < BLKSZ) { 2.96 + return -1; 2.97 + } 2.98 + return 0; 2.99 +} 2.100 + 2.101 +int user_writeblock(int dev, uint32_t blk, void *buf) 2.102 +{ 2.103 + if(lseek(fd, blk * BLKSZ, SEEK_SET) == -1) { 2.104 + return -1; 2.105 + } 2.106 + if(write(fd, buf, BLKSZ) < BLKSZ) { 2.107 + return -1; 2.108 + } 2.109 + return 0; 2.110 +} 2.111 + 2.112 +int parse_args(int argc, char **argv) 2.113 +{ 2.114 + int i; 2.115 + 2.116 + fd = -1; 2.117 + 2.118 + for(i=1; i<argc; i++) { 2.119 + if(argv[i][0] == '-' && argv[i][2] == 0) { 2.120 + switch(argv[i][1]) { 2.121 + case 'h': 2.122 + printf("usage: %s <device file>\n", argv[0]); 2.123 + exit(0); 2.124 + 2.125 + default: 2.126 + goto invalid; 2.127 + } 2.128 + } else { 2.129 + if(fd != -1) { 2.130 + goto invalid; 2.131 + } 2.132 + 2.133 + if((fd = open(argv[i], O_RDWR)) == -1) { 2.134 + fprintf(stderr, "failed to open %s: %s\n", argv[i], strerror(errno)); 2.135 + return -1; 2.136 + } 2.137 + } 2.138 + } 2.139 + 2.140 + if(fd == -1) { 2.141 + fprintf(stderr, "you must specify a device or image file\n"); 2.142 + return -1; 2.143 + } 2.144 + 2.145 + return 0; 2.146 + 2.147 +invalid: 2.148 + fprintf(stderr, "invalid argument: %s\n", argv[i]); 2.149 + return -1; 2.150 +}
3.1 --- a/include/kdef.h Thu Dec 08 18:19:35 2011 +0200 3.2 +++ b/include/kdef.h Fri Dec 09 13:44:15 2011 +0200 3.3 @@ -32,6 +32,8 @@ 3.4 #define EAGAIN 1 3.5 #define EINVAL 2 3.6 #define ECHILD 3 3.7 + 3.8 +#define EBUG 255 /* not implemented yet */ 3.9 #endif /* errno.h */ 3.10 3.11 3.12 @@ -47,8 +49,16 @@ 3.13 #define SYS_WAITPID 4 3.14 #define SYS_GETPID 5 3.15 #define SYS_GETPPID 6 3.16 +#define SYS_MOUNT 7 3.17 +#define SYS_UMOUNT 8 3.18 +#define SYS_OPEN 9 3.19 +#define SYS_CLOSE 10 3.20 +#define SYS_READ 11 3.21 +#define SYS_WRITE 12 3.22 +#define SYS_LSEEK 13 3.23 3.24 -#define NUM_SYSCALLS 7 3.25 +/* keep this one more than the last syscall */ 3.26 +#define NUM_SYSCALLS 14 3.27 3.28 #endif /* syscall.h */ 3.29
4.1 --- a/src/ata.c Thu Dec 08 18:19:35 2011 +0200 4.2 +++ b/src/ata.c Fri Dec 09 13:44:15 2011 +0200 4.3 @@ -110,6 +110,16 @@ 4.4 return ndev; 4.5 } 4.6 4.7 +uint64_t ata_num_sectors(int devno) 4.8 +{ 4.9 + struct device *dev = devices + devno; 4.10 + 4.11 + if(dev->nsect_lba48) { 4.12 + return dev->nsect_lba48; 4.13 + } 4.14 + return dev->nsect_lba; 4.15 +} 4.16 + 4.17 int ata_read_pio(int devno, uint64_t sect, void *buf) 4.18 { 4.19 return readwrite_pio(devno, sect, buf, read_data);
5.1 --- a/src/ata.h Thu Dec 08 18:19:35 2011 +0200 5.2 +++ b/src/ata.h Fri Dec 09 13:44:15 2011 +0200 5.3 @@ -4,6 +4,7 @@ 5.4 void init_ata(void); 5.5 5.6 int ata_num_devices(void); 5.7 +uint64_t ata_num_sectors(int devno); 5.8 5.9 int ata_read_pio(int devno, uint64_t sect, void *buf); 5.10 int ata_write_pio(int devno, uint64_t sect, void *buf);
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/src/bdev.c Fri Dec 09 13:44:15 2011 +0200 6.3 @@ -0,0 +1,86 @@ 6.4 +#include <stdlib.h> 6.5 +#include <assert.h> 6.6 +#include "bdev.h" 6.7 +#include "ata.h" 6.8 +#include "part.h" 6.9 + 6.10 +#define MINOR_DISK(x) (((x) >> 4) & 0xf) 6.11 +#define MINOR_PART(x) ((x) & 0xf) 6.12 + 6.13 +struct block_device *blk_open(dev_t dev) 6.14 +{ 6.15 + struct block_device *bdev; 6.16 + int i, minor, devno, part; 6.17 + 6.18 + /* XXX for now ignore the major number as we only have ata devices */ 6.19 + minor = DEV_MINOR(dev); 6.20 + devno = MINOR_DISK(minor); 6.21 + part = MINOR_PART(minor); 6.22 + 6.23 + bdev = malloc(sizeof *bdev); 6.24 + assert(bdev); 6.25 + 6.26 + bdev->ata_dev = devno; 6.27 + 6.28 + if(part) { 6.29 + struct partition *plist = get_part_list(devno); 6.30 + assert(plist); 6.31 + 6.32 + for(i=1; i<part; i++) { 6.33 + if(!plist) break; 6.34 + plist = plist->next; 6.35 + } 6.36 + if(!plist) { 6.37 + free(bdev); 6.38 + free_part_list(plist); 6.39 + return 0; 6.40 + } 6.41 + 6.42 + bdev->offset = SECT_TO_BLK(plist->start_sect); 6.43 + bdev->size = SECT_TO_BLK(plist->size_sect); 6.44 + 6.45 + free_part_list(plist); 6.46 + } else { 6.47 + bdev->offset = 0; 6.48 + bdev->size = SECT_TO_BLK(ata_num_sectors(devno)); 6.49 + } 6.50 + 6.51 + return bdev; 6.52 +} 6.53 + 6.54 +void blk_close(struct block_device *bdev) 6.55 +{ 6.56 + free(bdev); 6.57 +} 6.58 + 6.59 +#define NSECT (BLKSZ / 512) 6.60 + 6.61 +int blk_read(struct block_device *bdev, uint32_t blk, void *buf) 6.62 +{ 6.63 + int i; 6.64 + char *ptr = buf; 6.65 + uint32_t sect = blk * NSECT; 6.66 + 6.67 + for(i=0; i<NSECT; i++) { 6.68 + if(ata_read_pio(bdev->ata_dev, sect++, ptr) == -1) { 6.69 + return -1; 6.70 + } 6.71 + ptr += 512; 6.72 + } 6.73 + return 0; 6.74 +} 6.75 + 6.76 +int blk_write(struct block_device *bdev, uint32_t blk, void *buf) 6.77 +{ 6.78 + int i; 6.79 + char *ptr = buf; 6.80 + uint32_t sect = blk * NSECT; 6.81 + 6.82 + for(i=0; i<NSECT; i++) { 6.83 + if(ata_write_pio(bdev->ata_dev, sect++, ptr) == -1) { 6.84 + return -1; 6.85 + } 6.86 + ptr += 512; 6.87 + } 6.88 + return 0; 6.89 +}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/src/bdev.h Fri Dec 09 13:44:15 2011 +0200 7.3 @@ -0,0 +1,19 @@ 7.4 +#ifndef BDEV_H_ 7.5 +#define BDEV_H_ 7.6 + 7.7 +#include "fs.h" /* for dev_t */ 7.8 + 7.9 +/* TODO buffer cache */ 7.10 + 7.11 +struct block_device { 7.12 + int ata_dev; 7.13 + uint32_t offset, size; 7.14 +}; 7.15 + 7.16 +struct block_device *blk_open(dev_t dev); 7.17 +void blk_close(struct block_device *bdev); 7.18 + 7.19 +int blk_read(struct block_device *bdev, uint32_t blk, void *buf); 7.20 +int blk_write(struct block_device *bdev, uint32_t blk, void *buf); 7.21 + 7.22 +#endif /* BDEV_H_ */
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/src/file.h Fri Dec 09 13:44:15 2011 +0200 8.3 @@ -0,0 +1,11 @@ 8.4 +#ifndef FILE_H_ 8.5 +#define FILE_H_ 8.6 + 8.7 +#include "fs.h" 8.8 + 8.9 +struct file { 8.10 + struct inode *inode; 8.11 + long ptr; 8.12 +}; 8.13 + 8.14 +#endif /* FILE_H_ */
9.1 --- a/src/fs.c Thu Dec 08 18:19:35 2011 +0200 9.2 +++ b/src/fs.c Fri Dec 09 13:44:15 2011 +0200 9.3 @@ -1,48 +1,61 @@ 9.4 +/* This code is used by the kernel AND by userspace filesystem-related tools. 9.5 + * The kernel-specific parts are conditionally compiled in #ifdef KERNEL blocks 9.6 + * the rest of the code should be independent. 9.7 + */ 9.8 #include <stdio.h> 9.9 #include <stdlib.h> 9.10 #include <assert.h> 9.11 +#include <errno.h> 9.12 #include "fs.h" 9.13 +#include "part.h" 9.14 + 9.15 +#ifdef KERNEL 9.16 #include "ata.h" 9.17 -#include "part.h" 9.18 #include "panic.h" 9.19 - 9.20 -#define MAGIC 0xccf5ccf5 9.21 -#define BLKSZ 1024 9.22 - 9.23 -typedef uint32_t blkid; 9.24 - 9.25 -struct superblock { 9.26 - uint32_t magic; 9.27 - 9.28 - blkid istart; 9.29 - unsigned int icount; 9.30 - 9.31 - blkid dstart; 9.32 - unsigned int dcount; 9.33 -}; 9.34 +#endif 9.35 9.36 struct filesys { 9.37 int dev; 9.38 struct partition part; 9.39 9.40 struct superblock *sb; 9.41 + 9.42 + struct filesys *next; 9.43 }; 9.44 9.45 static int find_rootfs(struct filesys *fs); 9.46 +static int readblock(int dev, uint32_t blk, void *buf); 9.47 +static int writeblock(int dev, uint32_t blk, void *buf); 9.48 9.49 /* root device & partition */ 9.50 -static struct filesys root; 9.51 +static struct filesys *fslist; 9.52 + 9.53 +int sys_mount(char *mtpt, char *devname, unsigned int flags) 9.54 +{ 9.55 + if(strcmp(mtpt, "/") != 0) { 9.56 + printf("mount: only root can be mounted at the moment\n"); 9.57 + return -EBUG; 9.58 + } 9.59 + 9.60 + /* mounting root filesystem */ 9.61 + if(fslist) { 9.62 + 9.63 +} 9.64 9.65 void init_fs(void) 9.66 { 9.67 root.sb = malloc(512); 9.68 assert(root.sb); 9.69 9.70 +#ifdef KERNEL 9.71 if(find_rootfs(&root) == -1) { 9.72 panic("can't find root filesystem\n"); 9.73 } 9.74 +#endif 9.75 } 9.76 9.77 + 9.78 +#ifdef KERNEL 9.79 #define PART_TYPE 0xcc 9.80 static int find_rootfs(struct filesys *fs) 9.81 { 9.82 @@ -59,7 +72,7 @@ 9.83 /* found the correct partition, now read the superblock 9.84 * and make sure it's got the correct magic id 9.85 */ 9.86 - ata_read_pio(i, p->start_sect + 2, fs->sb); 9.87 + readblock(i, p->start_sect / 2 + 1, fs->sb); 9.88 9.89 if(fs->sb->magic == MAGIC) { 9.90 printf("found root ata%dp%d\n", i, partid); 9.91 @@ -75,3 +88,33 @@ 9.92 } 9.93 return -1; 9.94 } 9.95 + 9.96 +#define NSECT (BLKSZ / 512) 9.97 + 9.98 +static int readblock(struct block_device *bdev, uint32_t blk, void *buf) 9.99 +{ 9.100 + return blk_read(bdev, blk, buf); 9.101 +} 9.102 + 9.103 +static int writeblock(struct block_device *bdev, uint32_t blk, void *buf) 9.104 +{ 9.105 + return blk_write(bdev, blk, buf); 9.106 +} 9.107 +#else 9.108 + 9.109 +/* if this is compiled as part of the user-space tools instead of the kernel 9.110 + * forward the call to a user read/write block function supplied by the app. 9.111 + */ 9.112 +int user_readblock(uint32_t, void*); 9.113 +int user_writeblock(uint32_t, void*); 9.114 + 9.115 +static int readblock(struct block_device *bdev, uint32_t blk, void *buf) 9.116 +{ 9.117 + return user_readblock(blk, buf); 9.118 +} 9.119 + 9.120 +static int writeblock(struct block_device *bdev, uint32_t blk, void *buf) 9.121 +{ 9.122 + return user_writeblock(blk, buf); 9.123 +} 9.124 +#endif /* KERNEL */
10.1 --- a/src/fs.h Thu Dec 08 18:19:35 2011 +0200 10.2 +++ b/src/fs.h Fri Dec 09 13:44:15 2011 +0200 10.3 @@ -1,7 +1,75 @@ 10.4 #ifndef FS_H_ 10.5 #define FS_H_ 10.6 10.7 -void init_fs(void); 10.8 +#include <inttypes.h> 10.9 + 10.10 +#define MAGIC 0xccf5ccf5 10.11 +#define BLKSZ 1024 10.12 + 10.13 +#define SECT_TO_BLK(x) ((x) / (BLKSZ / 512)) 10.14 + 10.15 +#define DEV_MAJOR(dev) (((dev) >> 8) & 0xff) 10.16 +#define DEV_MINOR(dev) ((dev) & 0xff) 10.17 + 10.18 + 10.19 +typedef uint32_t dev_t; 10.20 +typedef uint32_t blkid; 10.21 + 10.22 +struct superblock { 10.23 + uint32_t magic; /* magic number */ 10.24 + int ver; /* filesystem version */ 10.25 + int blksize; /* only BLKSZ supported at the moment */ 10.26 + 10.27 + /* total number of blocks */ 10.28 + unsigned int num_blocks; 10.29 + /* inode allocation bitmap start and count */ 10.30 + blkid ibm_start; 10.31 + unsigned int ibm_count; 10.32 + /* inode table start and count */ 10.33 + blkid itbl_start; 10.34 + unsigned int itbl_count; 10.35 + /* data block allocation bitmap start and count */ 10.36 + blkid dbm_start; 10.37 + unsigned int dbm_count; 10.38 + /* data blocks start and count */ 10.39 + blkid data_start; 10.40 + unsigned int data_count; 10.41 + 10.42 + int root_ino; /* root direcotry inode */ 10.43 + 10.44 + /* the following are valid only at runtime, ignored on disk */ 10.45 + uint32_t *ibm; /* memory inode bitmap */ 10.46 + uint32_t *dbm; /* memory datablock bitmap */ 10.47 + 10.48 +} __attribute__((packed)); 10.49 + 10.50 + 10.51 +/* 20 direct blocks + 10 attributes + 2 indirect = 128 bytes per inode */ 10.52 +#define NDIRBLK 20 10.53 +struct inode { 10.54 + int ino; 10.55 + int uid, gid, mode; 10.56 + int nlink; 10.57 + dev_t dev; 10.58 + uint32_t atime, ctime, mtime; 10.59 + uint32_t size; 10.60 + blkid blk[NDIRBLK]; /* direct blocks */ 10.61 + blkid ind; /* indirect */ 10.62 + blkid dind; /* double-indirect */ 10.63 +} __attribute__((packed)); 10.64 + 10.65 + 10.66 +int sys_mount(char *mntpt, char *devname, unsigned int flags); 10.67 +int sys_umount(char *devname); 10.68 + 10.69 +int sys_open(char *pathname, int flags, unsigned int mode); 10.70 +int sys_close(int fd); 10.71 + 10.72 +int sys_read(int fd, void *buf, int sz); 10.73 +int sys_write(int fd, void *buf, int sz); 10.74 +long sys_lseek(int fd, long offs, int from); 10.75 + 10.76 +int lookup_path(const char *path); 10.77 10.78 10.79 #endif /* FS_H_ */
11.1 --- a/src/proc.c Thu Dec 08 18:19:35 2011 +0200 11.2 +++ b/src/proc.c Fri Dec 09 13:44:15 2011 +0200 11.3 @@ -165,6 +165,9 @@ 11.4 p = proc + pid; 11.5 parent = get_current_proc(); 11.6 11.7 + /* copy file table */ 11.8 + memcpy(p->files, parent->files, sizeof p->files); 11.9 + 11.10 /* allocate a kernel stack for the new process */ 11.11 if((p->kern_stack_pg = pgalloc(KERN_STACK_SIZE / PGSIZE, MEM_KERNEL)) == -1) { 11.12 return -EAGAIN;
12.1 --- a/src/proc.h Thu Dec 08 18:19:35 2011 +0200 12.2 +++ b/src/proc.h Fri Dec 09 13:44:15 2011 +0200 12.3 @@ -4,8 +4,10 @@ 12.4 #include <inttypes.h> 12.5 #include "asmops.h" 12.6 #include "rbtree.h" 12.7 +#include "file.h" 12.8 12.9 #define MAX_PROC 128 12.10 +#define MAX_FD 64 12.11 12.12 struct context { 12.13 /*struct registers regs;*/ /* saved general purpose registers */ 12.14 @@ -46,6 +48,9 @@ 12.15 12.16 struct context ctx; 12.17 12.18 + /* open files */ 12.19 + struct file files[MAX_FD]; 12.20 + 12.21 struct process *child_list; 12.22 12.23 struct process *next, *prev; /* for the scheduler queues */
13.1 --- a/src/syscall.c Thu Dec 08 18:19:35 2011 +0200 13.2 +++ b/src/syscall.c Fri Dec 09 13:44:15 2011 +0200 13.3 @@ -4,6 +4,7 @@ 13.4 #include "proc.h" 13.5 #include "sched.h" 13.6 #include "timer.h" 13.7 +#include "fs.h" 13.8 13.9 static int (*sys_func[NUM_SYSCALLS])(); 13.10 13.11 @@ -21,6 +22,14 @@ 13.12 sys_func[SYS_GETPID] = sys_getpid; /* proc.c */ 13.13 sys_func[SYS_GETPPID] = sys_getppid; /* proc.c */ 13.14 13.15 + sys_func[SYS_MOUNT] = sys_mount; /* fs.c */ 13.16 + sys_func[SYS_UMOUNT] = sys_umount; /* fs.c */ 13.17 + sys_func[SYS_OPEN] = sys_open; /* fs.c */ 13.18 + sys_func[SYS_CLOSE] = sys_close; /* fs.c */ 13.19 + sys_func[SYS_READ] = sys_read; /* fs.c */ 13.20 + sys_func[SYS_WRITE] = sys_write; /* fs.c */ 13.21 + sys_func[SYS_LSEEK] = sys_lseek; /* fs.c */ 13.22 + 13.23 interrupt(SYSCALL_INT, syscall); 13.24 } 13.25