[
  {
    "path": ".gitignore",
    "content": "*.o\n/fiwix\nSystem.map.gz\ninclude/fiwix/custom_config.h\ninclude/fiwix/custom_limits.h\ninclude/fiwix/custom_kernel.h\ninclude/fiwix/custom_system.h\n"
  },
  {
    "path": "CODING",
    "content": "Fiwix kernel coding standards\n-------------------------------------------------------------------------------\nIt's easier on everyone if all authors working on a shared code base are\nconsistent in the way they write their programs. Fiwix has the following\nconventions in its code:\n\n- Keep lines length to a maximum of 80 characters (some exceptions accepted).\n\n- Use of snake_case (multi-word names are lower_case_with_underscores) for\n  everything except for macro in #define directives.\n\n- No space after the name of a function in a call.\n  For example, printk(\"hello\") not printk (\"hello\").\n\n- Optional space after keywords \"if\", \"for\", \"while\", \"switch\".\n  For example, if(x) or if (x).\n\n- Space before braces (except in function declarations).\n  For example, if(x) { not if(x){.\n\n- Space between operands.\n  For example, for(n = 0; n < 10; n++), not for(n=0;n<10;n++).\n\n- Beginning-of-line indentation via tabs, not spaces.\n\n- Preprocessor macros are always UPPERCASE.\n\n- Pointer types have spaces: (uint16_t *), not (uint16_t*).\n\n- The pointer qualifier, '*', should be with the variable name rather than with\n  the type.\n\n- Comments in code are always in C-Style (as in C89) /* ... */.\n\n- Only the comments that span multiple lines start always with a capital letter\n  and the last sentence ends with a period. Also the open and close tags must go\n  in separate lines. Just like this:\n  /*\n   * Comment line 1\n   * comment line 2\n   * comment line 3.\n   */\n\n- Comments in a single line must not start with a capital letter and must not\n  end with a period.\n\n- Functions that take no arguments are declared as f(void), not f().\n\n- The open parenthesis is always on the same line as the function name.\n\n- There is never a space between the function name and the open parenthesis.\n\n- There is never a space between the parentheses and the parameters.\n\n- The open curly brace is always at the next line of the function declaration.\n\n- Conditionals should always include curly braces, even if there is only a\n  single statement within the conditional.\n\n- The parameters in function prototypes don't need to have a name to reference\n  them by.\n\n- Case statements should be indented one from switch keyword indentation.\n\nRecommended for reading\n-------------------------------------------------------------------------------\n- http://skull.piratehaven.org/~bapper/298c/cstyle.html\n\n"
  },
  {
    "path": "Changes",
    "content": "1.8.0 - DD-MMM-2026\n===================\n- Added generic PCI Bus-Master DMA support on ATA disks.\n- Added support for tilde dead key. [#102]\n- Added the 'flags' entry in the 'kernel_params' structure to group all toggle-\n  type parameters.\n- Added the new kernel parameter 'ide_nodma' to disable DMA in all ATA drives.\n- Added support to be able to right-justify strings in printk().\n- Added support for some new functions in lib/string.c.\n- Changed the 'ps2_noreset' to a toggle parameter.\n- Changed the way how device drivers find PCI-type devices.\n- Moved ipc_init() and net_init() initialization into kswpad() to make sure the\n  'current' process stucture is completely setup.\n- Removed the file CREDITS because the LICENSE file already contains the list of\n  contributors.\n- Removed the configuration option CONFIG_LAZY_USER_ADDR_CHECK.\n- Reimplemented atoi() to rely on strtol().\n- Fixed the ATA disk initialitzation to reduce the number of messages like\n  'unexpected interrupt'.\n- Fixed the DMA functionality in ATA disks to use UDMA since the support for the\n  Multiword DMA is not always assured in all cases.\n- Fixed ata_hd_init() to preserve the current value of Status in Bus-Master\n  register while setting DMA.\n- Fixed ata_setup_dma() and ata_start_dma() to preserve the current register\n  status before writing a new value.\n- Fixed to save the BIOS Data Area (256 bytes) to prevent it from being\n  clobbered by the early use of the first memory page.\n- Fixed dump_registers() to be able to show the registres on an early kernel\n  panic.\n- Fixed wakeup() to avoid flagging 'need_resched' on every iteration and thus\n  saving extra context switchings.\n- Fixed ps2_init() to no use anymore the command 0xCA (to get the current\n  interface) as it is not an standardized command.\n- Fixed the start_code and end_code values in '/proc/<PID>/stat' file.\n- Fixed a bad vma address calculation in verify_address().\n- Fixed verify_address() to not verify pointer addresses when calling system\n  calls from the kernel.\n- Fixed strncmp() to actually compare only the first (at most) n bytes of str1\n  and str2.\n- Fixed the inode count in mmap() functions.\n- Fixed a possible infinite loop in do_munmap().\n- Small fixes and improvements, code cleanup and cosmetic changes.\n\n\n1.7.0 - 15-Nov-2025\n===================\n- Added support for UNIX98 pseudoterminals (pty).\n- Added support for the devpts filesystem.\n- Added support for system logging via sys_syslog() and /proc/kmsg.\n- Added the member s_blocksize_bits in the superblock struct to use bitwise\n  shift instead of division in ext2_bmap() and ext2_truncate().\n- Added the RSS column in the list of processes generated by the Magic SysRq\n  key 't'.\n- Added the 'fd' structure as a new argument in ioctl() and select() methods.\n- Added a free data pointer called 'private_data', in 'fd' structure, which is\n  mostly used by the tty driver for now.\n- Added support for the command TIOCINQ in tty_ioctl().\n- Added the new kernel parameter 'ps2_noreset=' (which defaults to 0, disabled)\n  to avoid reseting the PS/2 controller (specially useful on systems that don't\n  has any PS/2 controller.\n- Added support for the '/proc/pci/ and '/proc/bus/pci/devices' files.\n- Added the support for the ioctls BLKSSZGET and BLKBSZGET on ATA and floppy\n  drivers, and also added the missing BLKFLSBUF to the floppy driver.\n- Changed modulo operations by bitwise (where possible) to reduce dependency\n  from libgcc.\n- Changed static array tty_table to dynamic.\n- Rewritten mostly the PCI driver.\n- Removed some flags from LDFLAGS in the main Makefile that prevented compile\n  the kernel with newer GCC versions. [#97]\n- Removed the dir_write method from the ext2 and minix filesystems.\n- Removed a condition in do_sched() because it has no effect.\n- Removed an unneeded assignment to need_resched in do_exit() and reduced the\n  abuse of using need_resched because it costs excessive context switches.\n- Renamed the functions *_dir_readdir() and *_dir_readdir64() to *_readdir()\n  and *_readdir64().\n- Renamed all *fd_table function arguments to avoid shadowing the global\n  fd_table array.\n- Simplified a do.while() in reclaim_siblings() also with small improvements in\n  reclaim_buffers().\n- Reverted 49393d0 and fixed 'memksize' in all cases to be able to boot again on\n  systems with 4MiB of memory.\n- Reverted 39c0097 because an existing bug prevents a complete installation on\n  systems with less than 64MiB of memory.\n- Update LICENSE file with additional contributor information.\n- Fixed ext2_balloc() and ext2_ialloc() to return -ENOSPC when there is not\n  space on device.\n- Fixed fs.h to include fd.h when CONFIG_NET is not set.\n- Fixed some kernel crashes with the message 'WARNING: page_head returned NULL!\n  (free_pages = 0)' when using a RAMdisk drive as the root filesystem. [#98]\n- Fixed ext2_file_write() to avoid to brelse() a NULL buffer. [#98]\n- Fixed sys_open() to catch early an attempt to write on a directory.\n- Fixed to add some missing iput() in procfs_lookup() and procfs_followlink().\n- Fixed sys_mount() to also save the mount point for nodev filesystems.\n- Fixed an unintended fall-through in set_color() of fbcon.c.\n- Fixed a long standing bug in send_sig() that missed to add SIGCONT, SIGWINCH\n  and SIGUSR to the list of signals to ignore when the disposition is set to\n  SIG_DFL.\n- Fixed an always true comparison in get_procfs_by_inode().\n- Fixed a long standing bug in sys_kill() that prevented from sending the signal\n  zero.\n- Fixed a long standing bug in sys_select() that returned always -EBADF when\n  'nfds' is equal to FD_SETSIZE.\n- Fixed a long standing bug in tty_read() that always returned VMIN bytes\n  regardless of the amount of data available.\n- Fixed a possible null pointer dereference in proc_list().\n- Fixed a long standing bug in sys_select() that didn't return -EINTR if it was\n  interrupted by a signal.\n- Fixed sys_fork() to share the remaining CPU time of the parent with the new\n  child.\n- Fixed to avoid a division by zero in SLEEP_HASH() macro when NR_PROCS is less\n  than 10.\n- Fixed a long standing bug in data_proc_pid_cmdline() and\n  data_proc_pid_environ() functions that led to the kernel panic.\n- Fixed an accidental fall through in opost().\n- Fixed a missing iput() when freeing or merging a vma region.\n- Fixed get_free_buffer() to not create new buffers if free memory pages are\n  lower than minimal.\n- Fixed inefficient code by reducing excessive calls to wakeup(&buffer_wait) in\n  fs/buffer.c.\n- Fixed a bug in sys_open() that allowed to create a file on a read-only\n  filesystem.\n- Small fixes, code cleanup and cosmetic changes.\n\n\n1.6.0 - 15-Nov-2024\n===================\n- Added support for UNIX-domain sockets (with the Berkeley socket API). [#36]\n- Added support for sys_truncate64, sys_ftruncate64, sys_stat64, sys_lstat64,\n  sys_fstat64 and sys_fcntl64 system calls. [#49]\n- Added support for sys_getdents64. [#51]\n- Added support for sys_chown32. [#53]\n- Added support for sys_utimes. [#57]\n- Added support for building Fiwix with the TCC compiler. [#63]\n- Added support for the Linux boot protocol in kexec. [#65]\n- Added support for the PS/2 mouse with the new device /dev/psaux. [#94]\n- Added the new configuration option PAGE_HASH_PERCENTAGE (0.1% by default) to\n  set the size of the page_hash_table relative to the number of physical memory\n  pages, with a mininum of 1 page and a maximum of 16 pages. The kernel now\n  shows the hash tables sizes during the boot.\n- Added to sync drives when kernel stops because no more user processes exist.\n  [#70]\n- Added the flag PF_NOTINTERRUPT to avoid waking up a process sleeping in the\n  non-interruptible mode.\n- Added a consistency check on every directory entry during ext2_lookup().\n- Added a call to invalidate_buffers() before reread the partition table in the\n  ioctl BLKRRPART.\n- Rewritten how multiple I/O block requests are managed. Now the new I/O block\n  layer enqueues a block request group with all the buffers needed in a read or\n  write operation, and keeps sleeping until the whole transaction has been\n  completed. This improves dramatically the disk accesses, reduces a lot the\n  number of context switches, and it overall boosts the performance of the\n  system.\n- Changed the file position for reads to be set to zero when a file is opened\n  with O_APPEND. [#76]\n- Implement mapping framebuffer physical address to user space using mmap. [#79]\n- Changed the inode cache mechanism to avoid caching inodes from\n  pseudo-filesystems.\n- Changed count_active_procs() to also count processes that are sleeping as\n  non-interruptible.\n- Changed the tty sleeping address to be process specific in order to reduce\n  the wakeup latency.\n- Moved the values sb->dirty, inode->locked and inode->dirty to flags.\n- Moved the call to sysrq() into the keyboard interrupt bottom half.\n- Improved code compaction and efficiency in ATA disk read/write.\n- Improved the efficiency of the buffer cache.\n- Improved ext2_file_write() to use a multiblock request with gbread() when the\n  count is greater than the blocksize.\n- Reorganized and improved the system console related code.\n- Pass through 64-bit PAE memory entries as part of kexec. [#67]\n- Make sure that the early system log will be shown in all system consoles.\n- Removed unneeded low memory kernel virtual address mappings. [#88]\n- Reduced a number of functions in the timer interrupt by moving them to the\n  bottom half.\n- Reorganized the code of the keyboard driver.\n- Renamed and reorganized tty_queue into charq to make it more generic.\n- Fixed sys_mount() to avoid mounting a device already mounted.\n- Fixed compilation errors when CONFIG_PCI is not defined.\n- Fixed to allow removing a directory in use. [#59]\n- Fixed in sys_getcwd() to check 'diff_dev' variable before accessing\n  'tmp_inode'. [#61]\n- Fixed vconsole_select() to not switch to an unexistent vconsole.\n- Fixed ata_hd_init() to make sure that the command SET_FEATURES is sent in all\n  cases.\n- Fixed the kernel stack backtrace to skip the first 5 stack values.\n- Fixed an scrolling bug with 'vi' in fbcon_scroll_screen(). [#81]\n- Fixed UNIX sockets working with select(). [#83]\n- Fixed serial system console table overindex. [#87]\n- Fixed a major problem in do_switch routine. [#89]\n- Fixed incorrect passing of e820 memory map to Linux kexec guests. [#72]\n- Fixed EXT2_DESC_PER_BLOCK() to avoid redundant calculations.\n- Fixed kswapd() to enable interrupts after initializing devices.\n- Fixed a long standing bug during bitmap calculation in the ext2 filesystem.\n- Fixed CHECK_IF_NESTED_INTERRUPT by comparing KERNEL_CS against CS.\n- Fixed a kernel crash on boot when PCI is disabled and the kernel parameter\n  'bga=' is supplied.\n- Fixed sleep() to avoid race conditions by executing CLI() earlier.\n- Fixed a bug introduced in 4317cbe that prevented from continuing to the next\n  running process in stop_kernel().\n- Fixed read_msdos_partition() to use the default device block size instead of\n  BLKSIZE_1K.\n- Fixed to flag the superblock as dirty in ext2_ialloc(), ext2_ifree(),\n  ext2_balloc() and ext2_bfree().\n- Fixed fbcon_blank_screen() to not show cursor. [#94]\n- Fixed a lack of schedule randomization introduced in b935b3d.\n- Fixed reclaim_buffers() to run with interrupts enabled.\n- Fixed to initialize the new vma struct in merge_vma_regions().\n- Fixed to reset the flag before calling some functions to avoid reentrancy\n  in irq_keyboard_bh().\n- Fixed a long standing bug in vconsole_select() that prevented from switching\n  between consoles in VT_PROCESS mode.\n- Fixed permissions in the ioctl VT_WAITACTIVE.\n- Fixed a long standing bug in wakeup() that put as running one in two processes\n  sleeping, leading to frequent cases where some processes keep sleeping.\n- Small fixes and cosmetic changes.\n\n\n1.5.0 - 15-Nov-2023\n===================\n- Added a kernel memory allocator that uses the buddy algorithm to manage\n  requests smaller than PAGE_SIZE (4KiB).\n- Added the new file /proc/buddyinfo to view buddy algorithm statistics.\n- Added the new configuration option FREE_PAGES_RATIO (with a default value of\n  5), as the minimum percentage of free memory pages before calling the swapper\n  to reclaim memory from the buffer cache.\n- Added the buffer-dirty-flush kernel daemon 'kbdflushd'. This also includes the\n  new configuration option BUFFER_DIRTY_RATIO to limit the percentage of dirty\n  buffers.\n- Added the new file '/proc/sys/vm/dirty_background_ratio' to show the current\n  value of the option BUFFER_DIRTY_RATIO.\n- Added support for the Bochs Graphics Adapter with the configuration option\n  CONFIG_BGA, and introducing the new kernel parameter 'bga=' to set the screen\n  resolution (width x height x bpp). Refer to 'docs/kernel-parameters.txt' to\n  know all the screen resolutions supported.\n- Added 32bit I/O transfers support to the ATA/ATAPI driver.\n- Added DMA (Multi-word) transfers support to the ATA disk driver.\n- Added overall improvements in the ATA disk driver.\n- Added a check in psig() to terminate the process if it doesn't have the stack\n  region in its vma table.\n- Added PCI BARs handling in the serial driver.\n- Added the files 'buffer_max' and 'buffer_nr' in '/proc/sys/kernel/'.\n- Added more checks on data received during ATA drive identify to make sure it\n  makes sense.\n- Added the magic SysRq key 'm' to show current memory information.\n- Added the Multiboot magic value as a new parameter in get_last_boot_addr() to\n  avoid a kernel panic when it is booted without the Multiboot structure.\n- Added a check if flag MULTIBOOT_INFO_ELF_SHDR is set before reading the ELF\n  section header table to avoid possible kernel panics.\n- Added support in parse_cmdline() to recognize values enclosed in double\n  quotes.\n- Added support for multiple RAMdisk drives.\n- Added kexec implementation (see 'docs/kexec.txt') which introduces the new\n  configuration option CONFIG_KEXEC (disabled by default).\n- Added microsecond resolution to sys_gettimeofday().\n- Added the /proc/<PID>/fd/ subdirectory containing symbolic links named by its\n  file descriptor.\n- Added support for 64bit offsets and introduced the new option CONFIG_OFFSET64\n  (enabled by default).\n- Added the linkage of libgcc into the kernel in order to have functions like\n  __divdi3() and friends, necessary when doing certain arithmetic operations\n  with 64bit offsets on an i386 architecture.\n- Added support for the O_DIRECTORY flag to sys_open(). [#32]\n- Added support for the virtual memory split 2GiB(user)/2GiB(kernel), by\n  introducing the new option CONFIG_VM_SPLIT22 (disabled by default). [#34]\n- Added support for large initrd images (see 'docs/initrd.txt'). [#34]\n- Added the ability to have different blksize values for each device minor.\n- Added the new system call sys_lchown by renaming the old sys_chown (number 16)\n  to sys_lchown, and creating the new sys_chown (number 182) which will follow\n  (dereference) symbolic links. This might break the compatibility with Linux\n  2.0 ABI.\n- Added support for F_DUPFD_CLOEXEC in sys/fcntl.h. [#40]\n- Added support for sys_readv() and sys_writev() system calls. [#42]\n- Added support for sys_mmap2() system call. [#47]\n- Added the length modifier 'l' for long long int arguments in printk().\n- Changed the mode how the kernel mounts the root filesystem. From now on, it\n  will be mounted in read/write mode by default. This introduces the new kernel\n  parameter 'ro' to force to mount it in read-only mode.\n- Changed the vma table from static to dynamically allocated array and removed\n  the option VMA_REGIONS.\n- Changed lots of fixed-size arrays to dynamically allocated arrays.\n- Changed malloc_name() and free_name() to use the new memory allocator.\n- Changed do_namei() to use the new memory allocator.\n- Changed the generic llseek() method to support 64bit offsets.\n- Changed the location of the kernel stack address to be right after the BSS\n  section. [#34]\n- Rewritten reclaim_buffers() to be more efficient and also to free up unused\n  buffers and shrink the buffer table.\n- Modified the Makefile to disable compiling with PIE option enabled by some\n  builds of GCC. [#6]\n- Reverted 40bf18b because some signals weren't caugth and created malfunction\n  in cron jobs.\n- Reverted 082b316 as it created a kernel panic when using IPC shared memory.\n- Reverted ad3fc56 so malloc_name() and free_name() will always request\n  PAGE_SIZE bytes. This is more efficient as it helped to remove the call to\n  strlen() and even can return now a proper ENAMETOOLONG error.\n- Disabled interrupts in runnable() and not_runnable() to avoid race conditions.\n- Removed the option RAMDISK_MAXSIZE from the RAMdisk drives.\n- Bar addresses of PCI devices are now discovered by the driver.\n- Reorganized _init() functions in start_kernel().\n- Disk drives now show the ATA major version number.\n- Reorganized the steps to do on a page fault in kernel mode.\n- The kernel parameter 'ramdisksize=' no longer controls the size of the initrd\n  image. [#34]\n- The build of the Minix filesystem depends on the new option CONFIG_FS_MINIX\n  (disabled by default).\n- Fixed a bug in syscalls/wait4.c introduced in 9cfe372 that created malfunction\n  in control jobs.\n- Fixed to call sleep_init(), buffer_init(), sched_init() and inode_init()\n  before initializing devices.\n- Fixed the offset value in elf_load_interpreter() and elf_load().\n- Fixed in pci_add_device() to use pci_read_short() instead of pci_read_char()\n  for Command and Status registers.\n- Fixed in do_execve() to reuse tmp_name allocated in sys_execve().\n- Fixed a number of common variable definitions that prevented from build Fiwix\n  with the newest GCC cross-compiler. [#10]\n- Fixed in fs/namei.c to return ENOENT for missing directory. [#12]\n- Fixed a bug in ext2_bmap() that prevented large files from persist on an ext2\n  filesystem. [#14]\n- Fixed a bug in v2_minix_bmap() that prevented large files from persist on a\n  minix v2 filesystem. [#14]\n- Fixed do_page_fault() to handle better a faulty address outside the user\n  address space in kernel mode.\n- Fixed the I/O address size in the ISA serial driver.\n- Fixed a missing iput() in ext2_followlink() when there are too many nested\n  symbolic links.\n- Fixed a missing iput() in minix_followlink() when there are too many nested\n  symbolic links.\n- Fixed the hexadecimal values of /dev/tty10, /dev/tty11 and /dev/tty12 in\n  kparms.h.\n- Fixed some possible race conditions in buffer cache.\n- Fixed a bug in mmap that prevented overlapped VMA regions from merging\n  correctly. [#16]\n- Fixed to terminate properly a read or write request on hdd timeout.\n- Fixed a race condition in sys_nanosleep() when setting the processs sleeping\n  time.\n- Fixed merge_vma_regions() to free memory pages in overlapped segments. [#16]\n- Fixed memory mapped files not written to disk correctly. [#18]\n- Fixed sys_execve() to make sure arguments and environment do not exceed the\n  maximum length. [#20]\n- Fixed sys_mount() to use malloc_name() and free_name() to validate the\n  argument 'fstype'.\n- Fixed do_page_fault() to handle a page fault when trying to access a\n  non-existent user stack address in kernel mode when\n  CONFIG_LAZY_USER_ADDR_CHECK is enabled. [#22]\n- Fixed verify_address() to accept a possible non-existent user stack address\n  when CONFIG_LAZY_USER_ADDR_CHECK is disabled, since do_page_fault() will do\n  the rest of the job. [#22]\n- Fixed the logic in parse_arg() to support kernel parameters without arguments.\n- Fixed a long standing bug where after removing an inode there was not a call\n  to invalidate all its pages from the cache. [#24]\n- Fixed a missing initialization in the PCI structure during scan_bus(). [#25]\n- Fixed bread() to check if the bytes read matches with what was requested.\n- Fixed premature output of information from the serial driver when acting as\n  the remote console.\n- Fixed frame buffer memory spaces to be marked as reserved if they conflict\n  with available memory.\n- Fixed sys_select() to return in the timeout argument the amount of time not\n  slept. This is Linux specific but POSIX permits this behavior.\n- Fixed Magic SysRq key 't' to also list zombie processes.\n- Fixed Magic SysRq keys to work even when the tty has not been opened yet.\n- Fixed get_free_page() to reduce the excessive number of iterations with\n  reclaim_buffers() when running out of memory pages.\n- Fixed the mechanism to sleep all processes in stop_kernel().\n- Fixed the sleep address in page_lock() to match with page_unlock().\n- Fixed a kernel panic if irq_keyboard() receives an unrecognized function key.\n- Fixed to correctly disable the RAMdisk device if there is not enough physical\n  memory.\n- Fixed an inode-related race condition in iget() and iput().\n- Fixed to not use the buffer after failed to be synced in sync_one_buffer().\n- Fixed in ext2_symlink(), ext2_mkdir(), ext2_mknod() and ext2_create() to make\n  sure the inode doesn't exist.\n- Fixed in minix_symlink(), minix_mkdir(), minix_mknod() and minix_create() to\n  make sure the inode doesn't exist.\n- Fixed a deadlock between getblk() and kbdflushd(). [#27]\n- Fixed a missing lock that led to a possible memory page corruption bug in\n  bread_page(). [#27]\n- Fixed atapi_cd_init() to setup the correct block size in the device structure.\n- Fixed sys_ftruncate() to return EINVAL if its method does not exist.\n- Fixed sync_superblocks() to sync all superblocks if argument is zero.\n- Fixed the size on every symlink in procfs to 64 bytes.\n- Fixed iget() to avoid locking when read_inode() returns an error.\n- Fixed a missing call to sync_buffers() in close() methods of RAMdisk drive and\n  floppy drive.\n- Fixed serial_set_termios() to avoid a division by zero.\n- Fixed script_load() with || instead of && that led to incorrectly recognize as\n  script when there is an incomplete shebang.\n- Fixed a linked list corruption when messages are retrieved not sequentially in\n  sys_msgrcv().\n- Fixed ata_hd_init() to not fail build if CONFIG_PCI is #undef.\n- Fixed padding in fbcon_insert_char() to use character 0x20 instead of 0x00.\n- Fixed vgacon_scroll_screen() to use double-buffering.\n- Small fixes and cosmetic changes.\n\n\n1.4.0 - 15-Nov-2022\n===================\n- Added support for the PCI local bus.\n- Added support for the UNIX System V IPC mechanisms (semaphores, message queues\n  and shared memory).\n- Added the character device /dev/full.\n- Added the character device /dev/port.\n- Added the system call sys_getcwd. [#4]\n- Added the configuration option CONFIG_QEMU_DEBUGCON to include support for the\n  QEMU Bochs-style debug console.\n- Improved the serial driver to support QEMU PCI serial devices.\n- Removed the extra lock when dispatching the bottom halves.\n- Mask the interrupt during the execution of the interrupt handler.\n- Reorganized the code to separate interrupt related functions from specific pic\n  functions.\n- Moved set_leds() into the bottom half of the keyboard interrupt.\n- Moved the start and stop tty functions into the bottom half of the keyboard\n  interrupt.\n- Removed the command to detect the interface type of the keyboard.\n- Removed the kernel parameter 'noramdisk', so from now on the RAM disk driver\n  is disabled by default. Use the kernel parameter 'ramdisksize=' to configure\n  and enable it.\n- Reversed the check order of schedule and signals before leaving the kernel\n  space.\n- Improved the cooperation with reclaim_buffers() when kernel runs out of memory\n  pages.\n- Added the functions inport_l() and outport_l() in core386.S.\n- Added the sleeping address value in the SysRq process listing.\n- Added the configuration option CONFIG_SYSCALL_6TH_ARG (disabled by default),\n  to enable the 6th argument in the system calls.\n- Added the configuration option CONFIG_LAZY_USER_ADDR_CHECK to relax the number\n  of checks in the linear address of a system call parameter.\n- Reorganized the signal functions to avoid that signals sent by the kernel have\n  to use the same checking mechanism as if they were sent by a user process.\n  This also fixes a permission problem when sending the SIGCHLD signal to a\n  parent process owned by a different user, during the context of sys_exit().\n- IDE driver now shows the PIO mode instead of UDMA mode, since the later is not\n  supported yet.\n- IDE driver now will use the current logical values if they are valid in the\n  identify field.\n- Changed the bios memory map functions to show that the ending address is\n  inside each range.\n- Changed sys_execve() to use the first argument instead of argv[0].\n- Reverted 75bb49d and 4ecf9dd, as the PC emulator 'copy.sh/v86' (maybe others)\n  requires to select the drive on every command.\n- Fixed the slowness during the system boot-up caused by the keyboard driver not\n  using interrupts during its own initialization.\n- Fixed ext2_truncate() to return the error code after calling free_dblock().\n- Fixed v1_minix_truncate() and v2_minix_truncate() to return the error code\n  after calling free_zone().\n- Fixed ext2_truncate() to correctly free doubly-indirect blocks.\n- Fixed v1_minix_truncate() and v2_minix_truncate() to correctly free\n  doubly-indirect blocks.\n- Fixed ext2_truncate() to free triply-indirect blocks.\n- Fixed v2_minix_truncate() to free triply-indirect blocks.\n- Fixed the way how the I/O permission bitmap in TSS is implemented.\n- Fixed the implementation of the sys_ioperm() system call.\n- Fixed the execution permission logic that let root user execute any file.\n- Fixed to handle SysRq key inside keyboard interrupt instead of in its bottom\n  half.\n- Fixed a missing inode release in elf_load() when argument list exceeds ARG_MAX\n  on an ELF binary that requires an interpreter.\n- Fixed a possible NULL pointer dereference with elf32_ph in elf_load() and\n  elf_load_interpreter().\n- Fixed the type of the user file descriptor (to unsigned int) in a number of\n  system calls.\n- Fixed a possible index out of bounds in bios_map_add().\n- Fixed a missing validation in the arguments of sys_execve().\n- Fixed an inefficiency in the mechanism of ext2_dir_readdir() and\n  minix_dir_readdir().\n- Fixed the function get_last_boot_addr() to return a proper address even when\n  there are no ELF header tables. This mostly happens when the kernel is loaded\n  using the QEMU argument '-kernel'.\n- Fixed a possible out of bounds access in CHECK_UFD() macro.\n- Fixed a possible out of bounds in utsname structures.\n- Fixed UTS_MACHINE to return always 'i386' in all processor types on the i386\n  architecture.\n- Fixed do_printk() to show correctly the value of the second identifier when\n  there are two consecutive identifiers\n- Fixed to show the size of an ATA drive in KB if it's less than 1MB.\n- Fixed to use the standard algorithm to convert LBA to CHS in the ATA driver.\n- Fixed the TCSETSW, TCSETSF, TCSETAW and TCSETAF ioctl functions, so now they\n  wait output buffer to drain before apply the new settings.\n- Fixed a missing update of the termios structure during the ioctl functions:\n  TCSETA, TCSETAW and TCSETAF\n- Fixed sys_open() to check directory permissions only if the file does not\n  exist and O_CREAT has been specified.\n- Fixed callouts bottom half to avoid nesting.\n- Fixed a bug introduced in 8eaed51 that prevented initrd images from\n  working. [#7]\n- Small fixes and cosmetic changes.\n- Cleaned up a lot of code.\n\n\n1.3.0 - 08-Dec-2021\n===================\n- Added support for interrupt nesting.\n- Added framebuffer device support for VESA VBE 2.0+ compliant graphics cards.\n- Added support for the framebuffer console (fbcon).\n- Completely rewrite the console to support VGA text and framebuffer screens.\n- Improved the speed of VGA text consoles by using double-buffering and fixing\n  also a fair number of bugs.\n- Updated the header file to support the latest GRUB Multiboot Specification v1.\n- Moved 'cpu_idle()' to a C function to include more easily some tasks to do.\n- Isolated the multiboot code in order to prepare the kernel to support multiple\n  bootloader protocols.\n- Arrange boot.S to be compatible only with GRUB Multiboot Specification v1.\n- Changed from 0x90000 to 0x50000 the memory location of the 4MB temporary Page\n  Directory to be able to hold bigger initrd images.\n- Changed from 5% to 1% the amount of memory that will use the inode table.\n- Added the ability to insert extra regions to the memory map provided by the\n  boot loader.\n- Added support to detect non-contiguous areas of available memory in the BIOS\n  memory map.\n- Added support for the 'magic SysRq key' to help to know the cause of a kernel\n  freeze on a disaster situation.\n- Added some basic checks on data received during IDE identify to make sure it\n  makes sense.\n- Added support to handle two ATA/ATAPI devices in the same IDE controller.\n- Reduced the size of the buffer area used in floppy I/O operations.\n- Increased to 50 the maximum of BIOS memory map entries.\n- Removed CLI() functions in ide_hd and ide_cd.\n- Improved the handling of the inode free list and the locking mechanism.\n- Improved the handling of buffer and memory page free lists.\n- Improved the way how is counted the first megabyte of memory.\n- Changed bread_page() to reuse buffers and reduce disk I/O activity.\n- Honour POSIX.1-2008 by returning ELOOP if flag O_NOFOLLOW is set and the\n  trailing component (basename) of the pathname in open() is a symbolic link.\n- Disabled interrupts during the context switch.\n- Moved the values buffer->valid, buffer->locked and buffer->dirty to flags.\n- Moved the value pg->locked to a flag.\n- Changed kernel_process() to accept also the name of the process.\n- Removed a sizeof(void) in sys_signal() as it is not covered by the C standard.\n- Disabled interrupts during early boot up.\n- Added the configure option CONFIG_VERBOSE_SEGFAULTS (disabled by default).\n- Added a separate queue for all running processes.\n- Disabled default screen blanking.\n- Added a new linked list in the buffer structure to better handle the dirty\n  buffers.\n- Added the 'Dirty' line in '/proc/meminfo' to keep track the amount of memory\n  waiting to be written back to the disk.\n- Wakeup the INIT process (if it's sleeping on sys_wait4()) if one of the new\n  processes inherited during the sys_exit() call is a zombie.\n- Saved some CPU cycles in irq_handler() by isolating unused IRQs.\n- Fixed the RAMdisk driver to not access blocks beyond its size.\n- Fixed a race condition in floppy drive when the interrupt occurred right\n  before going to sleep.\n- Fixed a bug during the RAMdisk memory initialization that reserved twice the\n  size of the initrd image.\n- Fixed to return EISDIR when trying to read a directory in procfs.\n- Fixed a memory corruption bug in procfs_readlink() that was leading to\n  instability in user programs that read the procfs.\n- Fixed to use a simple assignment in elf_create_stack() instead of using a\n  function to copy a numeric value.\n- Fixed a long standing memory corruption bug when returning the contents of the\n  '/proc/<PID>/cmdline' file.\n- Fixed a possible memory corruption bug when returning the contents of the\n  '/proc/<PID>/environ' file.\n- Fixed a missing queue handling in the serial driver.\n- Fixed to remove the calls to reset termios and tty on tty_close().\n- Fixed an extra buffer_head assignment in get_free_buffer() which reduced to\n  50% the buffer space, and could also potentially use an already locked buffer.\n- Fixed a very long standing buffer corruption bug, in rename functions of ext2\n  and minix filesystems, that led to crashes with the message 'getblk(): no more\n  buffers on free list!' after a heavy filesystem use.\n- Fixed the tty_queue_room() function and aligned to 8 the number of cblocks per\n  queue.\n- Fixed the way how release_page() and reclaim_buffers() cooperate when there\n  are no more free memory pages, in order to avoid killing the current process\n  prematurely.\n- Fixed to avoid sleeping during console_flush_log_buf().\n- Fixed to return ENOSPC when trying to write beyond the size of a block device.\n- Fixed get_proc_by_pid() to not PANIC anymore if the process didn't exist.\n- Fixed to avoid multiple calls to tty_queue_init().\n- Fixed to return ENXIO when the device does not exist.\n- Fixed the CSI J Erase in Display (ED) and other sequences in console.\n- Fixed /dev/kmem to not access beyond the end of the virtual memory.\n- Fixed to make sure that disk partitions with status value other than 0x00 and\n  0x80 are invalid.\n- Fixed a race condition in ATA identify/read when the interrupt occurred right\n  before going to sleep.\n- Fixed a buffer overrun in iso9660_dir_readdir().\n- Fixed a bug in iso9660_dir_readdir() that prevented from including some files\n  in the user dirent structure under certain conditions.\n- Fixed a very long standing bug in the memory page hashing mechanism that led\n  to kernel freezes after a long use.\n- Fixed a very long standing bug in all inode lookup functions that ate an extra\n  inode on every call, leading to the premature message \"WARNING: no more inodes\n  on free list!\".\n- Fixed certain values to be signed instead of unsigned in kstat structure.\n- Fixed a bug in tty->canon_data that corrects a bad behavior in select().\n- Fixed to decrease rss memory from the zombie process instead from its parent\n  in remove_zombie().\n- Fixed to name correctly the IDLE process by assigning 'idle' to argv0.\n- Fixed to honour the select() function when handling pipes.\n- Fixed to reduce over-scheduling in tty_write() by calling do_sched() only if\n  needed.\n- Fixed a long standing bug in do_exit() that made some processes returning from\n  the death.\n- Fixed the inode reference counter when moving directories (sys_rename) in ext2\n  and minix filesystems.\n- Fixed to update the parent directory when moving directories (sys_rename) in\n  ext2 and minix filesystems.\n- Fixed to wake up all processes in select() after a console_write().\n- Fixed an incomplete copy of in-memory superblock data during a remount from RO\n  to RW, in ext2 and minix filesystems, that led to not save all changes in\n  superblock.\n- Fixed to decrease the number of children either when the process is exiting,\n  and from the correct parent after reaping a zombie process.\n- Fixed a long standing bug, in ext2_dir_readdir() and minix_dir_readdir(), that\n  prevented from listening directory entries if there were blank blocks in the\n  middle.\n- Small fixes and cosmetic changes.\n- Cleaned up a lot of code.\n\n\n1.2.0 - 12-Dec-2020\n===================\n- Added support for serial (RS-232) devices.\n- Completely rewritten the way how the device table is handled.\n- Completely rewritten the way how the interrupt table is handled.\n- Added the ability to share the same IRQ between multiple devices.\n- Completely rewritten the way how bottom halves are managed.\n- Added the 'doc/devices.txt' document.\n- Added basic functionality of OPOST functions to tty.\n- Added to reschedule the keyboard bottom-half if it was busy.\n- Added support of O_NONBLOCK in tty_write().\n- Added remote serial console support.\n- Added support for K_RAW and K_MEDIUMRAW keyboard modes.\n- Added and fixed some ECMA-48 CSI sequences in console.\n- Improved termios and other aspects of the tty driver to accomodate the new\n  serial driver.\n- Small optimizations and bug fixes in console.\n- Improved the macros that build the interrupt service routines.\n- Fixed to force some signals that a process cannot ignore by changing their\n  dispositions to SIG_DFL.\n- Fixed a bug in tty_read and tty_write that caused to send the SIGTTIN signal\n  to the foreground process.\n- Fixed nanosleep() to force to 10ms any request lower than 10ms.\n- Fixed a signedness bug in setreuid() and setregid().\n- Fixed to delimitate better the stack-related page faults in the vma region.\n- Fixed a NULL pointer dereference when __DEBUG__ is enabled in sys_waitpid().\n- Fixed to avoid freeing an invalid page that generated PANICs in SVGAlib\n  programs.\n- Fixed a bug that, under certain conditions, page_not_present() unmapped a\n  wrong page number.\n- Fixed to not clone MAP_SHARED pages during fork().\n- Saved twice the 'signum' value before calling the signal handler.\n- Small fixes and cosmetic changes.\n\n\n1.1.0 - 24-Mar-2020\n===================\n- Added support for an initial RAMdisk (initrd) image.\n- Added full support for the ext2 filesystem.\n- Added support to execute scripts.\n- Limit the number of messages on spurious interrupts.\n- RAMdisks initialization now shows the range of the memory addresses of each\n  RAMdisk created.\n- Added VMA_REGIONS as a general configurable option (default: 150 entries).\n- Changed the default kernel filesystem to ext2.\n- Renamed the sleep addresses in tty.c.\n- Added the ability to pass arguments to init from the kernel's command line.\n- Included memory values in /proc/PID/stat and /proc/PID/status.\n- Included the file /proc/PID/statm to provide more information about memory\n  usage.\n- Changed the ATA's SET MULTIPLE MODE command to do all I/O with 4KB block size\n  (8 sectors) by default.\n- Fixed to prevent from using an unexistent floppy type, in the fdd_type\n  structure, if CMOS returns a value bigger than 0x04.\n- Fixed a misplaced bitwise operator AND that was not ensuring the limitation\n  to 1GB as the amount of physical memory supported.\n- Fixed some bugs in *_minix_ialloc() and minix_balloc() when they fail.\n- Fixed a malfunction in the job control.\n- Fixed in sys_getgroups() to return the number of group IDs when the argument\n  size is zero.\n- Fixed the DEC Set Top and Bottom Margins (DECSTBM) sequence, which affected\n  the scroll up mechanism in consoles.\n- Fixed to set properly the timestamp on every read and write in all ttys.\n- Fixed the start time value in /proc/PID/stat of every single process.\n- Fixed to use a long long variable type to be able support block devices bigger\n  than 4GB.\n- Fixed a memory corruption bug processing the VT100 'CSI n J' sequence.\n- Small fixes and cosmetic changes.\n\n\n1.0.1 - 04-Aug-2018\n===================\n- Added a basic implementation of a Pseudo-Random Number Generator using the\n  character devices /dev/random and /dev/urandom.\n- Improved the mechanism in procfs_dir_readdir() to fix a memory corruption bug.\n- Fixed a bug in procfs_dir_readdir() that prevented from reading correctly the\n  entire procfs root directory.\n- Fixed a bug in iso9660_dir_readdir() that prevented from reading correctly any\n  directory.\n- Fixed to show the complete pathname in the argv[0] of the init process.\n- Fixed to protect INIT process from unexpected signals.\n\n\n1.0.0 - 23-Apr-2018\n===================\n- Fixed a bug in reclaim_buffers() to avoid kernel freeze.\n- Fixed a corruption bug when creating the dirent structure in the dir_readdir()\n  functions.\n- Massive code cleaning.\n- New system calls:\n\tsys_select\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2018 Jordi Sanfeliu, et al.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n--\n\nAuthors/contributors include:\n\nRichard R. Masters\nGreg Haerr\nAlwin Berger\nGábor Stefanik\n\n\n\nThe following notice is included for code incorporated from the Limine Project:\n\nCopyright (C) 2019-2023 mintsuki and contributors.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "Makefile",
    "content": "# fiwix/Makefile\n#\n# Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n# Distributed under the terms of the Fiwix License.\n#\n\nTOPDIR := $(shell if [ \"$$PWD\" != \"\" ] ; then echo $$PWD ; else pwd ; fi)\nINCLUDE = $(TOPDIR)/include\nTMPFILE := $(shell mktemp)\n\nARCH = -m32\nCPU = -march=i386\nLANG = -std=c89\n\n# CCEXE can be overridden at the command line. For example: make CCEXE=\"tcc\"\n# To use tcc see docs/tcc.txt\nCCEXE=gcc\n\nCC = $(CROSS_COMPILE)$(CCEXE) $(ARCH) $(CPU) $(LANG) -D__KERNEL__ $(CONFFLAGS) #-D__DEBUG__\nCFLAGS = -I$(INCLUDE) -O2 -fno-pie -fno-common -ffreestanding -Wall -Wstrict-prototypes #-Wextra -Wno-unused-parameter\n\nifeq ($(CCEXE),gcc)\nLD = $(CROSS_COMPILE)ld\nCPP = $(CROSS_COMPILE)cpp -P -I$(INCLUDE)\nLIBGCC := -L$(shell dirname `$(CC) -print-libgcc-file-name`) -lgcc\nLDFLAGS = -m elf_i386\nendif\n\nifeq ($(CCEXE),tcc)\nLD = $(CROSS_COMPILE)$(CCEXE) $(ARCH)\nLDFLAGS = -static -nostdlib -nostdinc\n# If you define CONFIG_VM_SPLIT22 this should be 0x80100000: make CCEXE=\"tcc\" TEXTADDR=\"0x80100000\"\nTEXTADDR = 0xC0100000\nendif\n\n\nDIRS =\tkernel \\\n\tkernel/syscalls \\\n\tmm \\\n\tfs \\\n\tdrivers/char \\\n\tdrivers/block \\\n\tdrivers/pci \\\n\tdrivers/video \\\n\tnet \\\n\tlib\n\nOBJS = \tkernel/*.o \\\n\tkernel/syscalls/*.o \\\n\tmm/*.o \\\n\tfs/*.o \\\n\tfs/devpts/*.o \\\n\tfs/ext2/*.o \\\n\tfs/iso9660/*.o \\\n\tfs/minix/*.o \\\n\tfs/pipefs/*.o \\\n\tfs/procfs/*.o \\\n\tfs/sockfs/*.o \\\n\tdrivers/char/*.o \\\n\tdrivers/block/*.o \\\n\tdrivers/pci/*.o \\\n\tdrivers/video/*.o \\\n\tnet/*.o \\\n\tlib/*.o\n\nexport CC LD CFLAGS LDFLAGS INCLUDE\n\nall:\n\t@echo \"#define UTS_VERSION \\\"`date -u`\\\"\" > include/fiwix/version.h\n\t@for n in $(DIRS) ; do (cd $$n ; $(MAKE)) || exit ; done\nifeq ($(CCEXE),gcc)\n\t$(CPP) $(CONFFLAGS) fiwix.ld > $(TMPFILE)\n\t$(LD) -N -T $(TMPFILE) $(LDFLAGS) $(OBJS) $(LIBGCC) -o fiwix\n\trm -f $(TMPFILE)\n\tnm fiwix | sort | gzip -9c > System.map.gz\nendif\nifeq ($(CCEXE),tcc)\n\t$(LD) -Wl,-Ttext=$(TEXTADDR) $(LDFLAGS) $(OBJS) -o fiwix\nendif\n\nclean:\n\t@for n in $(DIRS) ; do (cd $$n ; $(MAKE) clean) ; done\n\trm -f *.o fiwix System.map.gz\n\n"
  },
  {
    "path": "README.md",
    "content": "Fiwix\n=====\nFiwix is an operating system kernel written from scratch, based on the UNIX architecture and fully focused on being POSIX compatible. It is designed and developed mainly as a hobby OS and, since it serves also for educational purposes, the kernel code is kept as simple as possible for the benefit of students and OS enthusiasts. It is small in size (less than 50K lines of code), runs on the i386 hardware platform and is compatible with a good base of existing GNU applications.\n\nFeatures\n--------\n - Written in ANSI C language (Assembly used only in the needed parts).\n - GRUB Multiboot Specification v1 compliant.\n - Full 32bit protected mode non-preemptive kernel.\n - For i386 processors and higher.\n - Preemptive multitasking.\n - POSIX-compliant (mostly).\n - Process groups, sessions and job control.\n - Interprocess communication with pipes, signals and UNIX-domain sockets.\n - UNIX System V IPC (semaphores, message queues and shared memory).\n - BSD file locking mechanism (POSIX restricted to file and advisory only).\n - Virtual memory splits (user/kernel): 3GB/1GB and 2GB/2GB.\n - Demand paging with Copy-On-Write feature.\n - Linux 2.0 i386 ABI system calls compatibility (mostly).\n - ELF-i386 executable format support (statically and dynamically linked).\n - Round Robin based scheduler algorithm (no priorities yet).\n - VFS abstraction layer.\n - Kexec support with Multiboot Specification v1 and Linux boot protocols.\n - EXT2 filesystem support with 1KB, 2KB and 4KB block sizes.\n - Minix v1 and v2 filesystem support.\n - Linux-like PROC filesystem support (read only).\n - PIPE pseudo-filesystem support.\n - ISO9660 filesystem support with Rock Ridge extensions.\n - RAMdisk device support.\n - Initial RAMdisk (initrd) image support.\n - SVGAlib based applications support.\n - PCI local bus support.\n   - QEMU/Bochs Graphics Adapter support.\n - UNIX98 pseudoterminals (pty) and devpts filesystem support.\n - Virtual consoles support (up to 12).\n - Keyboard driver with Linux keymaps support.\n - PS/2 mouse support.\n - Framebuffer device support for VESA VBE 2.0+ compliant graphic cards.\n - Framebuffer console (fbcon) support.\n - Serial port (RS-232) driver support.\n - Remote serial console support.\n - QEMU Bochs-style debug console support.\n - Parallel port printer driver support.\n - Basic implementation of a Pseudo-Random Number Generator.\n - Floppy disk device driver and DMA management.\n - IDE/ATA ATAPI CD-ROM device driver.\n - IDE/ATA hard disk device driver.\n\nCompiling\n---------\nThe command needed to build the Fiwix kernel is `make clean ; make`.  This will create two the files in the root directory of the source code tree: **fiwix** (the kernel itself) and **System.map.gz** (the symbol table).\n\nBefore compiling you might want to tweak the kernel configuration by changing the default values in `include/fiwix/config.h` and `include/fiwix/limits.h`.\n\nKeep in mind that the kernel doesn't do anything on its own, you need to create a user-space environment to make use of it. Upon booting, the kernel mounts the root filesystem and tries to run `/sbin/init` on it, so you would need to provide this program yourself.  Fortunately, [FiwixOS](https://www.fiwix.org/downloads.html) provides a full user-space UNIX-like environment to test the Fiwix kernel.\n\nInstalling\n----------\nYou can proceed to install FiwixOS on a hard disk either by booting from the CD-ROM or from a floppy. If you chosen the latter, you will also need the Installation CD-ROM inserted in order to install the packages that form all the system environment.\n\nLet the system boot and when you are ready, just type `install.sh`.\n\nThe minimal hardware requirements are as follows:\n\n - Standard IBM PC-AT architecture.\n - i386 processor (with floating-point processor).\n - 4MB of RAM memory (128MB recommended).\n - IDE/ATAPI CD-ROM or floppy disk (3.5\", 1.44MB).\n - 1GB ATA hard disk.\n\nPlease keep in mind that this is a kernel in its very early stages and may well have serious bugs and broken features which have not yet been identified or resolved.\n\nLet me repeat that.\n\nPlease keep in mind that this is a kernel in its very early stages and may well have serious bugs and broken features which have not yet been identified or resolved.\n\n\t\t\t*****************************\n\t\t\t*** USE AT YOUR OWN RISK! ***\n\t\t\t*****************************\n\nReferences\n----------\n- [Website](https://www.fiwix.org)\n- [IRC](https://web.libera.chat/)\n- [Mailing List](https://lists.sourceforge.net/lists/listinfo/fiwix-general)\n\nLicense\n-------\nFiwix is free software licensed under the terms of the MIT License, see the LICENSE file for more details.  \nCopyright (C) 2018-2025, Jordi Sanfeliu.\n\nCredits\n-------\nFiwix was created by [Jordi Sanfeliu](https://www.fibranet.cat).  \nYou can contact me at [jordi@fibranet.cat](mailto:jordi@fibranet.cat).\nSee also the LICENSE file for a list of contributors.\n\n"
  },
  {
    "path": "THANKS",
    "content": "THANKS!\n\nA huge THANKS to all people who created their own hobby, and not so hobby,\noperating systems and made them freely available on Internet.\n\nFrom those simple \"Hello world!\\n\" kernels to a real self-hosting operating\nsystem, their projects were a invaluable source of information and inspiration\nto create the Fiwix kernel.\n\nA special thanks to OSDEV Community for their tutorials, documents, wikis, etc.\n\nJordi Sanfeliu\nhttps://www.fiwix.org\n"
  },
  {
    "path": "docs/devices.txt",
    "content": "Fiwix allocated devices\n=======================\n\nCharacter\n\nMajor | Minor | Device name   | Description\n------+-------+---------------+------------------------------------------------\n1\t\t\t\tMemory devices\n\t1\t/dev/mem\tphysical memory access\n\t2\t/dev/kmem\tkernel virtual memory access\n\t3\t/dev/null\tnull device\n\t4\t/dev/port\tI/O port access\n\t5\t/dev/zero\tnull byte source\n\t7\t/dev/full\treturns ENOSPC on write\n\t8\t/dev/random\trandom number generator\n\t9\t/dev/urandom\trandom number generator (same as above)\n\n4\t\t\t\tTTY devices\n\t0\t/dev/tty0\tcurrent virtual console\n\t1\t/dev/tty1\tfirst virtual console\n\t...\t...\n\t12\t/dev/tty12\t12th virtual console\n\t64\t/dev/ttyS0\tfirst UART serial port\n\t65\t/dev/ttyS1\tsecond UART serial port\n\t66\t/dev/ttyS2\tthird UART serial port\n\t67\t/dev/ttyS3\tfourth UART serial port\n\n5\t\t\t\tAlternate TTY devices\n\t0\t/dev/tty\tcurrent tty device\n\t1\t/dev/console\tsystem console\n\t2\t/dev/ptmx\tPTY master multiplex\n\n6\t\t\t\tParallel printer devices\n\t0\t/dev/lp0\tfirst parallel printer port\n\n10\t\t\t\tNon-serial mice\n\t1\t/dev/psaux\tPS/2-style mouse port\n\n29\t\t\t\tUniversal framebuffer\n\t0\t/dev/fb0\tfirst framebuffer\n\n136\t\t\t\tUNIX98 PTY slaves\n\t0\t/dev/pts/0\tfirst UNIX98 pseudo-TTY\n\t1\t/dev/pts/1\tsecond UNIX98 pseudo-TTY\n\t...\n\n\n\n\nBlock\n\nMajor | Minor | Device name   | Description\n------+-------+---------------+------------------------------------------------\n1\t\t\t\tRAMdisk drives\n\t0\t/dev/ram0\tfirst RAMdisk drive\n\t1\t/dev/ram1\tsecond RAMdisk drive\n\t...\t...\n\t9\t/dev/ram9\t10th RAMdisk drive\n\n2\t\t\t\tFloppy disks (controller 0)\n\t0\t/dev/fd0\tfloppy disk drive 0\n\t1\t/dev/fd1\tfloppy disk drive 1\n\t4\t/dev/fd0h360\tfloppy disk drive 0 (5.25\" 360KB)\n\t5\t/dev/fd1h360\tfloppy disk drive 1 (5.25\" 360KB)\n\t8\t/dev/fd0h1200\tfloppy disk drive 0 (5.25\" 1.2MB)\n\t9\t/dev/fd1h1200\tfloppy disk drive 1 (5.25\" 1.2MB)\n\t12\t/dev/fd0h720\tfloppy disk drive 0 (3.5\" 720KB)\n\t13\t/dev/fd1h720\tfloppy disk drive 1 (3.5\" 720KB)\n\t16\t/dev/fd0h1440\tfloppy disk drive 0 (3.5\" 1.44MB)\n\t17\t/dev/fd1h1440\tfloppy disk drive 1 (3.5\" 1.44MB)\n\n3\t\t\t\tPrimary ATA interface (hard disk or CD-ROM)\n\t0\t/dev/hda\twhole hard disk/CD-ROM master\n\t1\t/dev/hda1\tfirst partition\n\t2\t/dev/hda2\tsecond partition\n\t3\t/dev/hda3\tthird partition\n\t4\t/dev/hda4\tfourth partition\n\t64\t/dev/hdb\twhole hard disk/CD-ROM slave\n\t65\t/dev/hdb1\tfirst partition\n\t66\t/dev/hdb2\tsecond partition\n\t67\t/dev/hdb3\tthird partition\n\t68\t/dev/hdb4\tfourth partition\n\n22\t\t\t\tSecondary ATA interface (hard disk or CD-ROM)\n\t0\t/dev/hdc\twhole hard disk/CD-ROM master\n\t1\t/dev/hdc1\tfirst partition\n\t2\t/dev/hdc2\tsecond partition\n\t3\t/dev/hdc3\tthird partition\n\t4\t/dev/hdc4\tfourth partition\n\t64\t/dev/hdd\twhole hard disk/CD-ROM slave\n\t65\t/dev/hdd1\tfirst partition\n\t66\t/dev/hdd2\tsecond partition\n\t67\t/dev/hdd3\tthird partition\n\t68\t/dev/hdd4\tfourth partition\n\n"
  },
  {
    "path": "docs/initrd.txt",
    "content": "Initrd image size restriction\n=============================\nThe Fiwix kernel supports very large initrd images with two different maximum\nsizes depending on the type of the virtual memory split. If the configuration\noption CONFIG_VM_SPLIT22 is not defined (the default case), the virtual memory\nis divided as 3GB for the user and 1GB for the kernel, in this case the maximum\nsize of an initrd image will be near 1GB. When CONFIG_VM_SPLIT22 is defined,\nwhich means 2GB for the user and 2GB for the kernel, then the maximum size can\nbe near 2GB.\n\nIn all, the memory layout of the Fiwix kernel imposes a small and, hopefully,\nharmless restriction on an specific size of the initrd image.\n\nSince the kernel Page Directory and Page Tables are placed right after the end\nof the initrd image in memory, (see 'docs/kmem_layout.txt'), the PD and PTs will\nprobably conflict with a user program loaded at the address 0x08048000 if the\ninitrd image has a size of around 128MB.\n\nIn this case, is recommendable define a bigger initrd image to avoid PD and PTs\nbe placed in the same memory address as user programs.\n\n"
  },
  {
    "path": "docs/kernel-parameters.txt",
    "content": "Fiwix kernel parameters\n=======================\n\nThe following is a list of the current kernel parameters:\n\nbga=\t\tBochs Graphics Adapter resolution (width x height x bpp)\n\t\tOptions: 640x480x32, 800x600x32, 1024x768x32\n\nconsole=\tSet the output console device.\n\t\tOptions: /dev/tty[1..12], /dev/ttyS[0..3]\n\t\tSerial consoles have fixed settings: 9600,N,8,1\n\nide_nodma\tDisable DMA in all ATA drives.\n\ninitrd=\t\tOptional ramdisk image file which will be loaded by GRUB.\n\nkexec_proto=\tThe boot method of the new kernel.\n\t\tOptions: multiboot1, linux\n\nkexec_size=\tSize of the memory space to be reserved to allocate the new\n\t\tkernel (in KiB).\n\nkexec_cmdline=\tCommand line to be passed to the new kernel (enclosed in double\n\t\tquotes).\n\nps2_noreset\tDisable PS/2 controller reset.\n\nramdisksize=\tEnable the RAM disk drive and configure its size (in KiB).\n\nro\t\tMount root device as read-only on boot.\n\nroot=\t\tRoot device name.\n\t\tOptions: /dev/fd0, /dev/hda1, ...\n\nrootfstype=\tSet the root filesystem type.\n\t\tOptions: ext2, minix, iso9660\n\n\nUse -- to separate kernel parameters from arguments to init.\n\nThe kernel parses parameters from the kernel command line up to \"--\",\neverything found after \"--\" is passed as an argument to init.\n\n"
  },
  {
    "path": "docs/kexec.txt",
    "content": "Fiwix kexec implementation\n==========================\nKexec is a mechanism that let's you switch into a different kernel without\nrebooting your machine. Its implementation in Fiwix differs from the Linux\nkexec implementation because it doesn't need a system call nor specific\nuser-space tools, and your current system will completely shutdown before\njumping to the new kernel.\n\nThe new kernel can be another Fiwix kernel or any other ELF binary kernel as\nlong as it supports the Multiboot 1 Specification. It can also be a Linux Kernel\nby using the Linux Boot protocol.\n\nHow it works\n------------\nYour system needs to know at boot-time that it might switch to a different\nkernel. That is, you need to pass some special parameters in your kernel command\nline during the system boot. The following are the three parameters that you\nneed to specify:\n\n- kexec_proto=\n  This is the boot method of the new kernel. Currently the supported values\n  are 'multiboot1' and 'linux'.\n\n- kexec_size=\n  Size in KB of the memory space to be reserved to allocate the new kernel.\n\n- kexec_cmdline=\n  Command line to be passed to the new kernel (enclosed in double quotes).\n\nExample of a kernel command line:\n/boot/fiwix ro root=/dev/hda2 kexec_proto=multiboot1 kexec_size=500 \\\nkexec_cmdline=\"ro root=/dev/hda2\"\n\nThe RAMdisk drives play an important role here. You already know that they can\nbe used to allocate an initrd image specified during the boot, or to allocate\none or more all-purpose RAMdisk drives. Now they are also used for kexec to\nallocate the new kernel.\n\nKexec uses always the first unused RAMdisk drive. You'll know which one is the\nfirst unused depending if you specified an initrd image, or if you specified to\nhave all-purpose RAMdisk drives at boot-time.\n\nFiwix is configured by default to have the following possible RAMdisk drives\nlayout:\n\t- If an initrd image was specified at boot-time then the first RAMdisk\n\t  drive is used for it (i.e: /dev/ram0).\n\t- If 'ramdisksize=' was specified at boot-time then the first unused\n\t  RAMDISK_DRIVES RAMdisk drives will be used.\n\t- If 'kexec_size=' was specified at boot-time then the first unused\n\t  RAMdisk drive will be used.\n\nLet's see some examples to understand better these rules:\n\nExample 1:\n\t- Kernel cmdline: \"... ramdisksize=49152 initrd=/initrd.img\"\n\t- Resulting RAMdisk drives layout:\n\t\t- /dev/ram0\t-> initrd RAMdisk drive of 48MB (/ filesystem).\n\t\t- if RAMDISK_DRIVES == 1\n\t\t\t- /dev/ram1\t-> all-purpose RAMdisk drive of 48MB.\n\t\t- if RAMDISK_DRIVES == 2\n\t\t\t- /dev/ram1\t-> all-purpose RAMdisk drive of 48MB.\n\t\t\t- /dev/ram2\t-> all-purpose RAMdisk drive of 48MB.\n\t\t...\n\nExample 2:\n\t- Kernel cmdline: \"... ramdisksize=16384\"\n\t- Resulting RAMdisk drives layout:\n\t\t- if RAMDISK_DRIVES == 1\n\t\t\t- /dev/ram0\t-> all-purpose RAMdisk drive of 16MB.\n\t\t- if RAMDISK_DRIVES == 2\n\t\t\t- /dev/ram0\t-> all-purpose RAMdisk drive of 16MB.\n\t\t\t- /dev/ram1\t-> all-purpose RAMdisk drive of 16MB.\n\t\t...\n\nExample 3:\n\t- Kernel cmdline: \"... ramdisksize=16384 kexec_size=500 ...\"\n\t- Resulting RAMdisk drives layout:\n\t\t- if RAMDISK_DRIVES == 1\n\t\t\t- /dev/ram0\t-> all-purpose RAMdisk drive of 16MB.\n\t\t\t- /dev/ram1\t-> kexec RAMdisk drive of 500KB.\n\t\t- if RAMDISK_DRIVES == 2\n\t\t\t- /dev/ram0\t-> all-purpose RAMdisk drive of 16MB.\n\t\t\t- /dev/ram1\t-> all-purpose RAMdisk drive of 16MB.\n\t\t\t- /dev/ram2\t-> kexec RAMdisk drive of 500KB.\n\t\t...\n\n\nMultiboot\n---------\nOnce you know what RAMdisk drive will be used to allocate the new kernel, you\ncan proceed to copy the ELF binary kernel into such RAMdisk drive by using a\ncommon user-space tool like 'cp' or 'dd'.\n\nFinally, when you are ready, just do a normal shutdown to switch automatically\nto the new kernel.\n\nExample:\n# cp fiwix /dev/ram0\n# shutdown -h 0\n\n\nLinux\n-----\nIn the case of Linux the boot protocol is different. The Linux kernel expects to\nfind two 32bit numbers (in little-endian format) at the beginning of the RAMdisk\ndrive. The first number is the length of the Linux kernel, and the second one is\nthe length of the initramfs. If the kernel doesn't need an initramfs, the length\nmust have a value of zero.\n\nRight after both numbers you must copy the kernel image, and then the initramfs\nimage (if needed).\n\nThe RAMdisk drive should look like the following before to kexec:\n\n+-----------+-----------+-------------------- ~~~ -+-------------------- ~~~ -+\n| kernel    | initramfs |  the kernel image   ~~~ -|   the initramfs     ~~~ -|\n| length    | length    |      'vmlinuz'      ~~~ -|   image (optional)  ~~~ -|\n+-----------+-----------+-------------------- ~~~ -+-------------------- ~~~ -+\n0            4           8                          n = (8 + kernel length)\noffset (in bytes)\n\n\nThe following script might help you to format correctly the RAMdisk drive:\n\n---------------------------------- 8< ----------------------------------------\nKERNEL=linux-4.9.10\nRAMFS=initramfs.cpio\n\nsize=$(printf \"%08x\" `stat -c %s $KERNEL` | tac -rs .. | echo \"$(tr -d '\\n')\")\necho -n $size | xxd -r -p - /dev/ram0\n\nif [ -n \"$RAMFS\" ]; then\n        size=$(printf \"%08x\" `stat -c %s $RAMFS` | tac -rs .. | echo \"$(tr -d '\\n')\")\nelse\n        size=$(printf \"%08x\" `echo 0` | tac -rs .. | echo \"$(tr -d '\\n')\")\nfi\necho -n $size | xxd -r -p - | dd of=/dev/ram0 bs=1 seek=4\n\ncat $KERNEL $RAMFS | dd of=/dev/ram0 bs=1 seek=8\n---------------------------------- 8< ----------------------------------------\n\nFinally, when you are ready, just do a normal shutdown to switch automatically\nto the new kernel.\n\nExample:\n# shutdown -h 0\n\n"
  },
  {
    "path": "docs/kmem_layout.txt",
    "content": "Fiwix kernel memory address space on the i386 architecture\n==========================================================\n\n\t+-------------------+ \\\n\t| page_table        | |\n\t+-------------------+ |\n\t+-------------------+ |\n\t| page_hash_table   | |\n\t+-------------------+ | different\n\t+-------------------+ |\n\t| RAMdisk drives:   | | preallocated\n\t|   - initrd        | |\n\t|   - all-purpose   | | areas\n\t|   - kexec         | |\n\t+-------------------+ | of\n\t+-------------------+ |\n\t| fd_table          | | contiguous\n\t+-------------------+ |\n\t+-------------------+ | memory\n\t| inode_hash_table  | |\n\t+-------------------+ | spaces\n\t+-------------------+ |\n\t| buffer_hash_table | |\n\t+-------------------+ |\n\t+-------------------+ |\n\t| proc_table        | |\n\t+-------------------+ /\n\t+-------------------+\n\t| kpage_table       | kernel Page Tables\n\t+-------------------+\n\t+-------------------+\n\t| kpage_dir         | kernel Page Directory\n\t+-------------------+\n\t+-------------------+\n\t| initrd (optional) | allocated by GRUB or Multiboot\n\t+-------------------+\n\t+-------------------+\n\t| .bss section      |\n\t+-------------------+\n\t| .data section     |\n\t+-------------------+\n\t| .text section     | kernel binary (fiwix)\n\t+-------------------+\n0x00100000\n...\n\t+-------------------+\n\t| 4KB kpage_dir     | this page will be reused once the definitive\n\t| only used at boot | kpage_dir is installed\n\t+-------------------+\n0x00050000\n...\n0x00010000\n\t+-------------------+\n\t| kernel stack (4k) | later used as stack for idle process\n\t+-------------------+\n...\n0x00000000\n"
  },
  {
    "path": "docs/system-console.txt",
    "content": "Fiwix system console\n====================\nIt is possible to specify multiple devices for console output. You can define\nup to NR_SYSCONSOLES 'console=' kernel command line options to select which\ndevice(s) to use for console output.\n\nRefer to 'include/fiwix/kparms.h' to know which devices are supported as\nsystem consoles.\n\nThe device '/dev/tty0' is the default when no device is specified. It is\ndirectly linked to the current virtual console in use, so by default, all\nkernel messages will go to the current virtual console.\n\nSince the VGA graphics is always present in the PC i386 architecture, the early\nlog messages will appear only in the first virtual console defined, regardless\nif a serial console was also defined.\n\n"
  },
  {
    "path": "docs/tcc.txt",
    "content": "Fiwix can be built with a modified version of tcc instead of gcc.\n\nA version of tcc which has been verified to compile Fiwix can be retrieved\n(at the time of this writing) from the following URL:\nhttps://download.savannah.gnu.org/releases/tinycc/tcc-0.9.27.tar.bz2\n\nFiwix uses a linker script to specify high virtual addresses for data\nstructures but uses low physical addresses for the addresses to load\nthe kernel sections into.\n\ntcc does not support linker scripts and so a small modification must\nbe applied to tcc in order to calculate the appropriate physical addresess\nfor sections in the ELF header.\n\nThe layout_sections function in the file tccelf.c must be modified\n(around line 1674).\n\nThis line:\n                        ph->p_paddr = ph->p_vaddr;\n\nMust be changed to this:\n                        ph->p_paddr = ph->p_vaddr;\n                        if (s1->text_addr == 0xC0100000)\n                            ph->p_paddr = ph->p_paddr - 0xC0000000;\n                        if (s1->text_addr == 0x80100000)\n                            ph->p_paddr = ph->p_paddr - 0x80000000;\n\n\nThis change is specific to Fiwix and so it is unlikely to be incorporated\ninto the standard tcc compiler in the future.\n\n\nNote that tcc does not support certain constructs used by CONFIG_OFFSET64\nor CONFIG_PRINTK64, so you must undefine these options.\n\nThese commands will build Fiwix with tcc:\n\necho \"#undef CONFIG_OFFSET64\" > include/fiwix/custom_config.h\necho \"#undef CONFIG_PRINTK64\" >> include/fiwix/custom_config.h\nmake clean\nmake CCEXE=\"tcc\" CONFFLAGS=\"-DCUSTOM_CONFIG_H\"\n"
  },
  {
    "path": "docs/video/font-lat9-8x14.txt",
    "content": "\t/* 0x00        */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0xc3, \t/* ##----## */\n0x99, \t/* #--##--# */\n0x99, \t/* #--##--# */\n0xf3, \t/* ####--## */\n0xe7, \t/* ###--### */\n0xe7, \t/* ###--### */\n0xff, \t/* ######## */\n0xe7, \t/* ###--### */\n0xe7, \t/* ###--### */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x01        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0x00, \t/* -------- */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x02        */\n0x00, \t/* -------- */\n0x6e, \t/* -##-###- */\n0xd8, \t/* ##-##--- */\n0xd8, \t/* ##-##--- */\n0xd8, \t/* ##-##--- */\n0xd8, \t/* ##-##--- */\n0xde, \t/* ##-####- */\n0xd8, \t/* ##-##--- */\n0xd8, \t/* ##-##--- */\n0xd8, \t/* ##-##--- */\n0x6e, \t/* -##-###- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x03        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x6e, \t/* -##-###- */\n0xdb, \t/* ##-##-## */\n0xdb, \t/* ##-##-## */\n0xdf, \t/* ##-##### */\n0xd8, \t/* ##-##--- */\n0xdb, \t/* ##-##-## */\n0x6e, \t/* -##-###- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x04        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x10, \t/* ---#---- */\n0x38, \t/* --###--- */\n0x7c, \t/* -#####-- */\n0xfe, \t/* #######- */\n0x7c, \t/* -#####-- */\n0x38, \t/* --###--- */\n0x10, \t/* ---#---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x05        */\n0x00, \t/* -------- */\n0x88, \t/* #---#--- */\n0x88, \t/* #---#--- */\n0xf8, \t/* #####--- */\n0x88, \t/* #---#--- */\n0x88, \t/* #---#--- */\n0x00, \t/* -------- */\n0x3e, \t/* --#####- */\n0x08, \t/* ----#--- */\n0x08, \t/* ----#--- */\n0x08, \t/* ----#--- */\n0x08, \t/* ----#--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x06        */\n0x00, \t/* -------- */\n0xf8, \t/* #####--- */\n0x80, \t/* #------- */\n0xe0, \t/* ###----- */\n0x80, \t/* #------- */\n0x80, \t/* #------- */\n0x00, \t/* -------- */\n0x3e, \t/* --#####- */\n0x20, \t/* --#----- */\n0x38, \t/* --###--- */\n0x20, \t/* --#----- */\n0x20, \t/* --#----- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x07        */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0x80, \t/* #------- */\n0x80, \t/* #------- */\n0x80, \t/* #------- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n0x3c, \t/* --####-- */\n0x22, \t/* --#---#- */\n0x3e, \t/* --#####- */\n0x24, \t/* --#--#-- */\n0x22, \t/* --#---#- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x08        */\n0x00, \t/* -------- */\n0x80, \t/* #------- */\n0x80, \t/* #------- */\n0x80, \t/* #------- */\n0x80, \t/* #------- */\n0xf8, \t/* #####--- */\n0x00, \t/* -------- */\n0x3e, \t/* --#####- */\n0x20, \t/* --#----- */\n0x38, \t/* --###--- */\n0x20, \t/* --#----- */\n0x20, \t/* --#----- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x09        */\n0x88, \t/* #---#--- */\n0x22, \t/* --#---#- */\n0x88, \t/* #---#--- */\n0x22, \t/* --#---#- */\n0x88, \t/* #---#--- */\n0x22, \t/* --#---#- */\n0x88, \t/* #---#--- */\n0x22, \t/* --#---#- */\n0x88, \t/* #---#--- */\n0x22, \t/* --#---#- */\n0x88, \t/* #---#--- */\n0x22, \t/* --#---#- */\n0x88, \t/* #---#--- */\n0x22, \t/* --#---#- */\n\n\t/* 0x0a        */\n0xaa, \t/* #-#-#-#- */\n0x55, \t/* -#-#-#-# */\n0xaa, \t/* #-#-#-#- */\n0x55, \t/* -#-#-#-# */\n0xaa, \t/* #-#-#-#- */\n0x55, \t/* -#-#-#-# */\n0xaa, \t/* #-#-#-#- */\n0x55, \t/* -#-#-#-# */\n0xaa, \t/* #-#-#-#- */\n0x55, \t/* -#-#-#-# */\n0xaa, \t/* #-#-#-#- */\n0x55, \t/* -#-#-#-# */\n0xaa, \t/* #-#-#-#- */\n0x55, \t/* -#-#-#-# */\n\n\t/* 0x0b        */\n0xbb, \t/* #-###-## */\n0xee, \t/* ###-###- */\n0xbb, \t/* #-###-## */\n0xee, \t/* ###-###- */\n0xbb, \t/* #-###-## */\n0xee, \t/* ###-###- */\n0xbb, \t/* #-###-## */\n0xee, \t/* ###-###- */\n0xbb, \t/* #-###-## */\n0xee, \t/* ###-###- */\n0xbb, \t/* #-###-## */\n0xee, \t/* ###-###- */\n0xbb, \t/* #-###-## */\n0xee, \t/* ###-###- */\n\n\t/* 0x0c        */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n\n\t/* 0x0d        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n\n\t/* 0x0e        */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x0f        */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n\n\t/* 0x10        */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n\n\t/* 0x11        */\n0x00, \t/* -------- */\n0x88, \t/* #---#--- */\n0xc8, \t/* ##--#--- */\n0xa8, \t/* #-#-#--- */\n0x98, \t/* #--##--- */\n0x88, \t/* #---#--- */\n0x00, \t/* -------- */\n0x20, \t/* --#----- */\n0x20, \t/* --#----- */\n0x20, \t/* --#----- */\n0x20, \t/* --#----- */\n0x3e, \t/* --#####- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x12        */\n0x00, \t/* -------- */\n0x88, \t/* #---#--- */\n0x88, \t/* #---#--- */\n0x50, \t/* -#-#---- */\n0x50, \t/* -#-#---- */\n0x20, \t/* --#----- */\n0x00, \t/* -------- */\n0x3e, \t/* --#####- */\n0x08, \t/* ----#--- */\n0x08, \t/* ----#--- */\n0x08, \t/* ----#--- */\n0x08, \t/* ----#--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x13        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x06, \t/* -----##- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x14        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x0c, \t/* ----##-- */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x15        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x06, \t/* -----##- */\n0x0c, \t/* ----##-- */\n0xfe, \t/* #######- */\n0x38, \t/* --###--- */\n0xfe, \t/* #######- */\n0x60, \t/* -##----- */\n0xc0, \t/* ##------ */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x16        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x02, \t/* ------#- */\n0x0e, \t/* ----###- */\n0x3e, \t/* --#####- */\n0x7e, \t/* -######- */\n0xfe, \t/* #######- */\n0x7e, \t/* -######- */\n0x3e, \t/* --#####- */\n0x0e, \t/* ----###- */\n0x02, \t/* ------#- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x17        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x80, \t/* #------- */\n0xe0, \t/* ###----- */\n0xf0, \t/* ####---- */\n0xfc, \t/* ######-- */\n0xfe, \t/* #######- */\n0xfc, \t/* ######-- */\n0xf0, \t/* ####---- */\n0xe0, \t/* ###----- */\n0x80, \t/* #------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x18        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x7e, \t/* -######- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x19        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x7e, \t/* -######- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x1a        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x0c, \t/* ----##-- */\n0xfe, \t/* #######- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x1b        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0xfe, \t/* #######- */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x1c        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x7e, \t/* -######- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x7e, \t/* -######- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x1d        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x28, \t/* --#-#--- */\n0x6c, \t/* -##-##-- */\n0xfe, \t/* #######- */\n0x6c, \t/* -##-##-- */\n0x28, \t/* --#-#--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x1e        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x06, \t/* -----##- */\n0x06, \t/* -----##- */\n0x36, \t/* --##-##- */\n0x66, \t/* -##--##- */\n0xfe, \t/* #######- */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x1f        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc0, \t/* ##------ */\n0x7c, \t/* -#####-- */\n0x6e, \t/* -##-###- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x20  (' ') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x21  ('!') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x3c, \t/* --####-- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x22  ('\"') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x36, \t/* --##-##- */\n0x36, \t/* --##-##- */\n0x14, \t/* ---#-#-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x23  ('#') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0xfe, \t/* #######- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0xfe, \t/* #######- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x24  ('$') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x10, \t/* ---#---- */\n0x7c, \t/* -#####-- */\n0xd6, \t/* ##-#-##- */\n0x70, \t/* -###---- */\n0x38, \t/* --###--- */\n0x1c, \t/* ---###-- */\n0xd6, \t/* ##-#-##- */\n0x7c, \t/* -#####-- */\n0x10, \t/* ---#---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x25  ('%') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x62, \t/* -##---#- */\n0x66, \t/* -##--##- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x66, \t/* -##--##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x26  ('&') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x38, \t/* --###--- */\n0x76, \t/* -###-##- */\n0xf6, \t/* ####-##- */\n0xce, \t/* ##--###- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x27  (''') */\n0x00, \t/* -------- */\n0x1c, \t/* ---###-- */\n0x1c, \t/* ---###-- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x28  ('(') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x0c, \t/* ----##-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x29  (')') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x2a  ('*') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0xfe, \t/* #######- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x2b  ('+') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x7e, \t/* -######- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x2c  (',') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x2d  ('-') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x2e  ('.') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x2f  ('/') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x06, \t/* -----##- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0xc0, \t/* ##------ */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x30  ('0') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xd6, \t/* ##-#-##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x31  ('1') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x78, \t/* -####--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x32  ('2') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x33  ('3') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0x06, \t/* -----##- */\n0x06, \t/* -----##- */\n0x3c, \t/* --####-- */\n0x06, \t/* -----##- */\n0x06, \t/* -----##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x34  ('4') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x0c, \t/* ----##-- */\n0x1c, \t/* ---###-- */\n0x3c, \t/* --####-- */\n0x6c, \t/* -##-##-- */\n0xcc, \t/* ##--##-- */\n0xfe, \t/* #######- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x35  ('5') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xfc, \t/* ######-- */\n0x06, \t/* -----##- */\n0x06, \t/* -----##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x36  ('6') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xfc, \t/* ######-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x37  ('7') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0xc6, \t/* ##---##- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x38  ('8') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x39  ('9') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7e, \t/* -######- */\n0x06, \t/* -----##- */\n0x06, \t/* -----##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x3a  (':') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x3b  (';') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x3c  ('<') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0xc0, \t/* ##------ */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x0c, \t/* ----##-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x3d  ('=') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x3e  ('>') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x0c, \t/* ----##-- */\n0x06, \t/* -----##- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x3f  ('?') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x40  ('@') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xde, \t/* ##-####- */\n0xde, \t/* ##-####- */\n0xde, \t/* ##-####- */\n0xdc, \t/* ##-###-- */\n0xc0, \t/* ##------ */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x41  ('A') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x42  ('B') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfc, \t/* ######-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x7c, \t/* -#####-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x43  ('C') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x3c, \t/* --####-- */\n0x66, \t/* -##--##- */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0x66, \t/* -##--##- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x44  ('D') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xf8, \t/* #####--- */\n0x6c, \t/* -##-##-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x6c, \t/* -##-##-- */\n0xf8, \t/* #####--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x45  ('E') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0x66, \t/* -##--##- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x7c, \t/* -#####-- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x66, \t/* -##--##- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x46  ('F') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0x66, \t/* -##--##- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x7c, \t/* -#####-- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x47  ('G') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xce, \t/* ##--###- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x48  ('H') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x49  ('I') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x4a  ('J') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0xd8, \t/* ##-##--- */\n0xd8, \t/* ##-##--- */\n0x70, \t/* -###---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x4b  ('K') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xcc, \t/* ##--##-- */\n0xd8, \t/* ##-##--- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xd8, \t/* ##-##--- */\n0xcc, \t/* ##--##-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x4c  ('L') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xf0, \t/* ####---- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x62, \t/* -##---#- */\n0x66, \t/* -##--##- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x4d  ('M') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xee, \t/* ###-###- */\n0xfe, \t/* #######- */\n0xd6, \t/* ##-#-##- */\n0xd6, \t/* ##-#-##- */\n0xd6, \t/* ##-#-##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x4e  ('N') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xe6, \t/* ###--##- */\n0xe6, \t/* ###--##- */\n0xf6, \t/* ####-##- */\n0xde, \t/* ##-####- */\n0xce, \t/* ##--###- */\n0xce, \t/* ##--###- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x4f  ('O') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x50  ('P') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfc, \t/* ######-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x7c, \t/* -#####-- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x51  ('Q') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xd6, \t/* ##-#-##- */\n0x7c, \t/* -#####-- */\n0x06, \t/* -----##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x52  ('R') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfc, \t/* ######-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x7c, \t/* -#####-- */\n0x78, \t/* -####--- */\n0x6c, \t/* -##-##-- */\n0x66, \t/* -##--##- */\n0xe6, \t/* ###--##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x53  ('S') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc0, \t/* ##------ */\n0x60, \t/* -##----- */\n0x38, \t/* --###--- */\n0x0c, \t/* ----##-- */\n0x06, \t/* -----##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x54  ('T') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0x5a, \t/* -#-##-#- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x55  ('U') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x56  ('V') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x10, \t/* ---#---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x57  ('W') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xd6, \t/* ##-#-##- */\n0xd6, \t/* ##-#-##- */\n0xd6, \t/* ##-#-##- */\n0xfe, \t/* #######- */\n0xee, \t/* ###-###- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x58  ('X') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x38, \t/* --###--- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x59  ('Y') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x5a  ('Z') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0xc6, \t/* ##---##- */\n0x8c, \t/* #---##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0xc2, \t/* ##----#- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x5b  ('[') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x5c  ('\\') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc0, \t/* ##------ */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x0c, \t/* ----##-- */\n0x06, \t/* -----##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x5d  (']') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x5e  ('^') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x66, \t/* -##--##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x5f  ('_') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n\n\t/* 0x60  ('`') */\n0x00, \t/* -------- */\n0x1c, \t/* ---###-- */\n0x1c, \t/* ---###-- */\n0x18, \t/* ---##--- */\n0x0c, \t/* ----##-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x61  ('a') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0x7c, \t/* -#####-- */\n0xcc, \t/* ##--##-- */\n0xdc, \t/* ##-###-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x62  ('b') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xe0, \t/* ###----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x7c, \t/* -#####-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x63  ('c') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x64  ('d') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x1c, \t/* ---###-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x7c, \t/* -#####-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x65  ('e') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc0, \t/* ##------ */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x66  ('f') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x1c, \t/* ---###-- */\n0x36, \t/* --##-##- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0xfc, \t/* ######-- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x67  ('g') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x76, \t/* -###-##- */\n0xce, \t/* ##--###- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7e, \t/* -######- */\n0x06, \t/* -----##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n\n\t/* 0x68  ('h') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xe0, \t/* ###----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x6c, \t/* -##-##-- */\n0x76, \t/* -###-##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0xe6, \t/* ###--##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x69  ('i') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x6a  ('j') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x00, \t/* -------- */\n0x1c, \t/* ---###-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0x6b  ('k') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xe0, \t/* ###----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x66, \t/* -##--##- */\n0x6c, \t/* -##-##-- */\n0x78, \t/* -####--- */\n0x6c, \t/* -##-##-- */\n0x66, \t/* -##--##- */\n0xe6, \t/* ###--##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x6c  ('l') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x6d  ('m') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0xfe, \t/* #######- */\n0xd6, \t/* ##-#-##- */\n0xd6, \t/* ##-#-##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x6e  ('n') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xdc, \t/* ##-###-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x6f  ('o') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x70  ('p') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xdc, \t/* ##-###-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x7c, \t/* -#####-- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n0x00, \t/* -------- */\n\n\t/* 0x71  ('q') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x76, \t/* -###-##- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x7c, \t/* -#####-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x1e, \t/* ---####- */\n0x00, \t/* -------- */\n\n\t/* 0x72  ('r') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xdc, \t/* ##-###-- */\n0x66, \t/* -##--##- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x73  ('s') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0x70, \t/* -###---- */\n0x1c, \t/* ---###-- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x74  ('t') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0xfc, \t/* ######-- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x36, \t/* --##-##- */\n0x1c, \t/* ---###-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x75  ('u') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x76  ('v') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x10, \t/* ---#---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x77  ('w') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xd6, \t/* ##-#-##- */\n0xd6, \t/* ##-#-##- */\n0xfe, \t/* #######- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x78  ('x') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x79  ('y') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xce, \t/* ##--###- */\n0x76, \t/* -###-##- */\n0x06, \t/* -----##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n\n\t/* 0x7a  ('z') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0x8c, \t/* #---##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x62, \t/* -##---#- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x7b  ('{') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x0e, \t/* ----###- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x70, \t/* -###---- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x0e, \t/* ----###- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x7c  ('|') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x7d  ('}') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x70, \t/* -###---- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x0e, \t/* ----###- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x70, \t/* -###---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x7e  ('~') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x7f        */\n0x00, \t/* -------- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x00, \t/* -------- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x80        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x81        */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x82        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x1f, \t/* ---##### */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x83        */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x1f, \t/* ---##### */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x84        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n\n\t/* 0x85        */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n\n\t/* 0x86        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x1f, \t/* ---##### */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n\n\t/* 0x87        */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x1f, \t/* ---##### */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n\n\t/* 0x88        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xf8, \t/* #####--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x89        */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0xf8, \t/* #####--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x8a        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x8b        */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x8c        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xf8, \t/* #####--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n\n\t/* 0x8d        */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0xf8, \t/* #####--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n\n\t/* 0x8e        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n\n\t/* 0x8f        */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0xff, \t/* ######## */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n\n\t/* 0x90        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x91        */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x92        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x3f, \t/* --###### */\n0x30, \t/* --##---- */\n0x3f, \t/* --###### */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x93        */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6f, \t/* -##-#### */\n0x60, \t/* -##----- */\n0x7f, \t/* -####### */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x94        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n\n\t/* 0x95        */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n\n\t/* 0x96        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7f, \t/* -####### */\n0x60, \t/* -##----- */\n0x6f, \t/* -##-#### */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n\n\t/* 0x97        */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6f, \t/* -##-#### */\n0x60, \t/* -##----- */\n0x6f, \t/* -##-#### */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n\n\t/* 0x98        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfc, \t/* ######-- */\n0x0c, \t/* ----##-- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x99        */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0xec, \t/* ###-##-- */\n0x0c, \t/* ----##-- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x9a        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x9b        */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0xef, \t/* ###-#### */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x9c        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfc, \t/* ######-- */\n0x0c, \t/* ----##-- */\n0xec, \t/* ###-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n\n\t/* 0x9d        */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0xec, \t/* ###-##-- */\n0x0c, \t/* ----##-- */\n0xec, \t/* ###-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n\n\t/* 0x9e        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0xef, \t/* ###-#### */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n\n\t/* 0x9f        */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0xef, \t/* ###-#### */\n0x00, \t/* -------- */\n0xef, \t/* ###-#### */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n\n\t/* 0xa0        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x82, \t/* #-----#- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xa1        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x3c, \t/* --####-- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n\n\t/* 0xa2        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x10, \t/* ---#---- */\n0x7c, \t/* -#####-- */\n0xd6, \t/* ##-#-##- */\n0xd0, \t/* ##-#---- */\n0xd0, \t/* ##-#---- */\n0xd6, \t/* ##-#-##- */\n0x7c, \t/* -#####-- */\n0x10, \t/* ---#---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xa3        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n0x60, \t/* -##----- */\n0x66, \t/* -##--##- */\n0xf6, \t/* ####-##- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xa4        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x3c, \t/* --####-- */\n0x62, \t/* -##---#- */\n0x60, \t/* -##----- */\n0xf8, \t/* #####--- */\n0x60, \t/* -##----- */\n0xf8, \t/* #####--- */\n0x60, \t/* -##----- */\n0x62, \t/* -##---#- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xa5        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x7e, \t/* -######- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xa6        */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x60, \t/* -##----- */\n0x1c, \t/* ---###-- */\n0x06, \t/* -----##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xa7        */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x60, \t/* -##----- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x0c, \t/* ----##-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n\n\t/* 0xa8        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xa9        */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0x81, \t/* #------# */\n0x99, \t/* #--##--# */\n0xa5, \t/* #-#--#-# */\n0xa1, \t/* #-#----# */\n0xa5, \t/* #-#--#-# */\n0x99, \t/* #--##--# */\n0x81, \t/* #------# */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xaa        */\n0x00, \t/* -------- */\n0x3c, \t/* --####-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x3e, \t/* --#####- */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xab        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x36, \t/* --##-##- */\n0x6c, \t/* -##-##-- */\n0xd8, \t/* ##-##--- */\n0x6c, \t/* -##-##-- */\n0x36, \t/* --##-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xac        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0x06, \t/* -----##- */\n0x06, \t/* -----##- */\n0x06, \t/* -----##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xad        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xae        */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0x81, \t/* #------# */\n0xb9, \t/* #-###--# */\n0xa5, \t/* #-#--#-# */\n0xb9, \t/* #-###--# */\n0xa5, \t/* #-#--#-# */\n0xa5, \t/* #-#--#-# */\n0x81, \t/* #------# */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xaf        */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xb0        */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xb1        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x7e, \t/* -######- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xb2        */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xb3        */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x18, \t/* ---##--- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xb4        */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0xc6, \t/* ##---##- */\n0x8c, \t/* #---##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x62, \t/* -##---#- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xb5        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xf6, \t/* ####-##- */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n\n\t/* 0xb6        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7f, \t/* -####### */\n0xdb, \t/* ##-##-## */\n0xdb, \t/* ##-##-## */\n0xdb, \t/* ##-##-## */\n0x7b, \t/* -####-## */\n0x1b, \t/* ---##-## */\n0x1b, \t/* ---##-## */\n0x1b, \t/* ---##-## */\n0x1b, \t/* ---##-## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xb7        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xb8        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0x8c, \t/* #---##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x62, \t/* -##---#- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xb9        */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x70, \t/* -###---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xba        */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xbb        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xd8, \t/* ##-##--- */\n0x6c, \t/* -##-##-- */\n0x36, \t/* --##-##- */\n0x6c, \t/* -##-##-- */\n0xd8, \t/* ##-##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xbc        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x77, \t/* -###-### */\n0xdf, \t/* ##-##### */\n0xd8, \t/* ##-##--- */\n0xde, \t/* ##-####- */\n0xde, \t/* ##-####- */\n0xd8, \t/* ##-##--- */\n0xd8, \t/* ##-##--- */\n0xdf, \t/* ##-##### */\n0x77, \t/* -###-### */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xbd        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x6e, \t/* -##-###- */\n0xdb, \t/* ##-##-## */\n0xdf, \t/* ##-##### */\n0xd8, \t/* ##-##--- */\n0xdb, \t/* ##-##-## */\n0x6e, \t/* -##-###- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xbe        */\n0x00, \t/* -------- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x00, \t/* -------- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xbf        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n\n\t/* 0xc0        */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xc1        */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xc2        */\n0x10, \t/* ---#---- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xc3        */\n0x00, \t/* -------- */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xc4        */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xc5        */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xc6        */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0xd8, \t/* ##-##--- */\n0xd8, \t/* ##-##--- */\n0xd8, \t/* ##-##--- */\n0xd8, \t/* ##-##--- */\n0xfe, \t/* #######- */\n0xd8, \t/* ##-##--- */\n0xd8, \t/* ##-##--- */\n0xd8, \t/* ##-##--- */\n0xde, \t/* ##-####- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xc7        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x3c, \t/* --####-- */\n0x66, \t/* -##--##- */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0x66, \t/* -##--##- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n\n\t/* 0xc8        */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x0c, \t/* ----##-- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0x66, \t/* -##--##- */\n0x60, \t/* -##----- */\n0x7c, \t/* -#####-- */\n0x60, \t/* -##----- */\n0x66, \t/* -##--##- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xc9        */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0x66, \t/* -##--##- */\n0x60, \t/* -##----- */\n0x7c, \t/* -#####-- */\n0x60, \t/* -##----- */\n0x66, \t/* -##--##- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xca        */\n0x10, \t/* ---#---- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0x66, \t/* -##--##- */\n0x60, \t/* -##----- */\n0x7c, \t/* -#####-- */\n0x60, \t/* -##----- */\n0x66, \t/* -##--##- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xcb        */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0x66, \t/* -##--##- */\n0x60, \t/* -##----- */\n0x7c, \t/* -#####-- */\n0x60, \t/* -##----- */\n0x66, \t/* -##--##- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xcc        */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x0c, \t/* ----##-- */\n0x00, \t/* -------- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xcd        */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xce        */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x66, \t/* -##--##- */\n0x00, \t/* -------- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xcf        */\n0x00, \t/* -------- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x00, \t/* -------- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xd0        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xf8, \t/* #####--- */\n0x6c, \t/* -##-##-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0xf6, \t/* ####-##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x6c, \t/* -##-##-- */\n0xf8, \t/* #####--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xd1        */\n0x00, \t/* -------- */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xe6, \t/* ###--##- */\n0xf6, \t/* ####-##- */\n0xde, \t/* ##-####- */\n0xce, \t/* ##--###- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xd2        */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xd3        */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xd4        */\n0x10, \t/* ---#---- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xd5        */\n0x00, \t/* -------- */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xd6        */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xd7        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xd8        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0xc6, \t/* ##---##- */\n0xce, \t/* ##--###- */\n0xde, \t/* ##-####- */\n0xd6, \t/* ##-#-##- */\n0xf6, \t/* ####-##- */\n0xe6, \t/* ###--##- */\n0xc6, \t/* ##---##- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xd9        */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xda        */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xdb        */\n0x10, \t/* ---#---- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xdc        */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xdd        */\n0x06, \t/* -----##- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xde        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xf0, \t/* ####---- */\n0x60, \t/* -##----- */\n0x7c, \t/* -#####-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x7c, \t/* -#####-- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xdf        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xcc, \t/* ##--##-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xd6, \t/* ##-#-##- */\n0xdc, \t/* ##-###-- */\n0x80, \t/* #------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xe0        */\n0x00, \t/* -------- */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0x7c, \t/* -#####-- */\n0xcc, \t/* ##--##-- */\n0xdc, \t/* ##-###-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xe1        */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0x7c, \t/* -#####-- */\n0xcc, \t/* ##--##-- */\n0xdc, \t/* ##-###-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xe2        */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0x7c, \t/* -#####-- */\n0xcc, \t/* ##--##-- */\n0xdc, \t/* ##-###-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xe3        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0x7c, \t/* -#####-- */\n0xcc, \t/* ##--##-- */\n0xdc, \t/* ##-###-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xe4        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0x7c, \t/* -#####-- */\n0xcc, \t/* ##--##-- */\n0xdc, \t/* ##-###-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xe5        */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0x7c, \t/* -#####-- */\n0xcc, \t/* ##--##-- */\n0xdc, \t/* ##-###-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xe6        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0xdb, \t/* ##-##-## */\n0x1b, \t/* ---##-## */\n0x7f, \t/* -####### */\n0xd8, \t/* ##-##--- */\n0xdb, \t/* ##-##-## */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xe7        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x18, \t/* ---##--- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n\n\t/* 0xe8        */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x0c, \t/* ----##-- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc0, \t/* ##------ */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xe9        */\n0x00, \t/* -------- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc0, \t/* ##------ */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xea        */\n0x00, \t/* -------- */\n0x10, \t/* ---#---- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc0, \t/* ##------ */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xeb        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc0, \t/* ##------ */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xec        */\n0x00, \t/* -------- */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xed        */\n0x00, \t/* -------- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xee        */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x66, \t/* -##--##- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xef        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xf0        */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0x7e, \t/* -######- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xf1        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0x00, \t/* -------- */\n0xdc, \t/* ##-###-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xf2        */\n0x00, \t/* -------- */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xf3        */\n0x00, \t/* -------- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xf4        */\n0x00, \t/* -------- */\n0x10, \t/* ---#---- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xf5        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xf6        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xf7        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xf8        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0xce, \t/* ##--###- */\n0xde, \t/* ##-####- */\n0xf6, \t/* ####-##- */\n0xe6, \t/* ###--##- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xf9        */\n0x00, \t/* -------- */\n0xc0, \t/* ##------ */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xfa        */\n0x00, \t/* -------- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xfb        */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xfc        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xfd        */\n0x00, \t/* -------- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xce, \t/* ##--###- */\n0x76, \t/* -###-##- */\n0x06, \t/* -----##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n\n\t/* 0xfe        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xf0, \t/* ####---- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x78, \t/* -####--- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x78, \t/* -####--- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n\n\t/* 0xff        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xce, \t/* ##--###- */\n0x76, \t/* -###-##- */\n0x06, \t/* -----##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n\n\n/* cursor shape (8x14) */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0xFF,   /* ######## */\n0xFF,   /* ######## */\n\n"
  },
  {
    "path": "docs/video/font-lat9-8x16.txt",
    "content": "\t/* 0x00        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0xc3, \t/* ##----## */\n0x99, \t/* #--##--# */\n0x99, \t/* #--##--# */\n0xf3, \t/* ####--## */\n0xe7, \t/* ###--### */\n0xe7, \t/* ###--### */\n0xff, \t/* ######## */\n0xe7, \t/* ###--### */\n0xe7, \t/* ###--### */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x01        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0x00, \t/* -------- */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x02        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x6e, \t/* -##-###- */\n0xf8, \t/* #####--- */\n0xd8, \t/* ##-##--- */\n0xd8, \t/* ##-##--- */\n0xdc, \t/* ##-###-- */\n0xd8, \t/* ##-##--- */\n0xd8, \t/* ##-##--- */\n0xd8, \t/* ##-##--- */\n0xf8, \t/* #####--- */\n0x6e, \t/* -##-###- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x03        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x6e, \t/* -##-###- */\n0xdb, \t/* ##-##-## */\n0xdb, \t/* ##-##-## */\n0xdf, \t/* ##-##### */\n0xd8, \t/* ##-##--- */\n0xdb, \t/* ##-##-## */\n0x6e, \t/* -##-###- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x04        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x10, \t/* ---#---- */\n0x38, \t/* --###--- */\n0x7c, \t/* -#####-- */\n0xfe, \t/* #######- */\n0x7c, \t/* -#####-- */\n0x38, \t/* --###--- */\n0x10, \t/* ---#---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x05        */\n0x00, \t/* -------- */\n0x88, \t/* #---#--- */\n0x88, \t/* #---#--- */\n0xf8, \t/* #####--- */\n0x88, \t/* #---#--- */\n0x88, \t/* #---#--- */\n0x00, \t/* -------- */\n0x3e, \t/* --#####- */\n0x08, \t/* ----#--- */\n0x08, \t/* ----#--- */\n0x08, \t/* ----#--- */\n0x08, \t/* ----#--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x06        */\n0x00, \t/* -------- */\n0xf8, \t/* #####--- */\n0x80, \t/* #------- */\n0xe0, \t/* ###----- */\n0x80, \t/* #------- */\n0x80, \t/* #------- */\n0x00, \t/* -------- */\n0x3e, \t/* --#####- */\n0x20, \t/* --#----- */\n0x38, \t/* --###--- */\n0x20, \t/* --#----- */\n0x20, \t/* --#----- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x07        */\n0x00, \t/* -------- */\n0x70, \t/* -###---- */\n0x88, \t/* #---#--- */\n0x80, \t/* #------- */\n0x88, \t/* #---#--- */\n0x70, \t/* -###---- */\n0x00, \t/* -------- */\n0x3c, \t/* --####-- */\n0x22, \t/* --#---#- */\n0x3c, \t/* --####-- */\n0x24, \t/* --#--#-- */\n0x22, \t/* --#---#- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x08        */\n0x00, \t/* -------- */\n0x80, \t/* #------- */\n0x80, \t/* #------- */\n0x80, \t/* #------- */\n0x80, \t/* #------- */\n0xf8, \t/* #####--- */\n0x00, \t/* -------- */\n0x3e, \t/* --#####- */\n0x20, \t/* --#----- */\n0x38, \t/* --###--- */\n0x20, \t/* --#----- */\n0x20, \t/* --#----- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x09        */\n0x11, \t/* ---#---# */\n0x44, \t/* -#---#-- */\n0x11, \t/* ---#---# */\n0x44, \t/* -#---#-- */\n0x11, \t/* ---#---# */\n0x44, \t/* -#---#-- */\n0x11, \t/* ---#---# */\n0x44, \t/* -#---#-- */\n0x11, \t/* ---#---# */\n0x44, \t/* -#---#-- */\n0x11, \t/* ---#---# */\n0x44, \t/* -#---#-- */\n0x11, \t/* ---#---# */\n0x44, \t/* -#---#-- */\n0x11, \t/* ---#---# */\n0x44, \t/* -#---#-- */\n\n\t/* 0x0a        */\n0x55, \t/* -#-#-#-# */\n0xaa, \t/* #-#-#-#- */\n0x55, \t/* -#-#-#-# */\n0xaa, \t/* #-#-#-#- */\n0x55, \t/* -#-#-#-# */\n0xaa, \t/* #-#-#-#- */\n0x55, \t/* -#-#-#-# */\n0xaa, \t/* #-#-#-#- */\n0x55, \t/* -#-#-#-# */\n0xaa, \t/* #-#-#-#- */\n0x55, \t/* -#-#-#-# */\n0xaa, \t/* #-#-#-#- */\n0x55, \t/* -#-#-#-# */\n0xaa, \t/* #-#-#-#- */\n0x55, \t/* -#-#-#-# */\n0xaa, \t/* #-#-#-#- */\n\n\t/* 0x0b        */\n0xdd, \t/* ##-###-# */\n0x77, \t/* -###-### */\n0xdd, \t/* ##-###-# */\n0x77, \t/* -###-### */\n0xdd, \t/* ##-###-# */\n0x77, \t/* -###-### */\n0xdd, \t/* ##-###-# */\n0x77, \t/* -###-### */\n0xdd, \t/* ##-###-# */\n0x77, \t/* -###-### */\n0xdd, \t/* ##-###-# */\n0x77, \t/* -###-### */\n0xdd, \t/* ##-###-# */\n0x77, \t/* -###-### */\n0xdd, \t/* ##-###-# */\n0x77, \t/* -###-### */\n\n\t/* 0x0c        */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n\n\t/* 0x0d        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n\n\t/* 0x0e        */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x0f        */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n\n\t/* 0x10        */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n\n\t/* 0x11        */\n0x00, \t/* -------- */\n0x88, \t/* #---#--- */\n0xc8, \t/* ##--#--- */\n0xa8, \t/* #-#-#--- */\n0x98, \t/* #--##--- */\n0x88, \t/* #---#--- */\n0x00, \t/* -------- */\n0x20, \t/* --#----- */\n0x20, \t/* --#----- */\n0x20, \t/* --#----- */\n0x20, \t/* --#----- */\n0x3e, \t/* --#####- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x12        */\n0x00, \t/* -------- */\n0x88, \t/* #---#--- */\n0x88, \t/* #---#--- */\n0x50, \t/* -#-#---- */\n0x50, \t/* -#-#---- */\n0x20, \t/* --#----- */\n0x00, \t/* -------- */\n0x3e, \t/* --#####- */\n0x08, \t/* ----#--- */\n0x08, \t/* ----#--- */\n0x08, \t/* ----#--- */\n0x08, \t/* ----#--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x13        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x0e, \t/* ----###- */\n0x38, \t/* --###--- */\n0xe0, \t/* ###----- */\n0x38, \t/* --###--- */\n0x0e, \t/* ----###- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x14        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xe0, \t/* ###----- */\n0x38, \t/* --###--- */\n0x0e, \t/* ----###- */\n0x38, \t/* --###--- */\n0xe0, \t/* ###----- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x15        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x06, \t/* -----##- */\n0x0c, \t/* ----##-- */\n0xfe, \t/* #######- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0xfe, \t/* #######- */\n0x60, \t/* -##----- */\n0xc0, \t/* ##------ */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x16        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x06, \t/* -----##- */\n0x1e, \t/* ---####- */\n0x7e, \t/* -######- */\n0xfe, \t/* #######- */\n0x7e, \t/* -######- */\n0x1e, \t/* ---####- */\n0x06, \t/* -----##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x17        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc0, \t/* ##------ */\n0xf0, \t/* ####---- */\n0xfc, \t/* ######-- */\n0xfe, \t/* #######- */\n0xfc, \t/* ######-- */\n0xf0, \t/* ####---- */\n0xc0, \t/* ##------ */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x18        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x7e, \t/* -######- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x19        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x7e, \t/* -######- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x1a        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x0c, \t/* ----##-- */\n0xfe, \t/* #######- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x1b        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0xfe, \t/* #######- */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x1c        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x7e, \t/* -######- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x7e, \t/* -######- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x1d        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x28, \t/* --#-#--- */\n0x6c, \t/* -##-##-- */\n0xfe, \t/* #######- */\n0x6c, \t/* -##-##-- */\n0x28, \t/* --#-#--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x1e        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x06, \t/* -----##- */\n0x36, \t/* --##-##- */\n0x66, \t/* -##--##- */\n0xfe, \t/* #######- */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x1f        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x20  (' ') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x21  ('!') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x3c, \t/* --####-- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x22  ('\"') */\n0x00, \t/* -------- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x24, \t/* --#--#-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x23  ('#') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0xfe, \t/* #######- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0xfe, \t/* #######- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x24  ('$') */\n0x00, \t/* -------- */\n0x10, \t/* ---#---- */\n0x10, \t/* ---#---- */\n0x7c, \t/* -#####-- */\n0xd6, \t/* ##-#-##- */\n0xd0, \t/* ##-#---- */\n0xd0, \t/* ##-#---- */\n0x7c, \t/* -#####-- */\n0x16, \t/* ---#-##- */\n0x16, \t/* ---#-##- */\n0xd6, \t/* ##-#-##- */\n0x7c, \t/* -#####-- */\n0x10, \t/* ---#---- */\n0x10, \t/* ---#---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x25  ('%') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc2, \t/* ##----#- */\n0xc6, \t/* ##---##- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0xc6, \t/* ##---##- */\n0x86, \t/* #----##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x26  ('&') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x27  (''') */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x28  ('(') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x0c, \t/* ----##-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x29  (')') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x2a  ('*') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x66, \t/* -##--##- */\n0x3c, \t/* --####-- */\n0xff, \t/* ######## */\n0x3c, \t/* --####-- */\n0x66, \t/* -##--##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x2b  ('+') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x7e, \t/* -######- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x2c  (',') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x2d  ('-') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x2e  ('.') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x2f  ('/') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x06, \t/* -----##- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0xc0, \t/* ##------ */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x30  ('0') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xd6, \t/* ##-#-##- */\n0xd6, \t/* ##-#-##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x31  ('1') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x38, \t/* --###--- */\n0x78, \t/* -####--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x32  ('2') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0x06, \t/* -----##- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0xc0, \t/* ##------ */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x33  ('3') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0x06, \t/* -----##- */\n0x06, \t/* -----##- */\n0x3c, \t/* --####-- */\n0x06, \t/* -----##- */\n0x06, \t/* -----##- */\n0x06, \t/* -----##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x34  ('4') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x0c, \t/* ----##-- */\n0x1c, \t/* ---###-- */\n0x3c, \t/* --####-- */\n0x6c, \t/* -##-##-- */\n0xcc, \t/* ##--##-- */\n0xfe, \t/* #######- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x1e, \t/* ---####- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x35  ('5') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xfc, \t/* ######-- */\n0x06, \t/* -----##- */\n0x06, \t/* -----##- */\n0x06, \t/* -----##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x36  ('6') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x60, \t/* -##----- */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xfc, \t/* ######-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x37  ('7') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0xc6, \t/* ##---##- */\n0x06, \t/* -----##- */\n0x06, \t/* -----##- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x38  ('8') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x39  ('9') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7e, \t/* -######- */\n0x06, \t/* -----##- */\n0x06, \t/* -----##- */\n0x06, \t/* -----##- */\n0x0c, \t/* ----##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x3a  (':') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x3b  (';') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x3c  ('<') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x06, \t/* -----##- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x0c, \t/* ----##-- */\n0x06, \t/* -----##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x3d  ('=') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x3e  ('>') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x0c, \t/* ----##-- */\n0x06, \t/* -----##- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x3f  ('?') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x40  ('@') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xde, \t/* ##-####- */\n0xde, \t/* ##-####- */\n0xde, \t/* ##-####- */\n0xdc, \t/* ##-###-- */\n0xc0, \t/* ##------ */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x41  ('A') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x10, \t/* ---#---- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x42  ('B') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfc, \t/* ######-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x7c, \t/* -#####-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x43  ('C') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x3c, \t/* --####-- */\n0x66, \t/* -##--##- */\n0xc2, \t/* ##----#- */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc2, \t/* ##----#- */\n0x66, \t/* -##--##- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x44  ('D') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xf8, \t/* #####--- */\n0x6c, \t/* -##-##-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x6c, \t/* -##-##-- */\n0xf8, \t/* #####--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x45  ('E') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0x66, \t/* -##--##- */\n0x62, \t/* -##---#- */\n0x68, \t/* -##-#--- */\n0x78, \t/* -####--- */\n0x68, \t/* -##-#--- */\n0x60, \t/* -##----- */\n0x62, \t/* -##---#- */\n0x66, \t/* -##--##- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x46  ('F') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0x66, \t/* -##--##- */\n0x62, \t/* -##---#- */\n0x68, \t/* -##-#--- */\n0x78, \t/* -####--- */\n0x68, \t/* -##-#--- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x47  ('G') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x3c, \t/* --####-- */\n0x66, \t/* -##--##- */\n0xc2, \t/* ##----#- */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xde, \t/* ##-####- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x66, \t/* -##--##- */\n0x3a, \t/* --###-#- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x48  ('H') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x49  ('I') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x4a  ('J') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x1e, \t/* ---####- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x4b  ('K') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xe6, \t/* ###--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x6c, \t/* -##-##-- */\n0x78, \t/* -####--- */\n0x78, \t/* -####--- */\n0x6c, \t/* -##-##-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0xe6, \t/* ###--##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x4c  ('L') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xf0, \t/* ####---- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x62, \t/* -##---#- */\n0x66, \t/* -##--##- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x4d  ('M') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xee, \t/* ###-###- */\n0xfe, \t/* #######- */\n0xfe, \t/* #######- */\n0xd6, \t/* ##-#-##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x4e  ('N') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xe6, \t/* ###--##- */\n0xf6, \t/* ####-##- */\n0xfe, \t/* #######- */\n0xde, \t/* ##-####- */\n0xce, \t/* ##--###- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x4f  ('O') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x50  ('P') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfc, \t/* ######-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x7c, \t/* -#####-- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x51  ('Q') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xd6, \t/* ##-#-##- */\n0xde, \t/* ##-####- */\n0x7c, \t/* -#####-- */\n0x0c, \t/* ----##-- */\n0x0e, \t/* ----###- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x52  ('R') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfc, \t/* ######-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x7c, \t/* -#####-- */\n0x6c, \t/* -##-##-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0xe6, \t/* ###--##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x53  ('S') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x64, \t/* -##--#-- */\n0x38, \t/* --###--- */\n0x0c, \t/* ----##-- */\n0x06, \t/* -----##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x54  ('T') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0x7e, \t/* -######- */\n0x5a, \t/* -#-##-#- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x55  ('U') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x56  ('V') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x10, \t/* ---#---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x57  ('W') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xd6, \t/* ##-#-##- */\n0xd6, \t/* ##-#-##- */\n0xd6, \t/* ##-#-##- */\n0xfe, \t/* #######- */\n0xee, \t/* ###-###- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x58  ('X') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x6c, \t/* -##-##-- */\n0x7c, \t/* -#####-- */\n0x38, \t/* --###--- */\n0x38, \t/* --###--- */\n0x7c, \t/* -#####-- */\n0x6c, \t/* -##-##-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x59  ('Y') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x5a  ('Z') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0xc6, \t/* ##---##- */\n0x86, \t/* #----##- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0xc2, \t/* ##----#- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x5b  ('[') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x3c, \t/* --####-- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x5c  ('\\') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc0, \t/* ##------ */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x0c, \t/* ----##-- */\n0x06, \t/* -----##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x5d  (']') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x3c, \t/* --####-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x5e  ('^') */\n0x10, \t/* ---#---- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x5f  ('_') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n\n\t/* 0x60  ('`') */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x61  ('a') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0x7c, \t/* -#####-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x62  ('b') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xe0, \t/* ###----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x78, \t/* -####--- */\n0x6c, \t/* -##-##-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x63  ('c') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x64  ('d') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x1c, \t/* ---###-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x3c, \t/* --####-- */\n0x6c, \t/* -##-##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x65  ('e') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x66  ('f') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x64, \t/* -##--#-- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x67  ('g') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x76, \t/* -###-##- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x7c, \t/* -#####-- */\n0x0c, \t/* ----##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0x68  ('h') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xe0, \t/* ###----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x6c, \t/* -##-##-- */\n0x76, \t/* -###-##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0xe6, \t/* ###--##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x69  ('i') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x6a  ('j') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x06, \t/* -----##- */\n0x06, \t/* -----##- */\n0x00, \t/* -------- */\n0x0e, \t/* ----###- */\n0x06, \t/* -----##- */\n0x06, \t/* -----##- */\n0x06, \t/* -----##- */\n0x06, \t/* -----##- */\n0x06, \t/* -----##- */\n0x06, \t/* -----##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n\n\t/* 0x6b  ('k') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xe0, \t/* ###----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x66, \t/* -##--##- */\n0x6c, \t/* -##-##-- */\n0x78, \t/* -####--- */\n0x78, \t/* -####--- */\n0x6c, \t/* -##-##-- */\n0x66, \t/* -##--##- */\n0xe6, \t/* ###--##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x6c  ('l') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x6d  ('m') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xec, \t/* ###-##-- */\n0xfe, \t/* #######- */\n0xd6, \t/* ##-#-##- */\n0xd6, \t/* ##-#-##- */\n0xd6, \t/* ##-#-##- */\n0xd6, \t/* ##-#-##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x6e  ('n') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xdc, \t/* ##-###-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x6f  ('o') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x70  ('p') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xdc, \t/* ##-###-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x7c, \t/* -#####-- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n0x00, \t/* -------- */\n\n\t/* 0x71  ('q') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x76, \t/* -###-##- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x7c, \t/* -#####-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x1e, \t/* ---####- */\n0x00, \t/* -------- */\n\n\t/* 0x72  ('r') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xdc, \t/* ##-###-- */\n0x76, \t/* -###-##- */\n0x66, \t/* -##--##- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x73  ('s') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0x60, \t/* -##----- */\n0x38, \t/* --###--- */\n0x0c, \t/* ----##-- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x74  ('t') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x10, \t/* ---#---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0xfc, \t/* ######-- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x36, \t/* --##-##- */\n0x1c, \t/* ---###-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x75  ('u') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x76  ('v') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x77  ('w') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xd6, \t/* ##-#-##- */\n0xd6, \t/* ##-#-##- */\n0xd6, \t/* ##-#-##- */\n0xfe, \t/* #######- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x78  ('x') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x38, \t/* --###--- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x79  ('y') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7e, \t/* -######- */\n0x06, \t/* -----##- */\n0x0c, \t/* ----##-- */\n0xf8, \t/* #####--- */\n0x00, \t/* -------- */\n\n\t/* 0x7a  ('z') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0xcc, \t/* ##--##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x7b  ('{') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x0e, \t/* ----###- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x70, \t/* -###---- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x0e, \t/* ----###- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x7c  ('|') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x7d  ('}') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x70, \t/* -###---- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x0e, \t/* ----###- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x70, \t/* -###---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x7e  ('~') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x7f        */\n0x00, \t/* -------- */\n0x66, \t/* -##--##- */\n0x00, \t/* -------- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x80        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x81        */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x82        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x1f, \t/* ---##### */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x83        */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x1f, \t/* ---##### */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x84        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n\n\t/* 0x85        */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n\n\t/* 0x86        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x1f, \t/* ---##### */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n\n\t/* 0x87        */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x1f, \t/* ---##### */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n\n\t/* 0x88        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xf8, \t/* #####--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x89        */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0xf8, \t/* #####--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x8a        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x8b        */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x8c        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xf8, \t/* #####--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n\n\t/* 0x8d        */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0xf8, \t/* #####--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n\n\t/* 0x8e        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n\n\t/* 0x8f        */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0xff, \t/* ######## */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n\n\t/* 0x90        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x91        */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x92        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7f, \t/* -####### */\n0x60, \t/* -##----- */\n0x7f, \t/* -####### */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x93        */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6f, \t/* -##-#### */\n0x60, \t/* -##----- */\n0x7f, \t/* -####### */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x94        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n\n\t/* 0x95        */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n\n\t/* 0x96        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7f, \t/* -####### */\n0x60, \t/* -##----- */\n0x6f, \t/* -##-#### */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n\n\t/* 0x97        */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6f, \t/* -##-#### */\n0x60, \t/* -##----- */\n0x6f, \t/* -##-#### */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n\n\t/* 0x98        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfc, \t/* ######-- */\n0x0c, \t/* ----##-- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x99        */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0xec, \t/* ###-##-- */\n0x0c, \t/* ----##-- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x9a        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x9b        */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0xef, \t/* ###-#### */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x9c        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfc, \t/* ######-- */\n0x0c, \t/* ----##-- */\n0xec, \t/* ###-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n\n\t/* 0x9d        */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0xec, \t/* ###-##-- */\n0x0c, \t/* ----##-- */\n0xec, \t/* ###-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n\n\t/* 0x9e        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0xef, \t/* ###-#### */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n\n\t/* 0x9f        */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0xef, \t/* ###-#### */\n0x00, \t/* -------- */\n0xef, \t/* ###-#### */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n\n\t/* 0xa0        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x82, \t/* #-----#- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xa1        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x3c, \t/* --####-- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xa2        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x10, \t/* ---#---- */\n0x7c, \t/* -#####-- */\n0xd6, \t/* ##-#-##- */\n0xd0, \t/* ##-#---- */\n0xd0, \t/* ##-#---- */\n0xd0, \t/* ##-#---- */\n0xd6, \t/* ##-#-##- */\n0x7c, \t/* -#####-- */\n0x10, \t/* ---#---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xa3        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x66, \t/* -##--##- */\n0xf6, \t/* ####-##- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xa4        */\n0x00, \t/* -------- */\n0x1c, \t/* ---###-- */\n0x32, \t/* --##--#- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0xfc, \t/* ######-- */\n0x60, \t/* -##----- */\n0xfc, \t/* ######-- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x32, \t/* --##--#- */\n0x1c, \t/* ---###-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xa5        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x7e, \t/* -######- */\n0x18, \t/* ---##--- */\n0x7e, \t/* -######- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xa6        */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x60, \t/* -##----- */\n0x38, \t/* --###--- */\n0x0c, \t/* ----##-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xa7        */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0x60, \t/* -##----- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x0c, \t/* ----##-- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xa8        */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0x60, \t/* -##----- */\n0x38, \t/* --###--- */\n0x0c, \t/* ----##-- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xa9        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x3c, \t/* --####-- */\n0x42, \t/* -#----#- */\n0x99, \t/* #--##--# */\n0xa5, \t/* #-#--#-# */\n0xa1, \t/* #-#----# */\n0xa5, \t/* #-#--#-# */\n0x99, \t/* #--##--# */\n0x42, \t/* -#----#- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xaa        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x3c, \t/* --####-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x3e, \t/* --#####- */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xab        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x36, \t/* --##-##- */\n0x6c, \t/* -##-##-- */\n0xd8, \t/* ##-##--- */\n0x6c, \t/* -##-##-- */\n0x36, \t/* --##-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xac        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0x06, \t/* -----##- */\n0x06, \t/* -----##- */\n0x06, \t/* -----##- */\n0x06, \t/* -----##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xad        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xae        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x3c, \t/* --####-- */\n0x42, \t/* -#----#- */\n0xb9, \t/* #-###--# */\n0xa5, \t/* #-#--#-# */\n0xb9, \t/* #-###--# */\n0xa5, \t/* #-#--#-# */\n0xa5, \t/* #-#--#-# */\n0x42, \t/* -#----#- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xaf        */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xb0        */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xb1        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x7e, \t/* -######- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xb2        */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xb3        */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x18, \t/* ---##--- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xb4        */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0xc6, \t/* ##---##- */\n0x8c, \t/* #---##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0xc2, \t/* ##----#- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xb5        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xf6, \t/* ####-##- */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0x00, \t/* -------- */\n\n\t/* 0xb6        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7f, \t/* -####### */\n0xd6, \t/* ##-#-##- */\n0xd6, \t/* ##-#-##- */\n0x76, \t/* -###-##- */\n0x36, \t/* --##-##- */\n0x36, \t/* --##-##- */\n0x36, \t/* --##-##- */\n0x36, \t/* --##-##- */\n0x36, \t/* --##-##- */\n0x36, \t/* --##-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xb7        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xb8        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0xcc, \t/* ##--##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xb9        */\n0x30, \t/* --##---- */\n0x70, \t/* -###---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xba        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xbb        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xd8, \t/* ##-##--- */\n0x6c, \t/* -##-##-- */\n0x36, \t/* --##-##- */\n0x6c, \t/* -##-##-- */\n0xd8, \t/* ##-##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xbc        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x77, \t/* -###-### */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcf, \t/* ##--#### */\n0xcf, \t/* ##--#### */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x77, \t/* -###-### */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xbd        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x6e, \t/* -##-###- */\n0xdb, \t/* ##-##-## */\n0xdb, \t/* ##-##-## */\n0xdf, \t/* ##-##### */\n0xd8, \t/* ##-##--- */\n0xdb, \t/* ##-##-## */\n0x6e, \t/* -##-###- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xbe        */\n0x00, \t/* -------- */\n0x66, \t/* -##--##- */\n0x00, \t/* -------- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xbf        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xc0        */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xc1        */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xc2        */\n0x10, \t/* ---#---- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xc3        */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xc4        */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xc5        */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xc6        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x3e, \t/* --#####- */\n0x78, \t/* -####--- */\n0xd8, \t/* ##-##--- */\n0xd8, \t/* ##-##--- */\n0xfc, \t/* ######-- */\n0xd8, \t/* ##-##--- */\n0xd8, \t/* ##-##--- */\n0xd8, \t/* ##-##--- */\n0xd8, \t/* ##-##--- */\n0xde, \t/* ##-####- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xc7        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x3c, \t/* --####-- */\n0x66, \t/* -##--##- */\n0xc2, \t/* ##----#- */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc2, \t/* ##----#- */\n0x66, \t/* -##--##- */\n0x3c, \t/* --####-- */\n0x0c, \t/* ----##-- */\n0x66, \t/* -##--##- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n\n\t/* 0xc8        */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0x66, \t/* -##--##- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x7c, \t/* -#####-- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x66, \t/* -##--##- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xc9        */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0x66, \t/* -##--##- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x7c, \t/* -#####-- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x66, \t/* -##--##- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xca        */\n0x10, \t/* ---#---- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0x66, \t/* -##--##- */\n0x60, \t/* -##----- */\n0x7c, \t/* -#####-- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x66, \t/* -##--##- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xcb        */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0x66, \t/* -##--##- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x7c, \t/* -#####-- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x66, \t/* -##--##- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xcc        */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xcd        */\n0x06, \t/* -----##- */\n0x0c, \t/* ----##-- */\n0x00, \t/* -------- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xce        */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x66, \t/* -##--##- */\n0x00, \t/* -------- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xcf        */\n0x00, \t/* -------- */\n0x66, \t/* -##--##- */\n0x00, \t/* -------- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xd0        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xf8, \t/* #####--- */\n0x6c, \t/* -##-##-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0xf6, \t/* ####-##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x6c, \t/* -##-##-- */\n0xf8, \t/* #####--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xd1        */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xe6, \t/* ###--##- */\n0xf6, \t/* ####-##- */\n0xfe, \t/* #######- */\n0xde, \t/* ##-####- */\n0xce, \t/* ##--###- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xd2        */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xd3        */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xd4        */\n0x10, \t/* ---#---- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xd5        */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xd6        */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xd7        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x66, \t/* -##--##- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x66, \t/* -##--##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xd8        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0xc6, \t/* ##---##- */\n0xce, \t/* ##--###- */\n0xce, \t/* ##--###- */\n0xde, \t/* ##-####- */\n0xf6, \t/* ####-##- */\n0xe6, \t/* ###--##- */\n0xe6, \t/* ###--##- */\n0xc6, \t/* ##---##- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xd9        */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xda        */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xdb        */\n0x10, \t/* ---#---- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xdc        */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xdd        */\n0x06, \t/* -----##- */\n0x0c, \t/* ----##-- */\n0x00, \t/* -------- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xde        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xf0, \t/* ####---- */\n0x60, \t/* -##----- */\n0x7c, \t/* -#####-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x7c, \t/* -#####-- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xdf        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xcc, \t/* ##--##-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xd6, \t/* ##-#-##- */\n0xdc, \t/* ##-###-- */\n0x80, \t/* #------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xe0        */\n0x00, \t/* -------- */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0x7c, \t/* -#####-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xe1        */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0x7c, \t/* -#####-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xe2        */\n0x00, \t/* -------- */\n0x10, \t/* ---#---- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0x7c, \t/* -#####-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xe3        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0x7c, \t/* -#####-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xe4        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0x7c, \t/* -#####-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xe5        */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0x7c, \t/* -#####-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xe6        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0xdb, \t/* ##-##-## */\n0x1b, \t/* ---##-## */\n0x7f, \t/* -####### */\n0xd8, \t/* ##-##--- */\n0xdb, \t/* ##-##-## */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xe7        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x18, \t/* ---##--- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x00, \t/* -------- */\n\n\t/* 0xe8        */\n0x00, \t/* -------- */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xe9        */\n0x00, \t/* -------- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xea        */\n0x00, \t/* -------- */\n0x10, \t/* ---#---- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xeb        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xec        */\n0x00, \t/* -------- */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xed        */\n0x00, \t/* -------- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xee        */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x66, \t/* -##--##- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xef        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x38, \t/* --###--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xf0        */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0x7e, \t/* -######- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xf1        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0x00, \t/* -------- */\n0xdc, \t/* ##-###-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xf2        */\n0x00, \t/* -------- */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xf3        */\n0x00, \t/* -------- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xf4        */\n0x00, \t/* -------- */\n0x10, \t/* ---#---- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xf5        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xf6        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xf7        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xf8        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0xce, \t/* ##--###- */\n0xde, \t/* ##-####- */\n0xfe, \t/* #######- */\n0xf6, \t/* ####-##- */\n0xe6, \t/* ###--##- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xf9        */\n0x00, \t/* -------- */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xfa        */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xfb        */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xfc        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xfd        */\n0x00, \t/* -------- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7e, \t/* -######- */\n0x06, \t/* -----##- */\n0x0c, \t/* ----##-- */\n0xf8, \t/* #####--- */\n0x00, \t/* -------- */\n\n\t/* 0xfe        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xf0, \t/* ####---- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x7c, \t/* -#####-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x7c, \t/* -#####-- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xff        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7e, \t/* -######- */\n0x06, \t/* -----##- */\n0x0c, \t/* ----##-- */\n0xf8, \t/* #####--- */\n0x00, \t/* -------- */\n\n\n/* cursor shape (8x16) */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0xFF,   /* ######## */\n0xFF,   /* ######## */\n\n"
  },
  {
    "path": "docs/video/font-lat9-8x8.txt",
    "content": "\t/* 0x00        */\n0x7e, \t/* -######- */\n0xc3, \t/* ##----## */\n0x99, \t/* #--##--# */\n0xf3, \t/* ####--## */\n0xe7, \t/* ###--### */\n0xff, \t/* ######## */\n0xe7, \t/* ###--### */\n0x7e, \t/* -######- */\n\n\t/* 0x01        */\n0x00, \t/* -------- */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0x00, \t/* -------- */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x02        */\n0x76, \t/* -###-##- */\n0xd8, \t/* ##-##--- */\n0xd8, \t/* ##-##--- */\n0xdc, \t/* ##-###-- */\n0xd8, \t/* ##-##--- */\n0xd8, \t/* ##-##--- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n\n\t/* 0x03        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x6e, \t/* -##-###- */\n0xd8, \t/* ##-##--- */\n0xde, \t/* ##-####- */\n0xd8, \t/* ##-##--- */\n0x6e, \t/* -##-###- */\n0x00, \t/* -------- */\n\n\t/* 0x04        */\n0x10, \t/* ---#---- */\n0x38, \t/* --###--- */\n0x7c, \t/* -#####-- */\n0xfe, \t/* #######- */\n0x7c, \t/* -#####-- */\n0x38, \t/* --###--- */\n0x10, \t/* ---#---- */\n0x00, \t/* -------- */\n\n\t/* 0x05        */\n0xa0, \t/* #-#----- */\n0xa0, \t/* #-#----- */\n0xe0, \t/* ###----- */\n0xae, \t/* #-#-###- */\n0xa4, \t/* #-#--#-- */\n0x04, \t/* -----#-- */\n0x04, \t/* -----#-- */\n0x04, \t/* -----#-- */\n\n\t/* 0x06        */\n0xe0, \t/* ###----- */\n0x80, \t/* #------- */\n0xc0, \t/* ##------ */\n0x8e, \t/* #---###- */\n0x88, \t/* #---#--- */\n0x0c, \t/* ----##-- */\n0x08, \t/* ----#--- */\n0x08, \t/* ----#--- */\n\n\t/* 0x07        */\n0x60, \t/* -##----- */\n0x80, \t/* #------- */\n0x80, \t/* #------- */\n0x8c, \t/* #---##-- */\n0x6a, \t/* -##-#-#- */\n0x0c, \t/* ----##-- */\n0x0a, \t/* ----#-#- */\n0x0a, \t/* ----#-#- */\n\n\t/* 0x08        */\n0x80, \t/* #------- */\n0x80, \t/* #------- */\n0x80, \t/* #------- */\n0x8e, \t/* #---###- */\n0xe8, \t/* ###-#--- */\n0x0c, \t/* ----##-- */\n0x08, \t/* ----#--- */\n0x08, \t/* ----#--- */\n\n\t/* 0x09        */\n0x22, \t/* --#---#- */\n0x88, \t/* #---#--- */\n0x22, \t/* --#---#- */\n0x88, \t/* #---#--- */\n0x22, \t/* --#---#- */\n0x88, \t/* #---#--- */\n0x22, \t/* --#---#- */\n0x88, \t/* #---#--- */\n\n\t/* 0x0a        */\n0x55, \t/* -#-#-#-# */\n0xaa, \t/* #-#-#-#- */\n0x55, \t/* -#-#-#-# */\n0xaa, \t/* #-#-#-#- */\n0x55, \t/* -#-#-#-# */\n0xaa, \t/* #-#-#-#- */\n0x55, \t/* -#-#-#-# */\n0xaa, \t/* #-#-#-#- */\n\n\t/* 0x0b        */\n0xee, \t/* ###-###- */\n0xbb, \t/* #-###-## */\n0xee, \t/* ###-###- */\n0xbb, \t/* #-###-## */\n0xee, \t/* ###-###- */\n0xbb, \t/* #-###-## */\n0xee, \t/* ###-###- */\n0xbb, \t/* #-###-## */\n\n\t/* 0x0c        */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n\n\t/* 0x0d        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n\n\t/* 0x0e        */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x0f        */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n0xf0, \t/* ####---- */\n\n\t/* 0x10        */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n0x0f, \t/* ----#### */\n\n\t/* 0x11        */\n0x90, \t/* #--#---- */\n0xd0, \t/* ##-#---- */\n0xf0, \t/* ####---- */\n0xb4, \t/* #-##-#-- */\n0x94, \t/* #--#-#-- */\n0x04, \t/* -----#-- */\n0x04, \t/* -----#-- */\n0x07, \t/* -----### */\n\n\t/* 0x12        */\n0xa0, \t/* #-#----- */\n0xa0, \t/* #-#----- */\n0xa0, \t/* #-#----- */\n0xae, \t/* #-#-###- */\n0x44, \t/* -#---#-- */\n0x04, \t/* -----#-- */\n0x04, \t/* -----#-- */\n0x04, \t/* -----#-- */\n\n\t/* 0x13        */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n\n\t/* 0x14        */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0x00, \t/* -------- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n\n\t/* 0x15        */\n0x00, \t/* -------- */\n0x0c, \t/* ----##-- */\n0xfe, \t/* #######- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0xfe, \t/* #######- */\n0x60, \t/* -##----- */\n0x00, \t/* -------- */\n\n\t/* 0x16        */\n0x02, \t/* ------#- */\n0x0e, \t/* ----###- */\n0x3e, \t/* --#####- */\n0xfe, \t/* #######- */\n0x3e, \t/* --#####- */\n0x0e, \t/* ----###- */\n0x02, \t/* ------#- */\n0x00, \t/* -------- */\n\n\t/* 0x17        */\n0x80, \t/* #------- */\n0xe0, \t/* ###----- */\n0xf8, \t/* #####--- */\n0xfe, \t/* #######- */\n0xf8, \t/* #####--- */\n0xe0, \t/* ###----- */\n0x80, \t/* #------- */\n0x00, \t/* -------- */\n\n\t/* 0x18        */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x7e, \t/* -######- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n\n\t/* 0x19        */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x7e, \t/* -######- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n\n\t/* 0x1a        */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x0c, \t/* ----##-- */\n0xfe, \t/* #######- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x1b        */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0xfe, \t/* #######- */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x1c        */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x7e, \t/* -######- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x7e, \t/* -######- */\n0x3c, \t/* --####-- */\n0x18, \t/* ---##--- */\n\n\t/* 0x1d        */\n0x00, \t/* -------- */\n0x24, \t/* --#--#-- */\n0x66, \t/* -##--##- */\n0xff, \t/* ######## */\n0x66, \t/* -##--##- */\n0x24, \t/* --#--#-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x1e        */\n0x06, \t/* -----##- */\n0x06, \t/* -----##- */\n0x36, \t/* --##-##- */\n0x66, \t/* -##--##- */\n0xfe, \t/* #######- */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n\n\t/* 0x1f        */\n0x00, \t/* -------- */\n0xc0, \t/* ##------ */\n0x7c, \t/* -#####-- */\n0x6e, \t/* -##-###- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n\n\t/* 0x20  (' ') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x21  ('!') */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x78, \t/* -####--- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n\n\t/* 0x22  ('\"') */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x23  ('#') */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0xfe, \t/* #######- */\n0x6c, \t/* -##-##-- */\n0xfe, \t/* #######- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n\n\t/* 0x24  ('$') */\n0x30, \t/* --##---- */\n0x7c, \t/* -#####-- */\n0xc0, \t/* ##------ */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0xf8, \t/* #####--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n\n\t/* 0x25  ('%') */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xcc, \t/* ##--##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x66, \t/* -##--##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n\n\t/* 0x26  ('&') */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n\n\t/* 0x27  (''') */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x28  ('(') */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n\n\t/* 0x29  (')') */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0x00, \t/* -------- */\n\n\t/* 0x2a  ('*') */\n0x00, \t/* -------- */\n0x66, \t/* -##--##- */\n0x3c, \t/* --####-- */\n0xff, \t/* ######## */\n0x3c, \t/* --####-- */\n0x66, \t/* -##--##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x2b  ('+') */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0xfc, \t/* ######-- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x2c  (',') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n\n\t/* 0x2d  ('-') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x2e  ('.') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n\n\t/* 0x2f  ('/') */\n0x00, \t/* -------- */\n0x06, \t/* -----##- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0xc0, \t/* ##------ */\n0x00, \t/* -------- */\n\n\t/* 0x30  ('0') */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xd6, \t/* ##-#-##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n\n\t/* 0x31  ('1') */\n0x30, \t/* --##---- */\n0x70, \t/* -###---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n\n\t/* 0x32  ('2') */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0x0c, \t/* ----##-- */\n0x38, \t/* --###--- */\n0x60, \t/* -##----- */\n0xcc, \t/* ##--##-- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n\n\t/* 0x33  ('3') */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0x0c, \t/* ----##-- */\n0x38, \t/* --###--- */\n0x0c, \t/* ----##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0x34  ('4') */\n0x1c, \t/* ---###-- */\n0x3c, \t/* --####-- */\n0x6c, \t/* -##-##-- */\n0xcc, \t/* ##--##-- */\n0xfe, \t/* #######- */\n0x0c, \t/* ----##-- */\n0x1e, \t/* ---####- */\n0x00, \t/* -------- */\n\n\t/* 0x35  ('5') */\n0xfc, \t/* ######-- */\n0xc0, \t/* ##------ */\n0xf8, \t/* #####--- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0x36  ('6') */\n0x38, \t/* --###--- */\n0x60, \t/* -##----- */\n0xc0, \t/* ##------ */\n0xf8, \t/* #####--- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0x37  ('7') */\n0xfc, \t/* ######-- */\n0xcc, \t/* ##--##-- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n\n\t/* 0x38  ('8') */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0x39  ('9') */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x7c, \t/* -#####-- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x70, \t/* -###---- */\n0x00, \t/* -------- */\n\n\t/* 0x3a  (':') */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n\n\t/* 0x3b  (';') */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n\n\t/* 0x3c  ('<') */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0xc0, \t/* ##------ */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n\n\t/* 0x3d  ('=') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x3e  ('>') */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0x00, \t/* -------- */\n\n\t/* 0x3f  ('?') */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n\n\t/* 0x40  ('@') */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xde, \t/* ##-####- */\n0xde, \t/* ##-####- */\n0xde, \t/* ##-####- */\n0xc0, \t/* ##------ */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0x41  ('A') */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xfc, \t/* ######-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n\n\t/* 0x42  ('B') */\n0xfc, \t/* ######-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x7c, \t/* -#####-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n\n\t/* 0x43  ('C') */\n0x3c, \t/* --####-- */\n0x66, \t/* -##--##- */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0x66, \t/* -##--##- */\n0x3c, \t/* --####-- */\n0x00, \t/* -------- */\n\n\t/* 0x44  ('D') */\n0xf8, \t/* #####--- */\n0x6c, \t/* -##-##-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x6c, \t/* -##-##-- */\n0xf8, \t/* #####--- */\n0x00, \t/* -------- */\n\n\t/* 0x45  ('E') */\n0xfe, \t/* #######- */\n0x62, \t/* -##---#- */\n0x68, \t/* -##-#--- */\n0x78, \t/* -####--- */\n0x68, \t/* -##-#--- */\n0x62, \t/* -##---#- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n\n\t/* 0x46  ('F') */\n0xfe, \t/* #######- */\n0x62, \t/* -##---#- */\n0x68, \t/* -##-#--- */\n0x78, \t/* -####--- */\n0x68, \t/* -##-#--- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n0x00, \t/* -------- */\n\n\t/* 0x47  ('G') */\n0x3c, \t/* --####-- */\n0x66, \t/* -##--##- */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0xce, \t/* ##--###- */\n0x66, \t/* -##--##- */\n0x3e, \t/* --#####- */\n0x00, \t/* -------- */\n\n\t/* 0x48  ('H') */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xfc, \t/* ######-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n\n\t/* 0x49  ('I') */\n0x78, \t/* -####--- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0x4a  ('J') */\n0x1e, \t/* ---####- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0x4b  ('K') */\n0xe6, \t/* ###--##- */\n0x66, \t/* -##--##- */\n0x6c, \t/* -##-##-- */\n0x78, \t/* -####--- */\n0x6c, \t/* -##-##-- */\n0x66, \t/* -##--##- */\n0xe6, \t/* ###--##- */\n0x00, \t/* -------- */\n\n\t/* 0x4c  ('L') */\n0xf0, \t/* ####---- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x62, \t/* -##---#- */\n0x66, \t/* -##--##- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n\n\t/* 0x4d  ('M') */\n0xc6, \t/* ##---##- */\n0xee, \t/* ###-###- */\n0xfe, \t/* #######- */\n0xfe, \t/* #######- */\n0xd6, \t/* ##-#-##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n\n\t/* 0x4e  ('N') */\n0xc6, \t/* ##---##- */\n0xe6, \t/* ###--##- */\n0xf6, \t/* ####-##- */\n0xde, \t/* ##-####- */\n0xce, \t/* ##--###- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n\n\t/* 0x4f  ('O') */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x00, \t/* -------- */\n\n\t/* 0x50  ('P') */\n0xfc, \t/* ######-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x7c, \t/* -#####-- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n0x00, \t/* -------- */\n\n\t/* 0x51  ('Q') */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xdc, \t/* ##-###-- */\n0x78, \t/* -####--- */\n0x1c, \t/* ---###-- */\n0x00, \t/* -------- */\n\n\t/* 0x52  ('R') */\n0xfc, \t/* ######-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x7c, \t/* -#####-- */\n0x6c, \t/* -##-##-- */\n0x66, \t/* -##--##- */\n0xe6, \t/* ###--##- */\n0x00, \t/* -------- */\n\n\t/* 0x53  ('S') */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xe0, \t/* ###----- */\n0x70, \t/* -###---- */\n0x1c, \t/* ---###-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0x54  ('T') */\n0xfc, \t/* ######-- */\n0xb4, \t/* #-##-#-- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0x55  ('U') */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0x56  ('V') */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n\n\t/* 0x57  ('W') */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xd6, \t/* ##-#-##- */\n0xfe, \t/* #######- */\n0xee, \t/* ###-###- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n\n\t/* 0x58  ('X') */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n\n\t/* 0x59  ('Y') */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0x5a  ('Z') */\n0xfe, \t/* #######- */\n0xc6, \t/* ##---##- */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x66, \t/* -##--##- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n\n\t/* 0x5b  ('[') */\n0x78, \t/* -####--- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0x5c  ('\\') */\n0x00, \t/* -------- */\n0xc0, \t/* ##------ */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x0c, \t/* ----##-- */\n0x06, \t/* -----##- */\n0x00, \t/* -------- */\n\n\t/* 0x5d  (']') */\n0x78, \t/* -####--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0x5e  ('^') */\n0x18, \t/* ---##--- */\n0x3c, \t/* --####-- */\n0x66, \t/* -##--##- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x5f  ('_') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n\n\t/* 0x60  ('`') */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x61  ('a') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0x7c, \t/* -#####-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n\n\t/* 0x62  ('b') */\n0xe0, \t/* ###----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0x7c, \t/* -#####-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0xdc, \t/* ##-###-- */\n0x00, \t/* -------- */\n\n\t/* 0x63  ('c') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xc0, \t/* ##------ */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0x64  ('d') */\n0x1c, \t/* ---###-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x7c, \t/* -#####-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n\n\t/* 0x65  ('e') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xfc, \t/* ######-- */\n0xc0, \t/* ##------ */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0x66  ('f') */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n0x00, \t/* -------- */\n\n\t/* 0x67  ('g') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x76, \t/* -###-##- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x7c, \t/* -#####-- */\n0x0c, \t/* ----##-- */\n0xf8, \t/* #####--- */\n\n\t/* 0x68  ('h') */\n0xe0, \t/* ###----- */\n0x60, \t/* -##----- */\n0x6c, \t/* -##-##-- */\n0x76, \t/* -###-##- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0xe6, \t/* ###--##- */\n0x00, \t/* -------- */\n\n\t/* 0x69  ('i') */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x70, \t/* -###---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0x6a  ('j') */\n0x0c, \t/* ----##-- */\n0x00, \t/* -------- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n\n\t/* 0x6b  ('k') */\n0xe0, \t/* ###----- */\n0x60, \t/* -##----- */\n0x66, \t/* -##--##- */\n0x6c, \t/* -##-##-- */\n0x78, \t/* -####--- */\n0x6c, \t/* -##-##-- */\n0xe6, \t/* ###--##- */\n0x00, \t/* -------- */\n\n\t/* 0x6c  ('l') */\n0x70, \t/* -###---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0x6d  ('m') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0xfe, \t/* #######- */\n0xfe, \t/* #######- */\n0xd6, \t/* ##-#-##- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n\n\t/* 0x6e  ('n') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xf8, \t/* #####--- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n\n\t/* 0x6f  ('o') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0x70  ('p') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xdc, \t/* ##-###-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x7c, \t/* -#####-- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n\n\t/* 0x71  ('q') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x76, \t/* -###-##- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x7c, \t/* -#####-- */\n0x0c, \t/* ----##-- */\n0x1e, \t/* ---####- */\n\n\t/* 0x72  ('r') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xdc, \t/* ##-###-- */\n0x76, \t/* -###-##- */\n0x66, \t/* -##--##- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n0x00, \t/* -------- */\n\n\t/* 0x73  ('s') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc0, \t/* ##------ */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0xf8, \t/* #####--- */\n0x00, \t/* -------- */\n\n\t/* 0x74  ('t') */\n0x10, \t/* ---#---- */\n0x30, \t/* --##---- */\n0x7c, \t/* -#####-- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x34, \t/* --##-#-- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n\n\t/* 0x75  ('u') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n\n\t/* 0x76  ('v') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n\n\t/* 0x77  ('w') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xd6, \t/* ##-#-##- */\n0xfe, \t/* #######- */\n0xfe, \t/* #######- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n\n\t/* 0x78  ('x') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n\n\t/* 0x79  ('y') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x7c, \t/* -#####-- */\n0x0c, \t/* ----##-- */\n0xf8, \t/* #####--- */\n\n\t/* 0x7a  ('z') */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfc, \t/* ######-- */\n0x98, \t/* #--##--- */\n0x30, \t/* --##---- */\n0x64, \t/* -##--#-- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n\n\t/* 0x7b  ('{') */\n0x1c, \t/* ---###-- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0xe0, \t/* ###----- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x1c, \t/* ---###-- */\n0x00, \t/* -------- */\n\n\t/* 0x7c  ('|') */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n\n\t/* 0x7d  ('}') */\n0xe0, \t/* ###----- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x1c, \t/* ---###-- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0xe0, \t/* ###----- */\n0x00, \t/* -------- */\n\n\t/* 0x7e  ('~') */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x7f        */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0x80        */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x81        */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x82        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x1f, \t/* ---##### */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x83        */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x1f, \t/* ---##### */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x84        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n\n\t/* 0x85        */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n\n\t/* 0x86        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x1f, \t/* ---##### */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n\n\t/* 0x87        */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x1f, \t/* ---##### */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n\n\t/* 0x88        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xf8, \t/* #####--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x89        */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0xf8, \t/* #####--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x8a        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x8b        */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x8c        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xf8, \t/* #####--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n\n\t/* 0x8d        */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0xf8, \t/* #####--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n\n\t/* 0x8e        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n\n\t/* 0x8f        */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0xff, \t/* ######## */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n\n\t/* 0x90        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x91        */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x92        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7f, \t/* -####### */\n0x60, \t/* -##----- */\n0x7f, \t/* -####### */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x93        */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6f, \t/* -##-#### */\n0x60, \t/* -##----- */\n0x7f, \t/* -####### */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x94        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n\n\t/* 0x95        */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n\n\t/* 0x96        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7f, \t/* -####### */\n0x60, \t/* -##----- */\n0x6f, \t/* -##-#### */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n\n\t/* 0x97        */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6f, \t/* -##-#### */\n0x60, \t/* -##----- */\n0x6f, \t/* -##-#### */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n\n\t/* 0x98        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfc, \t/* ######-- */\n0x0c, \t/* ----##-- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x99        */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0xec, \t/* ###-##-- */\n0x0c, \t/* ----##-- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x9a        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x9b        */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0xef, \t/* ###-#### */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0x9c        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfc, \t/* ######-- */\n0x0c, \t/* ----##-- */\n0xec, \t/* ###-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n\n\t/* 0x9d        */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0xec, \t/* ###-##-- */\n0x0c, \t/* ----##-- */\n0xec, \t/* ###-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n\n\t/* 0x9e        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0xef, \t/* ###-#### */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n\n\t/* 0x9f        */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0xef, \t/* ###-#### */\n0x00, \t/* -------- */\n0xef, \t/* ###-#### */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n\n\t/* 0xa0        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xc6, \t/* ##---##- */\n0xfe, \t/* #######- */\n\n\t/* 0xa1        */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x78, \t/* -####--- */\n0x30, \t/* --##---- */\n\n\t/* 0xa2        */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xc0, \t/* ##------ */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n\n\t/* 0xa3        */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x64, \t/* -##--#-- */\n0xf0, \t/* ####---- */\n0x60, \t/* -##----- */\n0xe6, \t/* ###--##- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n\n\t/* 0xa4        */\n0x38, \t/* --###--- */\n0x64, \t/* -##--#-- */\n0xf0, \t/* ####---- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n0x64, \t/* -##--#-- */\n0x38, \t/* --###--- */\n0x00, \t/* -------- */\n\n\t/* 0xa5        */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0xfc, \t/* ######-- */\n0x30, \t/* --##---- */\n0xfc, \t/* ######-- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n\n\t/* 0xa6        */\n0x48, \t/* -#--#--- */\n0x78, \t/* -####--- */\n0x84, \t/* #----#-- */\n0x60, \t/* -##----- */\n0x18, \t/* ---##--- */\n0x84, \t/* #----#-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xa7        */\n0x3e, \t/* --#####- */\n0x61, \t/* -##----# */\n0x3c, \t/* --####-- */\n0x66, \t/* -##--##- */\n0x66, \t/* -##--##- */\n0x3c, \t/* --####-- */\n0x86, \t/* #----##- */\n0x7c, \t/* -#####-- */\n\n\t/* 0xa8        */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xc0, \t/* ##------ */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0xf8, \t/* #####--- */\n0x00, \t/* -------- */\n\n\t/* 0xa9        */\n0x7c, \t/* -#####-- */\n0x82, \t/* #-----#- */\n0x9a, \t/* #--##-#- */\n0xa2, \t/* #-#---#- */\n0xa2, \t/* #-#---#- */\n0x9a, \t/* #--##-#- */\n0x82, \t/* #-----#- */\n0x7c, \t/* -#####-- */\n\n\t/* 0xaa        */\n0x3c, \t/* --####-- */\n0x6c, \t/* -##-##-- */\n0x3e, \t/* --#####- */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xab        */\n0x00, \t/* -------- */\n0x33, \t/* --##--## */\n0x66, \t/* -##--##- */\n0xcc, \t/* ##--##-- */\n0x66, \t/* -##--##- */\n0x33, \t/* --##--## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xac        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xfc, \t/* ######-- */\n0x0c, \t/* ----##-- */\n0x0c, \t/* ----##-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xad        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xae        */\n0x7c, \t/* -#####-- */\n0x82, \t/* #-----#- */\n0xb2, \t/* #-##--#- */\n0xaa, \t/* #-#-#-#- */\n0xb2, \t/* #-##--#- */\n0xaa, \t/* #-#-#-#- */\n0x82, \t/* #-----#- */\n0x7c, \t/* -#####-- */\n\n\t/* 0xaf        */\n0xff, \t/* ######## */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xb0        */\n0x70, \t/* -###---- */\n0xd8, \t/* ##-##--- */\n0x70, \t/* -###---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xb1        */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0xfc, \t/* ######-- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n\n\t/* 0xb2        */\n0x70, \t/* -###---- */\n0xd8, \t/* ##-##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0xf8, \t/* #####--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xb3        */\n0x70, \t/* -###---- */\n0xd8, \t/* ##-##--- */\n0x30, \t/* --##---- */\n0xd8, \t/* ##-##--- */\n0x70, \t/* -###---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xb4        */\n0x6c, \t/* -##-##-- */\n0xfe, \t/* #######- */\n0xcc, \t/* ##--##-- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x66, \t/* -##--##- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n\n\t/* 0xb5        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xf6, \t/* ####-##- */\n0xc0, \t/* ##------ */\n\n\t/* 0xb6        */\n0x7f, \t/* -####### */\n0xdb, \t/* ##-##-## */\n0x7b, \t/* -####-## */\n0x3b, \t/* --###-## */\n0x1b, \t/* ---##-## */\n0x1b, \t/* ---##-## */\n0x1b, \t/* ---##-## */\n0x00, \t/* -------- */\n\n\t/* 0xb7        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xb8        */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n0xfc, \t/* ######-- */\n0x98, \t/* #--##--- */\n0x30, \t/* --##---- */\n0x64, \t/* -##--#-- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n\n\t/* 0xb9        */\n0x60, \t/* -##----- */\n0xe0, \t/* ###----- */\n0x60, \t/* -##----- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xba        */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xbb        */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0x66, \t/* -##--##- */\n0x33, \t/* --##--## */\n0x66, \t/* -##--##- */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xbc        */\n0x7e, \t/* -######- */\n0xd8, \t/* ##-##--- */\n0xd8, \t/* ##-##--- */\n0xdc, \t/* ##-###-- */\n0xd8, \t/* ##-##--- */\n0xd8, \t/* ##-##--- */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n\n\t/* 0xbd        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0xdb, \t/* ##-##-## */\n0xde, \t/* ##-####- */\n0xd8, \t/* ##-##--- */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n\n\t/* 0xbe        */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xbf        */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x00, \t/* -------- */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x60, \t/* -##----- */\n0x66, \t/* -##--##- */\n0x3c, \t/* --####-- */\n\n\t/* 0xc0        */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xfc, \t/* ######-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n\n\t/* 0xc1        */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xfc, \t/* ######-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n\n\t/* 0xc2        */\n0x78, \t/* -####--- */\n0x84, \t/* #----#-- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xfc, \t/* ######-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n\n\t/* 0xc3        */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xfc, \t/* ######-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n\n\t/* 0xc4        */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xfc, \t/* ######-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n\n\t/* 0xc5        */\n0x30, \t/* --##---- */\n0x48, \t/* -#--#--- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xfc, \t/* ######-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n\n\t/* 0xc6        */\n0x3e, \t/* --#####- */\n0x78, \t/* -####--- */\n0xd8, \t/* ##-##--- */\n0xfc, \t/* ######-- */\n0xd8, \t/* ##-##--- */\n0xd8, \t/* ##-##--- */\n0xde, \t/* ##-####- */\n0x00, \t/* -------- */\n\n\t/* 0xc7        */\n0x3c, \t/* --####-- */\n0x66, \t/* -##--##- */\n0xc0, \t/* ##------ */\n0xc0, \t/* ##------ */\n0x66, \t/* -##--##- */\n0x3c, \t/* --####-- */\n0x0c, \t/* ----##-- */\n0x78, \t/* -####--- */\n\n\t/* 0xc8        */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0xfe, \t/* #######- */\n0x62, \t/* -##---#- */\n0x78, \t/* -####--- */\n0x62, \t/* -##---#- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n\n\t/* 0xc9        */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0xfe, \t/* #######- */\n0x62, \t/* -##---#- */\n0x78, \t/* -####--- */\n0x62, \t/* -##---#- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n\n\t/* 0xca        */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0xfe, \t/* #######- */\n0x62, \t/* -##---#- */\n0x78, \t/* -####--- */\n0x62, \t/* -##---#- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n\n\t/* 0xcb        */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0xfe, \t/* #######- */\n0x62, \t/* -##---#- */\n0x78, \t/* -####--- */\n0x62, \t/* -##---#- */\n0xfe, \t/* #######- */\n0x00, \t/* -------- */\n\n\t/* 0xcc        */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xcd        */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xce        */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xcf        */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xd0        */\n0xf8, \t/* #####--- */\n0x6c, \t/* -##-##-- */\n0x66, \t/* -##--##- */\n0xf6, \t/* ####-##- */\n0x66, \t/* -##--##- */\n0x6c, \t/* -##-##-- */\n0xf8, \t/* #####--- */\n0x00, \t/* -------- */\n\n\t/* 0xd1        */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0xe6, \t/* ###--##- */\n0xf6, \t/* ####-##- */\n0xde, \t/* ##-####- */\n0xce, \t/* ##--###- */\n0xc6, \t/* ##---##- */\n0x00, \t/* -------- */\n\n\t/* 0xd2        */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xd3        */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xd4        */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xd5        */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xd6        */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xd7        */\n0x00, \t/* -------- */\n0x6c, \t/* -##-##-- */\n0x38, \t/* --###--- */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xd8        */\n0x3e, \t/* --#####- */\n0x6c, \t/* -##-##-- */\n0xde, \t/* ##-####- */\n0xd6, \t/* ##-#-##- */\n0xf6, \t/* ####-##- */\n0x6c, \t/* -##-##-- */\n0xf8, \t/* #####--- */\n0x00, \t/* -------- */\n\n\t/* 0xd9        */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xda        */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xdb        */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xdc        */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xdd        */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xde        */\n0xf0, \t/* ####---- */\n0x60, \t/* -##----- */\n0x7c, \t/* -#####-- */\n0x66, \t/* -##--##- */\n0x7c, \t/* -#####-- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n0x00, \t/* -------- */\n\n\t/* 0xdf        */\n0x7c, \t/* -#####-- */\n0xc6, \t/* ##---##- */\n0xc6, \t/* ##---##- */\n0xcc, \t/* ##--##-- */\n0xc6, \t/* ##---##- */\n0xd6, \t/* ##-#-##- */\n0xdc, \t/* ##-###-- */\n0x80, \t/* #------- */\n\n\t/* 0xe0        */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0x7c, \t/* -#####-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n\n\t/* 0xe1        */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0x7c, \t/* -#####-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n\n\t/* 0xe2        */\n0x78, \t/* -####--- */\n0x84, \t/* #----#-- */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0x7c, \t/* -#####-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n\n\t/* 0xe3        */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0x7c, \t/* -#####-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n\n\t/* 0xe4        */\n0x6c, \t/* -##-##-- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0x7c, \t/* -#####-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n\n\t/* 0xe5        */\n0x38, \t/* --###--- */\n0x6c, \t/* -##-##-- */\n0x78, \t/* -####--- */\n0x0c, \t/* ----##-- */\n0x7c, \t/* -#####-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n\n\t/* 0xe6        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7e, \t/* -######- */\n0x1b, \t/* ---##-## */\n0x7e, \t/* -######- */\n0xd8, \t/* ##-##--- */\n0x7e, \t/* -######- */\n0x00, \t/* -------- */\n\n\t/* 0xe7        */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xc0, \t/* ##------ */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x18, \t/* ---##--- */\n0x70, \t/* -###---- */\n\n\t/* 0xe8        */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xfc, \t/* ######-- */\n0xc0, \t/* ##------ */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xe9        */\n0x0c, \t/* ----##-- */\n0x18, \t/* ---##--- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xfc, \t/* ######-- */\n0xc0, \t/* ##------ */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xea        */\n0x78, \t/* -####--- */\n0x84, \t/* #----#-- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xfc, \t/* ######-- */\n0xc0, \t/* ##------ */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xeb        */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xfc, \t/* ######-- */\n0xc0, \t/* ##------ */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xec        */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x70, \t/* -###---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xed        */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x70, \t/* -###---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xee        */\n0x70, \t/* -###---- */\n0xd8, \t/* ##-##--- */\n0x00, \t/* -------- */\n0x70, \t/* -###---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xef        */\n0x00, \t/* -------- */\n0xd8, \t/* ##-##--- */\n0x00, \t/* -------- */\n0x70, \t/* -###---- */\n0x30, \t/* --##---- */\n0x30, \t/* --##---- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xf0        */\n0x78, \t/* -####--- */\n0x70, \t/* -###---- */\n0x18, \t/* ---##--- */\n0x7c, \t/* -#####-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xf1        */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0xf8, \t/* #####--- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n\n\t/* 0xf2        */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xf3        */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xf4        */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xf5        */\n0x76, \t/* -###-##- */\n0xdc, \t/* ##-###-- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xf6        */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x78, \t/* -####--- */\n0x00, \t/* -------- */\n\n\t/* 0xf7        */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0xfc, \t/* ######-- */\n0x00, \t/* -------- */\n0x30, \t/* --##---- */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n\n\t/* 0xf8        */\n0x00, \t/* -------- */\n0x00, \t/* -------- */\n0x7c, \t/* -#####-- */\n0xdc, \t/* ##-###-- */\n0xfc, \t/* ######-- */\n0xec, \t/* ###-##-- */\n0xf8, \t/* #####--- */\n0x00, \t/* -------- */\n\n\t/* 0xf9        */\n0x60, \t/* -##----- */\n0x30, \t/* --##---- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n\n\t/* 0xfa        */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n\n\t/* 0xfb        */\n0x78, \t/* -####--- */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n\n\t/* 0xfc        */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x76, \t/* -###-##- */\n0x00, \t/* -------- */\n\n\t/* 0xfd        */\n0x18, \t/* ---##--- */\n0x30, \t/* --##---- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x7c, \t/* -#####-- */\n0x0c, \t/* ----##-- */\n0xf8, \t/* #####--- */\n\n\t/* 0xfe        */\n0xf0, \t/* ####---- */\n0x60, \t/* -##----- */\n0x78, \t/* -####--- */\n0x6c, \t/* -##-##-- */\n0x6c, \t/* -##-##-- */\n0x78, \t/* -####--- */\n0x60, \t/* -##----- */\n0xf0, \t/* ####---- */\n\n\t/* 0xff        */\n0xcc, \t/* ##--##-- */\n0x00, \t/* -------- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0xcc, \t/* ##--##-- */\n0x7c, \t/* -#####-- */\n0x0c, \t/* ----##-- */\n0xf8, \t/* #####--- */\n\n\n/* cursor shape (8x8) */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0x00,   /* -------- */\n0xFF,   /* ######## */\n0xFF,   /* ######## */\n\n"
  },
  {
    "path": "drivers/block/Makefile",
    "content": "# fiwix/drivers/block/Makefile\n#\n# Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n# Distributed under the terms of the Fiwix License.\n#\n\n.c.o:\n\t$(CC) $(CFLAGS) -c -o $@ $<\n\nOBJS = dma.o floppy.o part.o ata.o ata_pci.o ata_hd.o atapi.o atapi_cd.o \\\n       ramdisk.o blk_queue.o\n\nall:\t$(OBJS)\n\nclean:\n\trm -f *.o\n\n"
  },
  {
    "path": "drivers/block/ata.c",
    "content": "/*\n * fiwix/drivers/block/ata.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/ata.h>\n#include <fiwix/ata_pci.h>\n#include <fiwix/ata_hd.h>\n#include <fiwix/atapi_cd.h>\n#include <fiwix/devices.h>\n#include <fiwix/sleep.h>\n#include <fiwix/sched.h>\n#include <fiwix/cpu.h>\n#include <fiwix/pic.h>\n#include <fiwix/irq.h>\n#include <fiwix/pci.h>\n#include <fiwix/fs.h>\n#include <fiwix/blk_queue.h>\n#include <fiwix/mm.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstatic struct fs_operations ata_driver_fsop = {\n\t0,\n\t0,\n\n\tata_open,\n\tata_close,\n\tNULL,\t\t\t/* read */\n\tNULL,\t\t\t/* write */\n\tata_ioctl,\n\tata_llseek,\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lockup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tata_read,\n\tata_write,\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nstruct ide *ide_table;\n\nstatic struct ide default_ide_table[NR_IDE_CTRLS] = {\n\t{ IDE_PRIMARY, \"primary\", IDE0_BASE, IDE0_CTRL, 0, IDE0_IRQ, 0, 0, &ide0_timer, { 0 }, 0, 0,\n\t\t{\n\t\t\t{ IDE_MASTER, \"master\", \"hda\", IDE0_MAJOR, 0, IDE_MASTER_MSF, 0, 0, 0, 0, 0, 0, 0, 0, { 0 }, { 0 }, { 0 }, 0, 0, 0, 0, {{ 0 }} },\n\t\t\t{ IDE_SLAVE, \"slave\", \"hdb\", IDE0_MAJOR, 0, IDE_SLAVE_MSF, 0, 0, 0, 0, 0, 0, 0, 0, { 0 }, { 0 }, { 0 }, 0, 0, 0, 0, {{ 0 }} }\n\t\t}\n\t},\n\t{ IDE_SECONDARY, \"secondary\", IDE1_BASE, IDE1_CTRL, 0, IDE1_IRQ, 0, 0, &ide1_timer, { 0 }, 0, 0,\n\t\t{\n\t\t\t{ IDE_MASTER, \"master\", \"hdc\", IDE1_MAJOR, 0, IDE_MASTER_MSF, 0, 0, 0, 0, 0, 0, 0, 0, { 0 }, { 0 }, { 0 }, 0, 0, 0, 0, {{ 0 }} },\n\t\t\t{ IDE_SLAVE, \"slave\", \"hdd\", IDE1_MAJOR, 0, IDE_SLAVE_MSF, 0, 0, 0, 0, 0, 0, 0, 0, { 0 }, { 0 }, { 0 }, 0, 0, 0, 0, {{ 0 }} }\n\t\t}\n\t}\n};\n\nstatic struct device ide_device[NR_IDE_CTRLS] = {\n\t{\n\t\t\"ide0\",\n\t\tIDE0_MAJOR,\n\t\t{ 0, 0, 0, 0, 0, 0, 0, 0 },\n\t\tNULL,\n\t\tNULL,\n\t\t&ata_driver_fsop,\n\t\tNULL,\n\t\tNULL,\n\t\tNULL\n\t},\n\t{\n\t\t\"ide1\",\n\t\tIDE1_MAJOR,\n\t\t{ 0, 0, 0, 0, 0, 0, 0, 0 },\n\t\tNULL,\n\t\tNULL,\n\t\t&ata_driver_fsop,\n\t\tNULL,\n\t\tNULL,\n\t\tNULL\n\t}\n};\n\nstatic struct interrupt irq_config_ide[NR_IDE_CTRLS] = {\n\t{ 0, \"ide0\", &irq_ide0, NULL },\n\t{ 0, \"ide1\", &irq_ide1, NULL }\n};\n\n\nstatic void ata_identify_device(struct ide *ide, struct ata_drv *drive)\n{\n\tint cmd, status;\n\n\tif((status = ata_select_drv(ide, drive->num, ATA_CHS_MODE, 0))) {\n\t\t/* some controllers return 0xFF to indicate a non-drive condition */\n\t\tif(status == 0xFF) {\n\t\t\treturn;\n\t\t}\n\t\tprintk(\"WARNING: %s(): error on device '%s'.\\n\", __FUNCTION__, drive->dev_name);\n\t\tata_error(ide, status);\n\t}\n\n\tcmd = (drive->flags & DRIVE_IS_ATAPI) ? ATAPI_IDENTIFY_PACKET : ATA_IDENTIFY;\n\n\toutport_b(ide->base + ATA_FEATURES, 0);\n\toutport_b(ide->base + ATA_SECCNT, 0);\n\toutport_b(ide->base + ATA_SECTOR, 0);\n\toutport_b(ide->base + ATA_LCYL, 0);\n\toutport_b(ide->base + ATA_HCYL, 0);\n\tata_set_timeout(ide, WAIT_FOR_DISK, WAKEUP_AND_RETURN);\n\toutport_b(ide->base + ATA_COMMAND, cmd);\n\tif(ide->wait_interrupt) {\n\t\tsleep(ide, PROC_UNINTERRUPTIBLE);\n\t}\n}\n\nstatic int identify_drive(struct ide *ide, struct ata_drv *drive)\n{\n\tshort int status;\n\tunsigned char *buffer, *buffer2;\n\tint n;\n\n\t/* read device identification using a 16bit transfer */\n\tata_identify_device(ide, drive);\n\tstatus = inport_b(ide->base + ATA_STATUS);\n\tif((status & (ATA_STAT_RDY | ATA_STAT_DRQ)) != (ATA_STAT_RDY | ATA_STAT_DRQ)) {\n\t\treturn 1;\n\t}\n\tif(!(buffer = (void *)kmalloc(ATA_HD_SECTSIZE))) {\n\t\treturn 1;\n\t}\n\tinport_sw(ide->base + ATA_DATA, (void *)buffer, ATA_HD_SECTSIZE / sizeof(short int));\n\n\t/* re-read again using a 32bit transfer */\n\tata_identify_device(ide, drive);\n\tstatus = inport_b(ide->base + ATA_STATUS);\n\tif((status & (ATA_STAT_RDY | ATA_STAT_DRQ)) != (ATA_STAT_RDY | ATA_STAT_DRQ)) {\n\t\tkfree((unsigned int)buffer);\n\t\treturn 1;\n\t}\n\tif(!(buffer2 = (void *)kmalloc(ATA_HD_SECTSIZE))) {\n\t\tkfree((unsigned int)buffer);\n\t\treturn 1;\n\t}\n\tinport_sl(ide->base + ATA_DATA, (void *)buffer2, ATA_HD_SECTSIZE / sizeof(unsigned int));\n\n\t/* now compare results */\n\tdrive->flags |= DRIVE_HAS_DATA32;\n\tfor(n = 0; n < ATA_HD_SECTSIZE; n++) {\n\t\tif(buffer[n] != buffer2[n]) {\n\t\t\t/* not good, fall back to 16bits */\n\t\t\tdrive->flags &= ~DRIVE_HAS_DATA32;\n\t\t\tbreak;\n\t\t}\n\t}\n\tkfree((unsigned int)buffer2);\n\tmemcpy_b(&drive->ident, (void *)buffer, sizeof(struct ata_drv_ident));\n\tkfree((unsigned int)buffer);\n\n\n\t/* some basic checks to make sure that data received makes sense */\n\tif(drive->ident.logic_cyls > 0x7F00 &&\n\t   drive->ident.logic_heads > 0x7F00 &&\n\t   drive->ident.logic_spt > 0x7F00 &&\n\t   drive->ident.buffer_cache > 0x7F00) {\n\t\tmemset_b(&drive->ident, 0, sizeof(struct ata_drv_ident));\n\t\treturn 1;\n\t}\n\n\tif(drive->flags & DRIVE_IS_ATAPI) {\n\t\tif(((drive->ident.gen_config >> 8) & 0x1F) == ATAPI_IS_CDROM) {\n\t\t\tdrive->flags |= DRIVE_IS_CDROM;\n\t\t}\n\t\tif(drive->ident.gen_config & 0x3) {\n\t\t\tprintk(\"WARNING: %s(): packet size must be 16 bytes!\\n\");\n\t\t}\n\t}\n\n\t/* more checks */\n\tif(!(drive->flags & DRIVE_IS_CDROM) &&\n\t   (!drive->ident.logic_cyls ||\n\t   !drive->ident.logic_heads ||\n\t   !drive->ident.logic_spt)) {\n\t\tmemset_b(&drive->ident, 0, sizeof(struct ata_drv_ident));\n\t\treturn 1;\n\t}\n\n\treturn 0;\n}\n\nstatic void get_device_size(struct ata_drv *drive)\n{\n\tif(drive->ident.capabilities & ATA_HAS_LBA) {\n\t\tdrive->lba_cyls = drive->ident.logic_cyls;\n\t\tdrive->lba_heads = drive->ident.logic_heads;\n\t\tdrive->lba_factor = 0;\n\n\t\twhile(drive->lba_cyls > 1023) {\n\t\t\tif(drive->lba_heads < 255) {\n\t\t\t\tdrive->lba_cyls >>= 1;\n\t\t\t\tdrive->lba_heads <<= 1;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdrive->lba_factor++;\n\t\t}\n\t\tdrive->nr_sects = drive->ident.tot_sectors | (drive->ident.tot_sectors2 << 16);\n\t}\n\n\t/* some old disk drives (ATA or ATA2) don't specify total sectors */\n\tif(!(drive->ident.capabilities & ATA_HAS_LBA)) {\n\t\tif(drive->nr_sects == 0) {\n\t\t\tdrive->nr_sects = drive->ident.logic_cyls * drive->ident.logic_heads * drive->ident.logic_spt;\n\t\t}\n\t}\n\n}\n\nstatic int get_piomode(struct ata_drv *drive)\n{\n\tint piomode;\n\n\tpiomode = 0;\n\n\tif(drive->ident.fields_validity & ATA_HAS_ADVANCED_PIO) {\n\t\tif(drive->ident.adv_pio_modes & 1) {\n\t\t\tpiomode = 3;\n\t\t}\n\t\tif(drive->ident.adv_pio_modes & 2) {\n\t\t\tpiomode = 4;\n\t\t}\n\t}\n\n\treturn piomode;\n}\n\nstatic int get_udma(struct ata_drv *drive)\n{\n\tint n, udma;\n\n\tudma = 0;\n\n\t/*\n\t * The support for DMA is only for drives which already have UDMA\n\t * enabled (by BIOS).\n\t */\n\tif(drive->ident.ultradma >> 8) {\n\t\tfor(n = 7; n >= 0; n--) {\n\t\t\tif((drive->ident.ultradma >> 8) & (1 << n)) {\n\t\t\t\tudma = n;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn udma;\n}\n\nstatic int get_ata(struct ata_drv *drive)\n{\n\tint ata;\n\n\tata = 3;\t/* minimum is ATA-3 */\n\twhile(drive->ident.majorver & (1 << (ata + 1))) {\n\t\tata++;\n\t}\n\n\tif(!ata) {\n\t\tata = 1;\t/* now minimum is ATA-1 */\n\t\twhile(drive->ident.majorver & (1 << (ata + 1))) {\n\t\t\tata++;\n\t\t}\n\t}\n\n\treturn ata;\n}\n\nstatic void show_capabilities(struct ide *ide, struct ata_drv *drive)\n{\n\tunsigned int cyl, hds, sect;\n\t__loff_t size;\n\tint ksize, nrsectors;\n\n\tif(!(drive->flags & (DRIVE_IS_DISK | DRIVE_IS_CDROM))) {\n\t\treturn;\n\t}\n\n\tcyl = drive->ident.logic_cyls;\n\thds = drive->ident.logic_heads;\n\tsect = drive->ident.logic_spt;\n\n\tif(drive->ident.fields_validity & ATA_HAS_CURR_VALUES) {\n\t\tcyl = drive->ident.cur_log_cyls;\n\t\thds = drive->ident.cur_log_heads;\n\t\tsect = drive->ident.cur_log_spt;\n\t}\n\n\tdrive->pio_mode = get_piomode(drive);\n\tdrive->udma_mode = get_udma(drive);\n\n\tsize = (__loff_t)drive->nr_sects * BPS;\n\tsize = size >> 10;\n\tif(size < 1024) {\n\t\t/* the size is less than 1MB (will be reported in KB) */\n\t\tksize = size;\n\t\tsize = 0;\n\t} else {\n\t\tsize = size >> 10;\n\t\tksize = 0;\n\t}\n\n\tprintk(\"%s\\t\\t\\t\\t\", drive->dev_name);\n\tprintk(\"%s %s \", ide->name, drive->name);\n\n\tif(!(drive->flags & DRIVE_IS_ATAPI)) {\n\t\tprintk(\"ATA\");\n\t\tprintk(\"%d\", get_ata(drive));\n\t} else {\n\t\tprintk(\"ATAPI\");\n\t}\n\n\tswap_asc_word(drive->ident.model_number, 40);\n\tif(drive->flags & DRIVE_IS_DISK) {\n\t\tif(ksize) {\n\t\t\tprintk(\" disk drive %dKB\\n\", ksize);\n\t\t} else {\n\t\t\tprintk(\" disk drive %dMB\\n\", (unsigned int)size);\n\t\t}\n\t\tprintk(\"                                model=%s\\n\", drive->ident.model_number);\n\t\tif(drive->nr_sects < ATA_MIN_LBA) {\n\t\t\tprintk(\"\\t\\t\\t\\tCHS=%d/%d/%d\", cyl, hds, sect);\n\t\t} else {\n\t\t\tdrive->flags |= DRIVE_REQUIRES_LBA;\n\t\t\tprintk(\"\\t\\t\\t\\tsectors=%d\", drive->nr_sects);\n\t\t}\n\t\tprintk(\" cache=%dKB\\n\", drive->ident.buffer_cache >> 1);\n\n\t\t/* default values for 'xfer' */\n\t\tdrive->xfer.read_cmd = ATA_READ_PIO;\n\t\tdrive->xfer.write_cmd = ATA_WRITE_PIO;\n\t}\n\n\tif(drive->flags & DRIVE_IS_CDROM) {\n\t\tprintk(\" CDROM drive\\n\");\n\t\tprintk(\"\\t\\t\\t\\tmodel=%s\\n\", drive->ident.model_number);\n\t\tprintk(\"\\t\\t\\t\\tcache=%dKB\\n\", drive->ident.buffer_cache >> 1);\n\t}\n\n\t/* default common values for 'xfer' */\n\tdrive->xfer.copy_read_fn = inport_sw;\n\tdrive->xfer.copy_write_fn = outport_sw;\n\tdrive->xfer.copy_raw_factor = 2;\t/* 16bit */\n\n\tdrive->multi = 1;\n\tprintk(\"\\t\\t\\t\\tPIO%d\", drive->pio_mode);\n\tif((drive->ident.rw_multiple & 0xFF) > 1) {\n\t\t/*\n\t\t * Some very old controllers report a value of 16 here but they\n\t\t * don't support read or write multiple in PIO mode. So far,\n\t\t * I can detect these old controlers because they report a zero\n\t\t * in the Advanced PIO Data Transfer Supported Field (word 64).\n\t\t */\n\t\tif(drive->pio_mode > 0) {\n\t\t\tdrive->flags |= DRIVE_HAS_RW_MULTIPLE;\n\t\t\tdrive->xfer.read_cmd = ATA_READ_MULTIPLE_PIO;\n\t\t\tdrive->xfer.write_cmd = ATA_WRITE_MULTIPLE_PIO;\n\t\t\tdrive->multi = drive->ident.rw_multiple & 0xFF;\n\t\t\tnrsectors = PAGE_SIZE / ATA_HD_SECTSIZE;\n\t\t\tdrive->multi = MIN(drive->multi, nrsectors);\n\t\t}\n\t}\n\n#ifdef CONFIG_PCI\n\tif(drive->ident.capabilities & ATA_HAS_DMA && drive->ident.ultradma) {\n\t\tif(ide->pci_dev && ide->pci_dev->bar[4] > 0) {\n\t\t\tif(drive->flags & DRIVE_IS_DISK) {\n\t\t\t\tdrive->flags |= DRIVE_HAS_DMA;\n\t\t\t\tdrive->xfer.read_cmd = ATA_READ_DMA;\n\t\t\t\tdrive->xfer.write_cmd = ATA_WRITE_DMA;\n\t\t\t\tprintk(\", UDMA%d\", drive->udma_mode);\n\t\t\t}\n\t\t}\n\t}\n#endif /* CONFIG_PCI */\n\n\tif(drive->flags & DRIVE_HAS_DATA32) {\n\t\tprintk(\", 32bit\");\n\t\tdrive->xfer.copy_read_fn = inport_sl;\n\t\tdrive->xfer.copy_write_fn = outport_sl;\n\t\tdrive->xfer.copy_raw_factor = 4;\n\t} else {\n\t\tprintk(\", 16bit\");\n\t}\n\tprintk(\", multi %d\", drive->multi);\n\tif(drive->flags & DRIVE_HAS_RW_MULTIPLE) {\n\t\tprintk(\"(%d)\", drive->ident.rw_multiple & 0xFF);\n\t}\n\n\tif(drive->ident.capabilities & ATA_HAS_LBA) {\n\t\tdrive->flags |= DRIVE_REQUIRES_LBA;\n\t\tprintk(\", LBA\");\n\t}\n\n\tprintk(\"\\n\");\n}\n\nstatic int ata_softreset(struct ide *ide)\n{\n\tint error;\n\tunsigned short int dev_type;\n\n\terror = 0;\n\n\t/* select drive 0 (don't care of ATA_STAT_BSY bit) */\n\toutport_b(ide->base + ATA_DRVHD, ATA_CHS_MODE);\n\tata_delay();\n\n\t/* prepare for an interrupt */\n\tata_set_timeout(ide, WAIT_FOR_DISK, WAKEUP_AND_RETURN);\n\toutport_b(ide->ctrl + ATA_DEV_CTRL, ATA_DEVCTR_SRST);\n\tata_delay();\n\toutport_b(ide->ctrl + ATA_DEV_CTRL, 0);\n\tata_delay();\n\n\t/* select drive 0 (don't care of ATA_STAT_BSY bit) */\n\toutport_b(ide->base + ATA_DRVHD, ATA_CHS_MODE);\n\tata_delay();\n\tif(ide->wait_interrupt) {\n\t\tsleep(ide, PROC_UNINTERRUPTIBLE);\n\t}\n\n\tif(ata_wait_nobusy(ide)) {\n\t\tprintk(\"WARNING: %s(): reset error on ide%d(0).\\n\", __FUNCTION__, ide->channel);\n\t\terror = 1;\n\t} else {\n\t\t/* find out the device type */\n\t\tif(inport_b(ide->base + ATA_SECCNT) == 1 && inport_b(ide->base + ATA_SECTOR) == 1) {\n\t\t\tdev_type = (inport_b(ide->base + ATA_HCYL) << 8) | inport_b(ide->base + ATA_LCYL);\n\t\t\tswitch(dev_type) {\n\t\t\t\tcase 0xEB14:\n\t\t\t\t\tide->drive[IDE_MASTER].flags |= DRIVE_IS_ATAPI;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 0x0:\n\t\t\t\tdefault:\n\t\t\t\t\tide->drive[IDE_MASTER].flags |= DRIVE_IS_DISK;\n\t\t\t}\n\t\t}\n\t}\n\n\t/* select drive 1 (don't care of ATA_STAT_BSY bit) */\n\toutport_b(ide->base + ATA_DRVHD, ATA_CHS_MODE + (1 << 4));\n\tata_delay();\n\n\tif(ata_wait_nobusy(ide)) {\n\t\tprintk(\"WARNING: %s(): reset error on ide%d(1).\\n\", __FUNCTION__, ide->channel);\n\t\t/* select drive 0 (don't care of ATA_STAT_BSY bit) */\n\t\toutport_b(ide->base + ATA_DRVHD, ATA_CHS_MODE);\n\t\tata_delay();\n\t\tata_wait_nobusy(ide);\n\t\terror |= (1 << 4);\n\t}\n\n\toutport_b(ide->ctrl + ATA_DEV_CTRL, 0);\n\tata_delay();\n\tif(error > 1) {\n\t\treturn error;\n\t}\n\n\t/* find out the device type */\n\tif(inport_b(ide->base + ATA_SECCNT) == 1 && inport_b(ide->base + ATA_SECTOR) == 1) {\n\t\tdev_type = (inport_b(ide->base + ATA_HCYL) << 8) | inport_b(ide->base + ATA_LCYL);\n\t\tswitch(dev_type) {\n\t\t\tcase 0xEB14:\n\t\t\t\tide->drive[IDE_SLAVE].flags |= DRIVE_IS_ATAPI;\n\t\t\t\tbreak;\n\t\t\tcase 0x0:\n\t\t\tdefault:\n\t\t\t\tide->drive[IDE_SLAVE].flags |= DRIVE_IS_DISK;\n\t\t}\n\t}\n\n\treturn error;\n}\n\nstatic void sector2chs(__off_t offset, int *cyl, int *head, int *sector, struct ata_drv_ident *ident)\n{\n\tint r;\n\n\t*cyl = offset / (ident->logic_spt * ident->logic_heads);\n\tr = offset % (ident->logic_spt * ident->logic_heads);\n\t*head = r / ident->logic_spt;\n\t*sector = (r % ident->logic_spt) + 1;\n}\n\nvoid irq_ide0(int num, struct sigcontext *sc)\n{\n\tstruct ide *ide;\n\n\tide = &ide_table[IDE_PRIMARY];\n\tif(!ide->wait_interrupt) {\n\t\tprintk(\"WARNING: %s(): unexpected interrupt!\\n\", __FUNCTION__);\n\t} else {\n\t\tide->irq_timeout = ide->wait_interrupt = 0;\n\t\tata_end_request(ide);\n\t}\n}\n\nvoid irq_ide1(int num, struct sigcontext *sc)\n{\n\tstruct ide *ide;\n\n\tide = &ide_table[IDE_SECONDARY];\n\tif(!ide->wait_interrupt) {\n\t\tprintk(\"WARNING: %s(): unexpected interrupt!\\n\", __FUNCTION__);\n\t} else {\n\t\tide->irq_timeout = ide->wait_interrupt = 0;\n\t\tata_end_request(ide);\n\t}\n}\n\nvoid ide0_timer(unsigned int arg)\n{\n\tstruct ide *ide;\n\n\tide = &ide_table[IDE_PRIMARY];\n\tide->irq_timeout = 1;\n\tide->wait_interrupt = 0;\n\tata_end_request(ide);\n}\n\nvoid ide1_timer(unsigned int arg)\n{\n\tstruct ide *ide;\n\n\tide = &ide_table[IDE_SECONDARY];\n\tide->irq_timeout = 1;\n\tide->wait_interrupt = 0;\n\tata_end_request(ide);\n}\n\nvoid ata_error(struct ide *ide, int status)\n{\n\tint error;\n\n\tif(status & ATA_STAT_ERR) {\n\t\terror = inport_b(ide->base + ATA_ERROR);\n\t\tif(error) {\n\t\t\tprintk(\"error=0x%x [\", error);\n\t\t\tif(error & ATA_ERR_AMNF) {\n\t\t\t\tprintk(\"address mark not found, \");\n\t\t\t}\n\t\t\tif(error & ATA_ERR_TK0NF) {\n\t\t\t\tprintk(\"track 0 not found (no media) or media error, \");\n\t\t\t}\n\t\t\tif(error & ATA_ERR_ABRT) {\n\t\t\t\tprintk(\"command aborted, \");\n\t\t\t}\n\t\t\tif(error & ATA_ERR_MCR) {\n\t\t\t\tprintk(\"media change requested, \");\n\t\t\t}\n\t\t\tif(error & ATA_ERR_IDNF) {\n\t\t\t\tprintk(\"id mark not found, \");\n\t\t\t}\n\t\t\tif(error & ATA_ERR_MC) {\n\t\t\t\tprintk(\"media changer, \");\n\t\t\t}\n\t\t\tif(error & ATA_ERR_UNC) {\n\t\t\t\tprintk(\"uncorrectable data, \");\n\t\t\t}\n\t\t\tif(error & ATA_ERR_BBK) {\n\t\t\t\tprintk(\"bad block, \");\n\t\t\t}\n\t\t\tprintk(\"]\");\n\t\t}\n\t}\n\tif(status & ATA_STAT_DWF) {\n\t\tprintk(\"device fault, \");\n\t}\n\tif(status & ATA_STAT_BSY) {\n\t\tprintk(\"device busy, \");\n\t}\n\tprintk(\"\\n\");\n}\n\nvoid ata_delay(void)\n{\n\tint n;\n\n\tfor(n = 0; n < 10000; n++) {\n\t\tNOP();\n\t}\n}\n\nvoid ata_wait400ns(struct ide *ide)\n{\n\tint n;\n\n\t/* wait 400ns */\n\tfor(n = 0; n < 4; n++) {\n\t\tinport_b(ide->ctrl + ATA_ALT_STATUS);\n\t}\n}\n\nint ata_wait_nobusy(struct ide *ide)\n{\n\tint n, retries, status;\n\n\tstatus = 0;\n\tSET_ATA_RDY_RETR(retries);\n\n\tfor(n = 0; n < retries; n++) {\n\t\tstatus = inport_b(ide->base + ATA_STATUS);\n\t\tif(!(status & ATA_STAT_BSY)) {\n\t\t\treturn 0;\n\t\t}\n\t\tata_delay();\n\t}\n\treturn status;\n}\n\nint ata_wait_state(struct ide *ide, unsigned char state)\n{\n\tint n, retries, status;\n\n\tstatus = 0;\n\tSET_ATA_RDY_RETR(retries);\n\n\tfor(n = 0; n < retries; n++) {\n\t\tstatus = inport_b(ide->base + ATA_STATUS);\n\t\tif(!(status & ATA_STAT_BSY)) {\n\t\t\tif(status & (ATA_STAT_ERR | ATA_STAT_DWF)) {\n\t\t\t\treturn status;\n\t\t\t}\n\t\t\tif(status & state) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t\tata_delay();\n\t}\n\n\treturn status;\n}\n\nint ata_io(struct ide *ide, struct ata_drv *drive, __off_t offset, int nrsectors)\n{\n\tint cyl, sector, head;\n\n\tif(drive->flags & DRIVE_REQUIRES_LBA) {\n\t\tif(!ata_select_drv(ide, drive->num, ATA_LBA_MODE, offset >> 24)) {\n\t\t\toutport_b(ide->base + ATA_FEATURES, 0);\n\t\t\toutport_b(ide->base + ATA_SECCNT, nrsectors);\n\t\t\toutport_b(ide->base + ATA_LOWLBA, offset & 0xFF);\n\t\t\toutport_b(ide->base + ATA_MIDLBA, (offset >> 8) & 0xFF);\n\t\t\toutport_b(ide->base + ATA_HIGHLBA, (offset >> 16) & 0xFF);\n\t\t\treturn 0;\n\t\t}\n\t} else {\n\t\tsector2chs(offset, &cyl, &head, &sector, &drive->ident);\n\t\tif(!ata_select_drv(ide, drive->num, ATA_CHS_MODE, head)) {\n\t\t\toutport_b(ide->base + ATA_FEATURES, 0);\n\t\t\toutport_b(ide->base + ATA_SECCNT, nrsectors);\n\t\t\toutport_b(ide->base + ATA_SECTOR, sector);\n\t\t\toutport_b(ide->base + ATA_LCYL, cyl);\n\t\t\toutport_b(ide->base + ATA_HCYL, (cyl >> 8));\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tprintk(\"WARNING: %s(): %s: drive not ready.\\n\", __FUNCTION__, drive->dev_name);\n\treturn -EIO;\n}\n\nvoid ata_set_timeout(struct ide *ide, int timeout, int reason)\n{\n\tide->wait_interrupt = ide->base;\n\tide->creq.fn = ide->timer_fn;\n\tide->creq.arg = reason;\n\tadd_callout(&ide->creq, timeout);\n}\n\nvoid ata_end_request(struct ide *ide)\n{\n\tstruct blk_request *br, *brh;\n\tstruct xfer_data *xd;\n\n\tif(!ide->irq_timeout) {\n\t\tdel_callout(&ide->creq);\n\t}\n\n\tif(ide->creq.arg == WAKEUP_AND_RETURN) {\n\t\twakeup(ide);\n\t\treturn;\n\t}\n\n\tif((br = (struct blk_request *)ide->device->requests_queue)) {\n\t\tif(br->status != BR_PROCESSING) {\t/* FIXME: needed? */\n\t\t\tprintk(\"WARNING: block request: flag is %d in block %d.\\n\", br->status, br->block);\n\t\t}\n\n\t\txd = (struct xfer_data *)br->device->xfer_data;\n\t\tbr->errno = xd->rw_end_fn(ide, xd);\n\t\tif(br->errno < 0 || xd->count == xd->sectors_to_io) {\n\t\t\tide->device->requests_queue = (void *)br->next;\n\t\t\tbr->status = BR_COMPLETED;\n\t\t\tif(br->head_group) {\n\t\t\t\tbrh = br->head_group;\n\t\t\t\tbrh->left--;\n\t\t\t\tif(!brh->left) {\n\t\t\t\t\twakeup(brh);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twakeup(br);\n\t\t\t}\n\t\t\tif(br->errno < 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tif(br->next) {\n\t\t\trun_blk_request(br->device);\n\t\t}\n\t}\n}\n\nint ata_select_drv(struct ide *ide, int drive, int mode, unsigned char lba28_head)\n{\n\tint n, status;\n\n\tstatus = 0;\n\n\tfor(n = 0; n < MAX_IDE_ERR; n++) {\n\t\tif((status = ata_wait_nobusy(ide))) {\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\tif(status) {\n\t\treturn status;\n\t}\n\n\t/* 0x80 and 0x20 are for the obsolete bits #7 and #5 respectively */\n\toutport_b(ide->base + ATA_DRVHD, 0x80 | 0x20 | (mode + (drive << 4)) | lba28_head);\n\tata_wait400ns(ide);\n\n\tfor(n = 0; n < MAX_IDE_ERR; n++) {\n\t\tif((status = ata_wait_nobusy(ide))) {\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\n\treturn status;\n}\n\nstruct ide *get_ide_controller(__dev_t dev)\n{\n\tint controller;\n\n\tif(MAJOR(dev) == IDE0_MAJOR) {\n\t\tcontroller = IDE_PRIMARY;\n\t} else {\n\t\tif(MAJOR(dev) == IDE1_MAJOR) {\n\t\t\tcontroller = IDE_SECONDARY;\n\t\t} else {\n\t\t\treturn NULL;\n\t\t}\n\t}\n\treturn &ide_table[controller];\n}\n\n/* set default values */\nvoid ide_table_init(struct ide *ide, int channel)\n{\n\tmemcpy_b(ide, &default_ide_table[channel], sizeof(struct ide));\n}\n\nint ata_channel_init(struct ide *ide)\n{\n\tint drv_num;\n\tint devices, errno;\n\tstruct ata_drv *drive;\n\n\tif(!register_irq(ide->irq, &irq_config_ide[ide->channel])) {\n\t\tenable_irq(ide->irq);\n\t}\n\n\tide->device = &ide_device[ide->channel];\n\terrno = ata_softreset(ide);\n\tdevices = 0;\n\n\tide_device[ide->channel].blksize = (unsigned int *)kmalloc(MAX_MINORS * sizeof(unsigned int));\n\tide_device[ide->channel].device_data = (unsigned int *)kmalloc(MAX_MINORS * sizeof(unsigned int));\n\tmemset_l(ide_device[ide->channel].blksize, 0, MAX_MINORS);\n\tmemset_l(ide_device[ide->channel].device_data, 0, MAX_MINORS);\n\n\tfor(drv_num = IDE_MASTER; drv_num <= IDE_SLAVE; drv_num++) {\n\t\t/*\n\t\t * ata_softreset() returns error in the low nibble for master\n\t\t * devices, and in the high nibble for slave devices.\n\t\t */\n\t\tif(!(errno & (1 << (drv_num * 4)))) {\n\t\t\tdrive = &ide->drive[drv_num];\n\t\t\tif(!(identify_drive(ide, drive))) {\n\t\t\t\tget_device_size(drive);\n\t\t\t\tshow_capabilities(ide, drive);\n\t\t\t\tSET_MINOR(ide_device[ide->channel].minors, drv_num << drive->minor_shift);\n\t\t\t\tide_device[ide->channel].blksize[drv_num << drive->minor_shift] = BLKSIZE_1K;\n\t\t\t\tif(!devices) {\n\t\t\t\t\tregister_device(BLK_DEV, &ide_device[ide->channel]);\n\t\t\t\t}\n\t\t\t\tif(drive->flags & DRIVE_IS_DISK) {\n\t\t\t\t\tif(!ata_hd_init(ide, drive)) {\n\t\t\t\t\t\tdevices++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(drive->flags & DRIVE_IS_CDROM) {\n\t\t\t\t\tif(!atapi_cd_init(ide, drive)) {\n\t\t\t\t\t\tdevices++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif(!devices) {\n\t\tdisable_irq(ide->irq);\n\t\tunregister_irq(ide->irq, &irq_config_ide[ide->channel]);\n\t\tkfree((unsigned int)ide_device[ide->channel].blksize);\n\t\tkfree((unsigned int)ide_device[ide->channel].device_data);\n\t}\n\n\treturn devices;\n}\n\nint ata_open(struct inode *i, struct fd *f)\n{\n\tstruct ide *ide;\n\tstruct ata_drv *drive;\n\n\tif(!(ide = get_ide_controller(i->rdev))) {\n\t\treturn -EINVAL;\n\t}\n\n\tif(!get_device(BLK_DEV, i->rdev)) {\n\t\treturn -ENXIO;\n\t}\n\n\tdrive = &ide->drive[GET_DRIVE_NUM(i->rdev)];\n\treturn drive->fsop->open(i, f);\n}\n\nint ata_close(struct inode *i, struct fd *f)\n{\n\tstruct ide *ide;\n\tstruct ata_drv *drive;\n\n\tif(!(ide = get_ide_controller(i->rdev))) {\n\t\treturn -EINVAL;\n\t}\n\n\tif(!get_device(BLK_DEV, i->rdev)) {\n\t\treturn -ENXIO;\n\t}\n\n\tdrive = &ide->drive[GET_DRIVE_NUM(i->rdev)];\n\treturn drive->fsop->close(i, f);\n}\n\nint ata_read(__dev_t dev, __blk_t block, char *buffer, int blksize)\n{\n\tstruct ide *ide;\n\tstruct ata_drv *drive;\n\n\tif(!(ide = get_ide_controller(dev))) {\n\t\tprintk(\"%s(): no ide controller!\\n\", __FUNCTION__);\n\t\treturn -EINVAL;\n\t}\n\n\tif(!get_device(BLK_DEV, dev)) {\n\t\treturn -ENXIO;\n\t}\n\n\tdrive = &ide->drive[GET_DRIVE_NUM(dev)];\n\treturn drive->fsop->read_block(dev, block, buffer, blksize);\n}\n\nint ata_write(__dev_t dev, __blk_t block, char *buffer, int blksize)\n{\n\tstruct ide *ide;\n\tstruct ata_drv *drive;\n\n\tif(!(ide = get_ide_controller(dev))) {\n\t\tprintk(\"%s(): no ide controller!\\n\", __FUNCTION__);\n\t\treturn -EINVAL;\n\t}\n\n\tif(!get_device(BLK_DEV, dev)) {\n\t\treturn -ENXIO;\n\t}\n\n\tdrive = &ide->drive[GET_DRIVE_NUM(dev)];\n\treturn drive->fsop->write_block(dev, block, buffer, blksize);\n}\n\nint ata_ioctl(struct inode *i, struct fd *f, int cmd, unsigned int arg)\n{\n\tstruct ide *ide;\n\tstruct ata_drv *drive;\n\n\tif(!(ide = get_ide_controller(i->rdev))) {\n\t\treturn -EINVAL;\n\t}\n\n\tif(!get_device(BLK_DEV, i->rdev)) {\n\t\treturn -ENXIO;\n\t}\n\n\tdrive = &ide->drive[GET_DRIVE_NUM(i->rdev)];\n\treturn drive->fsop->ioctl(i, f, cmd, arg);\n}\n\n__loff_t ata_llseek(struct inode *i, __loff_t offset)\n{\n\tstruct ide *ide;\n\tstruct ata_drv *drive;\n\n\tif(!(ide = get_ide_controller(i->rdev))) {\n\t\treturn -EINVAL;\n\t}\n\n\tif(!get_device(BLK_DEV, i->rdev)) {\n\t\treturn -ENXIO;\n\t}\n\n\tdrive = &ide->drive[GET_DRIVE_NUM(i->rdev)];\n\treturn drive->fsop->llseek(i, offset);\n}\n\nvoid ata_init(void)\n{\n\tint channel;\n\tstruct ide *ide;\n\n\tide_table = (struct ide *)kmalloc(sizeof(struct ide) * NR_IDE_CTRLS);\n\tmemset_b(ide_table, 0, PAGE_SIZE);\n\tchannel = IDE_PRIMARY;\n\n#ifdef CONFIG_PCI\n\tchannel = ata_pci(ide_table);\n#endif /* CONFIG_PCI */\n\n\t/* ISA addresses are discarded if ide_pci() found a controller */\n\tchannel = channel ? NR_IDE_CTRLS : IDE_PRIMARY;\n\tide = ide_table;\n\twhile(channel < NR_IDE_CTRLS) {\n\t\tide_table_init(ide, channel);\n\t\tprintk(\"ide%d\t  0x%04x-0x%04x    %d\\t\", channel, ide->base, ide->base + IDE_BASE_LEN, ide->irq);\n\t\tprintk(\"ISA IDE controller\\n\");\n\t\tif(!ata_channel_init(ide)) {\n\t\t\tprintk(\"\\t\\t\\t\\tno drives detected\\n\");\n\t\t}\n\t\tchannel++;\n\t\tide++;\n\t}\n}\n"
  },
  {
    "path": "drivers/block/ata_hd.c",
    "content": "/*\n * fiwix/drivers/block/ata_hd.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/buffer.h>\n#include <fiwix/ata.h>\n#include <fiwix/ata_pci.h>\n#include <fiwix/ata_hd.h>\n#include <fiwix/ioctl.h>\n#include <fiwix/devices.h>\n#include <fiwix/timer.h>\n#include <fiwix/cpu.h>\n#include <fiwix/part.h>\n#include <fiwix/mm.h>\n#include <fiwix/sleep.h>\n#include <fiwix/sched.h>\n#include <fiwix/pci.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstatic struct fs_operations ata_hd_driver_fsop = {\n\t0,\n\t0,\n\n\tata_hd_open,\n\tata_hd_close,\n\tNULL,\t\t\t/* read */\n\tNULL,\t\t\t/* write */\n\tata_hd_ioctl,\n\tata_hd_llseek,\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lockup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tata_hd_read,\n\tata_hd_write,\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nstatic void assign_minors(__dev_t rdev, struct ata_drv *drive, struct partition *part)\n{\n\tint n, minor;\n\tstruct device *d;\n\n\tminor = 0;\n\n\tif(!(d = get_device(BLK_DEV, rdev))) {\n\t\tprintk(\"WARNING: %s(): unable to assign minors to device %d,%d.\\n\", __FUNCTION__, MAJOR(rdev), MINOR(rdev));\n\t\treturn;\n\t}\n\n\tfor(n = 0; n < NR_PARTITIONS; n++) {\n\t\tif(drive->num == IDE_MASTER) {\n\t\t\tminor = (1 << drive->minor_shift) + n;\n\t\t}\n\t\tif(drive->num == IDE_SLAVE) {\n\t\t\tminor = (1 << drive->minor_shift) + n + 1;\n\t\t}\n\t\tCLEAR_MINOR(d->minors, minor);\n\t\tif(part[n].type) {\n\t\t\tSET_MINOR(d->minors, minor);\n\t\t\t((unsigned int *)d->blksize)[minor] = BLKSIZE_1K;\n\t\t\t((unsigned int *)d->device_data)[minor] = part[n].nr_sects / 2;\n\t\t}\n\t}\n}\n\nstatic __off_t block2sector(__blk_t block, int blksize, struct partition *part, int minor)\n{\n\t__off_t sector;\n\n\tsector = block * (blksize / ATA_HD_SECTSIZE);\n\tif(minor) {\n\t\tsector += part[minor - 1].startsect;\n\t}\n\treturn sector;\n}\n\nstatic int setup_transfer(int mode, __dev_t dev, __blk_t block, char *buffer, int blksize)\n{\n\tstruct ide *ide;\n\tstruct ata_drv *drive;\n\tstruct partition *part;\n\n\tif(!(ide = get_ide_controller(dev))) {\n\t\treturn -EINVAL;\n\t}\n\n\tdrive = &ide->drive[GET_DRIVE_NUM(dev)];\n\tdrive->xd.minor = MINOR(dev);\n\tif(drive->num) {\n\t\tdrive->xd.minor &= ~(1 << IDE_SLAVE_MSF);\n\t}\n\n\tblksize = blksize ? blksize : BLKSIZE_1K;\n\tdrive->xd.sectors_to_io = MIN(blksize, PAGE_SIZE) / ATA_HD_SECTSIZE;\n\n\tpart = drive->part_table;\n\tdrive->xd.offset = block2sector(block, blksize, part, drive->xd.minor);\n\n\tif(drive->flags & DRIVE_HAS_RW_MULTIPLE) {\n\t\tdrive->xd.nrsectors = MIN(drive->xd.sectors_to_io, drive->multi);\n\t\tdrive->xd.datalen = ATA_HD_SECTSIZE * drive->xd.nrsectors;\n\t} else {\n\t\tdrive->xd.nrsectors = 1;\n\t\tdrive->xd.datalen = ATA_HD_SECTSIZE;\n\t}\n\n\tdrive->xd.dev = dev;\n\tdrive->xd.block = block;\n\tdrive->xd.buffer = buffer;\n\tdrive->xd.blksize = blksize;\n\tdrive->xd.count = 0;\n\n\tif(mode == BLK_READ) {\n#ifdef CONFIG_PCI\n\t\tdrive->xd.bm_cmd = BM_COMMAND_READ;\n#endif /* CONFIG_PCI */\n\t\tdrive->xd.cmd = drive->xfer.read_cmd;\n\t\tdrive->xd.mode = \"read\";\n\t\tdrive->xd.rw_end_fn = drive->read_end_fn;\n\t\treturn drive->read_fn(ide, drive, &drive->xd);\n\t} else {\n#ifdef CONFIG_PCI\n\t\tdrive->xd.bm_cmd = BM_COMMAND_WRITE;\n#endif /* CONFIG_PCI */\n\t\tdrive->xd.cmd = drive->xfer.write_cmd;\n\t\tdrive->xd.mode = \"write\";\n\t\tdrive->xd.rw_end_fn = drive->write_end_fn;\n\t\treturn drive->write_fn(ide, drive, &drive->xd);\n\t}\n}\n\nstatic int pio_read(struct ide *ide, struct ata_drv *drive, struct xfer_data *xd)\n{\n\tide->device->xfer_data = xd;\n\n\tif(ata_io(ide, drive, xd->offset, xd->nrsectors)) {\n\t\treturn -EIO;\n\t}\n\tata_set_timeout(ide, WAIT_FOR_DISK, 0);\n\toutport_b(ide->base + ATA_COMMAND, xd->cmd);\n\treturn 0;\n}\n\nstatic int pio_read_end(struct ide *ide, struct xfer_data *xd)\n{\n\tstruct ata_drv *drive;\n\tint status;\n\n\tdrive = &ide->drive[GET_DRIVE_NUM(xd->dev)];\n\n\tif(ide->irq_timeout) {\n\t\tstatus = inport_b(ide->base + ATA_STATUS);\n\t\tif((status & (ATA_STAT_RDY | ATA_STAT_DRQ)) != (ATA_STAT_RDY | ATA_STAT_DRQ)) {\n\t\t\tprintk(\"WARNING: %s(): %s: timeout on hard disk dev %d,%d during read.\\n\", __FUNCTION__, drive->dev_name, MAJOR(xd->dev), MINOR(xd->dev));\n\t\t\treturn -EIO;\n\t\t}\n\t}\n\n\tstatus = ata_wait_nobusy(ide);\n\tif(status & ATA_STAT_ERR) {\n\t\tprintk(\"WARNING: %s(): %s: error on hard disk dev %d,%d during read.\\n\", __FUNCTION__, drive->dev_name, MAJOR(xd->dev), MINOR(xd->dev));\n\t\tprintk(\"\\tstatus=0x%x \", status);\n\t\tata_error(ide, status);\n\t\tprintk(\"\\tblock %d, sector %d.\\n\", xd->block, xd->offset);\n\t\tinport_b(ide->base + ATA_STATUS);\t/* clear any pending interrupt */\n\t\treturn -EIO;\n\t}\n\tdrive->xfer.copy_read_fn(ide->base + ATA_DATA, (void *)xd->buffer, xd->datalen / drive->xfer.copy_raw_factor);\n\txd->count += xd->nrsectors;\n\tif(xd->count < xd->sectors_to_io) {\n\t\txd->offset += xd->nrsectors;\n\t\txd->buffer += (ATA_HD_SECTSIZE * xd->nrsectors);\n\t\treturn pio_read(ide, drive, xd);\n\t}\n\tinport_b(ide->base + ATA_STATUS);\t/* clear any pending interrupt */\n\treturn xd->sectors_to_io * ATA_HD_SECTSIZE;\n}\n\nstatic int pio_write(struct ide *ide, struct ata_drv *drive, struct xfer_data *xd)\n{\n\tint status;\n\n\tide->device->xfer_data = xd;\n\n\tif(ata_io(ide, drive, xd->offset, xd->nrsectors)) {\n\t\treturn -EIO;\n\t}\n\toutport_b(ide->base + ATA_COMMAND, drive->xfer.write_cmd);\n\tstatus = ata_wait_nobusy(ide);\n\tif(status & ATA_STAT_ERR) {\n\t\tprintk(\"WARNING: %s(): %s: error on hard disk dev %d,%d during write.\\n\", __FUNCTION__, drive->dev_name, MAJOR(xd->dev), MINOR(xd->dev));\n\t\tprintk(\"\\tstatus=0x%x \", status);\n\t\tata_error(ide, status);\n\t\tprintk(\"\\tblock %d, sector %d.\\n\", xd->block, xd->offset);\n\t\tinport_b(ide->base + ATA_STATUS);\t/* clear any pending interrupt */\n\t\treturn -EIO;\n\t}\n\tata_set_timeout(ide, WAIT_FOR_DISK, 0);\n\tdrive->xfer.copy_write_fn(ide->base + ATA_DATA, (void *)xd->buffer, xd->datalen / drive->xfer.copy_raw_factor);\n\treturn 0;\n}\n\nstatic int pio_write_end(struct ide *ide, struct xfer_data *xd)\n{\n\tstruct ata_drv *drive;\n\tint status;\n\n\tdrive = &ide->drive[GET_DRIVE_NUM(xd->dev)];\n\n\tif(ide->irq_timeout) {\n\t\tstatus = inport_b(ide->base + ATA_STATUS);\n\t\tif((status & (ATA_STAT_RDY | ATA_STAT_DRQ)) != (ATA_STAT_RDY | ATA_STAT_DRQ)) {\n\t\t\tprintk(\"WARNING: %s(): %s: timeout on hard disk dev %d,%d during write.\\n\", __FUNCTION__, drive->dev_name, MAJOR(xd->dev), MINOR(xd->dev));\n\t\t\treturn -EIO;\n\t\t}\n\t}\n\n\txd->count += xd->nrsectors;\n\tif(xd->count < xd->sectors_to_io) {\n\t\txd->offset += xd->nrsectors;\n\t\txd->buffer += (ATA_HD_SECTSIZE * xd->nrsectors);\n\t\treturn pio_write(ide, drive, xd);\n\t}\n\tinport_b(ide->base + ATA_STATUS);\t/* clear any pending interrupt */\n\treturn xd->sectors_to_io * ATA_HD_SECTSIZE;\n}\n\n#ifdef CONFIG_PCI\nstatic int dma_transfer(struct ide *ide, struct ata_drv *drive, struct xfer_data *xd)\n{\n\tide->device->xfer_data = xd;\n\n\tif(ata_io(ide, drive, xd->offset, xd->nrsectors)) {\n\t\treturn -EIO;\n\t}\n\n\tata_setup_dma(ide, drive, xd->buffer, xd->datalen, xd->bm_cmd);\n\tata_set_timeout(ide, WAIT_FOR_DISK, 0);\n\toutport_b(ide->base + ATA_COMMAND, xd->cmd);\n\tata_start_dma(ide, drive);\n\treturn 0;\n}\n\nstatic int dma_transfer_end(struct ide *ide, struct xfer_data *xd)\n{\n\tstruct ata_drv *drive;\n\tint status;\n\n\tdrive = &ide->drive[GET_DRIVE_NUM(xd->dev)];\n\n\tif(ide->irq_timeout) {\n\t\tstatus = inport_b(ide->base + ATA_STATUS);\n\t\tif((status & (ATA_STAT_RDY | ATA_STAT_DRQ)) != (ATA_STAT_RDY | ATA_STAT_DRQ)) {\n\t\t\tata_stop_dma(ide, drive);\n\t\t\tprintk(\"WARNING: %s(): %s: timeout on hard disk dev %d,%d during %s.\\n\", __FUNCTION__, drive->dev_name, MAJOR(xd->dev), MINOR(xd->dev), xd->mode);\n\t\t\treturn -EIO;\n\t\t}\n\t}\n\n\tata_stop_dma(ide, drive);\n\tstatus = ata_wait_nobusy(ide);\n\tif(status & ATA_STAT_ERR) {\n\t\tprintk(\"WARNING: %s(): %s: error on hard disk dev %d,%d during %s.\\n\", __FUNCTION__, drive->dev_name, MAJOR(xd->dev), MINOR(xd->dev), xd->mode);\n\t\tprintk(\"\\tstatus=0x%x \", status);\n\t\tata_error(ide, status);\n\t\tprintk(\"\\tblock %d, sector %d.\\n\", xd->block, xd->offset);\n\t\tinport_b(ide->base + ATA_STATUS);\t/* clear any pending interrupt */\n\t\treturn -EIO;\n\t}\n\txd->count += xd->nrsectors;\n\tif(xd->count < xd->sectors_to_io) {\n\t\txd->offset += xd->nrsectors;\n\t\txd->buffer += (ATA_HD_SECTSIZE * xd->nrsectors);\n\t\tdma_transfer(ide, drive, xd);\n\t}\n\tinport_b(ide->base + ATA_STATUS);\t/* clear any pending interrupt */\n\treturn xd->sectors_to_io * ATA_HD_SECTSIZE;\n}\n#endif /* CONFIG_PCI */\n\nint ata_hd_open(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\nint ata_hd_close(struct inode *i, struct fd *f)\n{\n\tsync_buffers(i->rdev);\n\treturn 0;\n}\n\nint ata_hd_read(__dev_t dev, __blk_t block, char *buffer, int blksize)\n{\n\treturn setup_transfer(BLK_READ, dev, block, buffer, blksize);\n}\n\nint ata_hd_write(__dev_t dev, __blk_t block, char *buffer, int blksize)\n{\n\treturn setup_transfer(BLK_WRITE, dev, block, buffer, blksize);\n}\n\nint ata_hd_ioctl(struct inode *i, struct fd *f, int cmd, unsigned int arg)\n{\n\tint minor;\n\tstruct ide *ide;\n\tstruct ata_drv *drive;\n\tstruct partition *part;\n\tstruct hd_geometry *geom;\n\tstruct device *d;\n\tint errno;\n\n\tif(!(ide = get_ide_controller(i->rdev))) {\n\t\treturn -EINVAL;\n\t}\n\n\tminor = MINOR(i->rdev);\n\tdrive = &ide->drive[GET_DRIVE_NUM(i->rdev)];\n\tif(drive->num) {\n\t\tminor &= ~(1 << IDE_SLAVE_MSF);\n\t}\n\n\tpart = drive->part_table;\n\n\tswitch(cmd) {\n\t\tcase HDIO_GETGEO:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(struct hd_geometry)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tgeom = (struct hd_geometry *)arg;\n\t                geom->cylinders = drive->ident.logic_cyls;\n\t                geom->heads = (char)drive->ident.logic_heads;\n\t                geom->sectors = (char)drive->ident.logic_spt;\n\t\t\tgeom->start = 0;\n\t\t\tif(minor) {\n\t                \tgeom->start = part[minor - 1].startsect;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase BLKGETSIZE:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned int)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tif(!minor) {\n\t\t\t\t*(int *)arg = (unsigned int)drive->nr_sects;\n\t\t\t} else {\n\t\t\t\t*(int *)arg = (unsigned int)drive->part_table[minor - 1].nr_sects;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase BLKSSZGET:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned int)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\t*(int *)arg = 512;\n\t\t\tbreak;\n\t\tcase BLKBSZGET:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned int)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\td = ide->device;\n\t\t\t*(int *)arg = ((unsigned int *)d->blksize)[MINOR(i->rdev)];\n\t\t\tbreak;\n\t\tcase BLKFLSBUF:\n\t\t\tsync_buffers(i->rdev);\n\t\t\tinvalidate_buffers(i->rdev);\n\t\t\tbreak;\n\t\tcase BLKRRPART:\n\t\t\tinvalidate_buffers(i->rdev);\n\t\t\tread_msdos_partition(i->rdev, part);\n\t\t\tassign_minors(i->rdev, drive, part);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\treturn -EINVAL;\n\t\t\tbreak;\n\t}\n\n\treturn 0;\n}\n\n__loff_t ata_hd_llseek(struct inode *i, __loff_t offset)\n{\n\treturn offset;\n}\n\nint ata_hd_init(struct ide *ide, struct ata_drv *drive)\n{\n\tint n, status, value;\n\t__dev_t rdev;\n\tstruct device *d;\n\tstruct partition *part;\n\n\trdev = 0;\n\tdrive->fsop = &ata_hd_driver_fsop;\n\tpart = drive->part_table;\n\n\tif(drive->num == IDE_MASTER) {\n\t\trdev = MKDEV(drive->major, drive->num);\n\t\tdrive->minor_shift = IDE_MASTER_MSF;\n\t\tif(!(d = get_device(BLK_DEV, rdev))) {\n\t\t\treturn -EINVAL;\n\t\t}\n\t\t((unsigned int *)d->device_data)[0] = drive->nr_sects / 2;\n\t} else {\n\t\trdev = MKDEV(drive->major, 1 << IDE_SLAVE_MSF);\n\t\tdrive->minor_shift = IDE_SLAVE_MSF;\n\t\tif(!(d = get_device(BLK_DEV, rdev))) {\n\t\t\treturn -EINVAL;\n\t\t}\n\t\t((unsigned int *)d->device_data)[1 << IDE_SLAVE_MSF] = drive->nr_sects / 2;\n\t}\n\n\t/* prepare for an interrupt */\n\tata_set_timeout(ide, WAIT_FOR_DISK, WAKEUP_AND_RETURN);\n\tif(drive->flags & DRIVE_HAS_RW_MULTIPLE) {\n\t\t/* read/write in 4KB blocks (8 sectors) as maximum */\n\t\toutport_b(ide->base + ATA_SECCNT, MIN(PAGE_SIZE / ATA_HD_SECTSIZE, drive->multi));\n\t\toutport_b(ide->base + ATA_DRVHD, drive->num << 4);\n\t\toutport_b(ide->base + ATA_COMMAND, ATA_SET_MULTIPLE_MODE);\n\t\tata_wait400ns(ide);\n\t\tstatus = inport_b(ide->base + ATA_STATUS);\n\t\tif(status & (ATA_STAT_ERR | ATA_STAT_DWF)) {\n\t\t\tprintk(\"WARNING: %s(): error while setting R/W multiple mode.\\n\", __FUNCTION__);\n\t\t\tprintk(\"\\t\");\n\t\t\tata_error(ide, status);\n\t\t\tprintk(\"\\n\");\n\t\t}\n\t}\n\tif(ide->wait_interrupt) {\n\t\tsleep(ide, PROC_UNINTERRUPTIBLE);\n\t}\n\toutport_b(ide->ctrl + ATA_DEV_CTRL, ATA_DEVCTR_DRQ);\n\n\tfor(;;) {\n\t\tstatus = inport_b(ide->base + ATA_STATUS);\n\t\tif(!(status & ATA_STAT_BSY)) {\n\t\t\tbreak;\n\t\t}\n\t\tata_delay();\n\t}\n\tif(ata_select_drv(ide, drive->num, 0, 0)) {\n\t\tprintk(\"WARNING: %s(): %s: drive not ready.\\n\", __FUNCTION__, drive->dev_name);\n\t}\n\n\tdrive->read_fn = pio_read;\n\tdrive->write_fn = pio_write;\n\tdrive->read_end_fn = pio_read_end;\n\tdrive->write_end_fn = pio_write_end;\n\n\t/* setup the transfer mode */\n\toutport_b(ide->base + ATA_FEATURES, ATA_SET_XFERMODE);\n\tif(drive->flags & DRIVE_HAS_DMA) {\n\t\tvalue = (ATA_SET_XFERMODE_UDMA | drive->udma_mode);\n\t} else {\n\t\tif(drive->pio_mode > 2) {\n\t\t\tvalue = ATA_SET_XFERMODE_PIO | drive->pio_mode;\n\t\t} else {\n\t\t\t/* PIO default mode */\n\t\t\tvalue = 0;\n\t\t}\n\t}\n\toutport_b(ide->base + ATA_SECCNT, value);\n\toutport_b(ide->base + ATA_DRVHD, drive->num << 4);\n\tata_set_timeout(ide, WAIT_FOR_DISK, WAKEUP_AND_RETURN);\n\toutport_b(ide->base + ATA_COMMAND, ATA_SET_FEATURES);\n\tif(ide->wait_interrupt) {\n\t\tsleep(ide, PROC_UNINTERRUPTIBLE);\n\t}\n\tata_wait400ns(ide);\n\tstatus = inport_b(ide->base + ATA_STATUS);\n\tif(status & (ATA_STAT_ERR | ATA_STAT_DWF)) {\n\t\tprintk(\"WARNING: %s(): error while setting transfer mode.\\n\", __FUNCTION__);\n\t\tprintk(\"\\t\");\n\t\tata_error(ide, status);\n\t\tprintk(\"\\n\");\n\t}\n\n#ifdef CONFIG_PCI\n\t/* set DMA Capable drive bit */\n\tif(drive->flags & DRIVE_HAS_DMA) {\n\t\tdrive->read_fn = drive->write_fn = dma_transfer;\n\t\tdrive->read_end_fn = drive->write_end_fn = dma_transfer_end;\n\t\tvalue = inport_b(ide->bm + BM_STATUS);\n\t\toutport_b(ide->bm + BM_STATUS, value | (BM_STATUS_DRVDMA << drive->num));\n\t}\n#endif /* CONFIG_PCI */\n\n\t/* show disk partition summary */\n\tprintk(\"\\t\\t\\t\\tpartition summary: \");\n\tif(!read_msdos_partition(rdev, part)) {\n\t\tassign_minors(rdev, drive, part);\n\t\tfor(n = 0; n < NR_PARTITIONS; n++) {\n\t\t\t/* status values other than 0x00 and 0x80 are invalid */\n\t\t\tif(part[n].status && part[n].status != 0x80) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif(part[n].type) {\n\t\t\t\tprintk(\"%s%d \", drive->dev_name, n + 1);\n\t\t\t}\n\t\t}\n\t}\n\tprintk(\"\\n\");\n\n\treturn 0;\n}\n"
  },
  {
    "path": "drivers/block/ata_pci.c",
    "content": "/*\n * fiwix/drivers/block/ata_pci.c\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kparms.h>\n#include <fiwix/ata.h>\n#include <fiwix/pci.h>\n#include <fiwix/mm.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#ifdef CONFIG_PCI\nstatic int setup_ata_device(struct ide *ide, struct pci_device *pci_dev)\n{\n\tint bar, channel, found;\n\tint size;\n\n\t/* enable I/O space */\n\tpci_write_short(pci_dev, PCI_COMMAND, pci_dev->command | PCI_COMMAND_IO);\n\n\tfor(found = 0, channel = 0; channel < NR_IDE_CTRLS; channel++, ide++) {\n\t\tbar = channel * 2;\n\t\tif(pci_dev->flags[bar] & PCI_F_ADDR_SPACE_MEM) {\n\t\t\tprintk(\"MMIO-based BAR registers are not supported.\\n\");\n\t\t\tcontinue;\n\t\t}\n\t\tprintk(\"ide%d\t  \", channel);\n\t\tfound++;\n\t\tide_table_init(ide, channel);\n\t\tsize = IDE_BASE_LEN;\n\t\tprintk(\"0x%04x-0x%04x    %d\\t\", ide->base, ide->base + size, ide->irq);\n\t\tswitch(pci_dev->prog_if & 0xF) {\n\t\t\tcase 0:\n\t\t\t\tprintk(\"ISA controller in compatibility mode-only\\n\");\n\t\t\t\tbreak;\n\t\t\tcase 0xA:\n\t\t\t\tprintk(\"ISA controller in compatibility mode, supports\\n\");\n\t\t\t\tprintk(\"\\t\\t\\t\\tboth channels switched to PCI native mode\\n\");\n\t\t\t\tbreak;\n\t\t\tcase 0x5:\n\t\t\tcase 0xF:\n\t\t\t\tif((pci_dev->prog_if & 0xF) == 0x5) {\n\t\t\t\t\tprintk(\"PCI controller in native mode-only\\n\");\n\t\t\t\t} else {\n\t\t\t\t\tprintk(\"PCI controller in native mode, supports\\n\");\n\t\t\t\t\tprintk(\"\\t\\t\\t\\tboth channels switched to ISA compatibility mode\\n\");\n\t\t\t\t}\n\t\t\t\tide->base = pci_dev->bar[bar];\n\t\t\t\tide->ctrl = pci_dev->bar[bar + 1];\n\t\t\t\tide->irq = pci_dev->irq;\n\t\t\t\tsize = pci_dev->size[bar];\n\t\t\t\tbreak;\n\t\t}\n\t\tif(!(kparms.flags & KPARMS_IDE_NODMA)) {\n\t\t\tif(pci_dev->bar[4] && (pci_dev->prog_if & 0x80)) {\n\t\t\t\tide->bm = (pci_dev->bar[4] + (channel * 8));\n\t\t\t\tprintk(\"\\t\\t\\t\\tbus master DMA at 0x%x\\n\", ide->bm);\n\t\t\t\t/* enable I/O space and bus master */\n\t\t\t\tpci_write_short(pci_dev, PCI_COMMAND, pci_dev->command | (PCI_COMMAND_IO | PCI_COMMAND_MASTER));\n\t\t\t\tide->pci_dev = pci_dev;\n\t\t\t}\n\t\t}\n\n\t\tpci_show_desc(pci_dev);\n\t\tif(!ata_channel_init(ide)) {\n\t\t\tprintk(\"\\t\\t\\t\\tno drives detected\\n\");\n\t\t}\n\t}\n\treturn found;\n}\n\nvoid ata_setup_dma(struct ide *ide, struct ata_drv *drive, char *buffer, int datalen, int mode)\n{\n\tint value;\n\tstruct prd *prd_table = &drive->xfer.prd_table;\n\n\tprd_table->addr = (unsigned int)V2P(buffer);\n\tprd_table->size = datalen;\n\tprd_table->eot = PRDT_MARK_END;\n\toutport_l(ide->bm + BM_PRD_ADDRESS, V2P((unsigned int)prd_table));\n\tvalue = inport_b(ide->bm + BM_COMMAND);\n\toutport_b(ide->bm + BM_COMMAND, value | mode);\n\n\t/* clear Error and Interrupt bits */\n\tvalue = inport_b(ide->bm + BM_STATUS);\n\toutport_b(ide->bm + BM_STATUS, value | BM_STATUS_ERROR | BM_STATUS_INTR);\n}\n\nvoid ata_start_dma(struct ide *ide, struct ata_drv *drive)\n{\n\tint value;\n\n\tvalue = inport_b(ide->bm + BM_COMMAND);\n\toutport_b(ide->bm + BM_COMMAND, value | BM_COMMAND_START);\n}\n\nvoid ata_stop_dma(struct ide *ide, struct ata_drv *drive)\n{\n\tint status;\n\n\tinport_b(ide->bm + BM_STATUS);\t/* extra read */\n\tstatus = inport_b(ide->bm + BM_STATUS);\n\toutport_b(ide->bm + BM_COMMAND, 0);\t/* stop bus master */\n\toutport_b(ide->bm + BM_STATUS, status);\n}\n\nint ata_pci(struct ide *ide)\n{\n\tstruct pci_device *pci_dev;\n\tint found;\n\n\tpci_dev = pci_device_table;\n\tfound = 0;\n\n\twhile(pci_dev) {\n\t\tif(pci_dev->class == PCI_CLASS_STORAGE_IDE) {\n\t\t\tif((found = setup_ata_device(ide, pci_dev))) {\n\t\t\t\t/* only one device is supported */\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tpci_dev = pci_dev->next;\n\t}\n\treturn found;\n}\n#endif /* CONFIG_PCI */\n"
  },
  {
    "path": "drivers/block/atapi.c",
    "content": "/*\n * fiwix/drivers/block/atapi.c\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/ata.h>\n#include <fiwix/atapi_cd.h>\n#include <fiwix/timer.h>\n#include <fiwix/cpu.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nint send_packet_command(unsigned char *pkt, struct ide *ide, struct ata_drv *drive, int len)\n{\n\tint status;\n\n\toutport_b(ide->ctrl + ATA_DEV_CTRL, 0);\n\tata_delay();\n\toutport_b(ide->base + ATA_DRVHD, ATA_CHS_MODE);\n\tata_delay();\n\tif(ata_select_drv(ide, drive->num, ATA_CHS_MODE, 0)) {\n\t\tprintk(\"WARNING: %s(): %s: drive not ready to receive PACKET command.\\n\", __FUNCTION__, drive->dev_name);\n\t\treturn 1;\n\t}\n\n\tstatus = ata_wait_state(ide, ATA_STAT_RDY);\n\toutport_b(ide->base + ATA_FEATURES, 0);\n\toutport_b(ide->base + ATA_SECCNT, 0);\n\toutport_b(ide->base + ATA_SECTOR, 0);\n\toutport_b(ide->base + ATA_LCYL, len & 0xFF);\n\toutport_b(ide->base + ATA_HCYL, len >> 8);\n\toutport_b(ide->base + ATA_DRVHD, drive->num << 4);\n\toutport_b(ide->base + ATA_COMMAND, ATA_PACKET);\n\tata_wait400ns(ide);\n\n\t/*\n\t * NOTE: Some devices prior to ATA/ATAPI-4 assert INTRQ if enabled\n\t * at this point. See IDENTIFY PACKET DEVICE, word 0, bits 5-6 to\n\t * determine if an interrupt will occur.\n\t */\n\n\tstatus = ata_wait_state(ide, ATA_STAT_DRQ);\n\tif(status) {\n\t\tprintk(\"WARNING: %s(): %s: drive not ready after PACKET sent.\\n\", __FUNCTION__, drive->dev_name);\n\t\treturn 1;\n\t}\n\n\toutport_sw(ide->base + ATA_DATA, pkt, 12 / sizeof(short int));\n\treturn 0;\n}\n\nint atapi_cmd_testunit(struct ide *ide, struct ata_drv *drive)\n{\n\tunsigned char pkt[12];\n\n\tmemset_b(pkt, 0, sizeof(pkt));\n\tpkt[0] = ATAPI_TEST_UNIT;\n\treturn send_packet_command(pkt, ide, drive, 0);\n}\n\nint atapi_cmd_reqsense(struct ide *ide, struct ata_drv *drive)\n{\n\tunsigned char pkt[12];\n\n\tmemset_b(pkt, 0, sizeof(pkt));\n\tpkt[0] = ATAPI_REQUEST_SENSE;\n\tpkt[4] = 252;\t/* this command can send up to 252 bytes */\n\treturn send_packet_command(pkt, ide, drive, 0);\n}\n\nint atapi_cmd_startstop(int action, struct ide *ide, struct ata_drv *drive)\n{\n\tunsigned char pkt[12];\n\n\tmemset_b(pkt, 0, sizeof(pkt));\n\tpkt[0] = ATAPI_START_STOP;\n\tpkt[4] = action;\n\treturn send_packet_command(pkt, ide, drive, 0);\n}\n\nint atapi_cmd_mediumrm(int action, struct ide *ide, struct ata_drv *drive)\n{\n\tunsigned char pkt[12];\n\n\tmemset_b(pkt, 0, sizeof(pkt));\n\tpkt[0] = ATAPI_MEDIUM_REMOVAL;\n\tpkt[4] = action;\n\treturn send_packet_command(pkt, ide, drive, 0);\n}\n\nint atapi_cmd_get_capacity(struct ide *ide, struct ata_drv *drive)\n{\n\tunsigned char pkt[12];\n\n\tmemset_b(pkt, 0, sizeof(pkt));\n\tpkt[0] = ATAPI_GET_CAPACITY;\n\treturn send_packet_command(pkt, ide, drive, 8);\n}\n\nint atapi_cmd_read10(struct ide *ide, struct ata_drv *drive)\n{\n\tunsigned char pkt[12];\n\tstruct xfer_data *xd;\n\n\tide->device->xfer_data = &drive->xd;\n\txd = &drive->xd;\n\n\tmemset_b(pkt, 0, sizeof(pkt));\n\tpkt[0] = ATAPI_READ10;\n\tpkt[2] = (xd->block >> 24) & 0xFF;\n\tpkt[3] = (xd->block >> 16) & 0xFF;\n\tpkt[4] = (xd->block >> 8) & 0xFF;\n\tpkt[5] = xd->block & 0xFF;\n\tpkt[7] = (xd->sectors_to_io >> 8) & 0xFF;\n\tpkt[8] = xd->sectors_to_io & 0xFF;\n\treturn send_packet_command(pkt, ide, drive, BLKSIZE_2K);\n}\n"
  },
  {
    "path": "drivers/block/atapi_cd.c",
    "content": "/*\n * fiwix/drivers/block/atapi_cd.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/buffer.h>\n#include <fiwix/atapi.h>\n#include <fiwix/ioctl.h>\n#include <fiwix/atapi_cd.h>\n#include <fiwix/devices.h>\n#include <fiwix/mm.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstatic struct fs_operations atapi_cd_driver_fsop = {\n\t0,\n\t0,\n\n\tatapi_cd_open,\n\tatapi_cd_close,\n\tNULL,\t\t\t/* read */\n\tNULL,\t\t\t/* write */\n\tatapi_cd_ioctl,\n\tatapi_cd_llseek,\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lockup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tatapi_cd_read,\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nstatic int setup_transfer(int mode, __dev_t dev, __blk_t block, char *buffer, int blksize)\n{\n\tstruct ide *ide;\n\tstruct ata_drv *drive;\n\n\tif(!(ide = get_ide_controller(dev))) {\n\t\treturn -EINVAL;\n\t}\n\n\tdrive = &ide->drive[GET_DRIVE_NUM(dev)];\n\tdrive->xd.dev = dev;\n\tdrive->xd.block = block;\n\tdrive->xd.buffer = buffer;\n\tdrive->xd.blksize = BLKSIZE_2K;\n\tdrive->xd.sectors_to_io = 1;\n\tdrive->xd.offset = 0;\n\tdrive->xd.datalen = ATAPI_CD_SECTSIZE;\n\tdrive->xd.nrsectors = 1;\n\tdrive->xd.count = 0;\n\tdrive->xd.retries = 0;\n\tdrive->xd.max_retries = MAX_CD_ERR;\n\n\tdrive->xd.mode = \"read\";\n\tdrive->xd.rw_end_fn = drive->read_end_fn;\n\treturn drive->read_fn(ide, drive, &drive->xd);\n}\n\nstatic int atapi_pio_read(struct ide *ide, struct ata_drv *drive, struct xfer_data *xd)\n{\n\tide->device->xfer_data = xd;\n\n\tif(!xd->retries) {\n\t\tif(atapi_cmd_read10(ide, drive)) {\n\t\t\tprintk(\"\\tread error on block=%d, offset=%d\\n\", xd->block, xd->block * xd->blksize);\n\t\t\treturn -EIO;\n\t\t}\n\t}\n\tata_set_timeout(ide, WAIT_FOR_CD, 0);\n\treturn 0;\n}\n\nstatic int atapi_pio_read_end(struct ide *ide, struct xfer_data *xd)\n{\n\tint status, errno, bytes;\n\tint errcode, sense_key;\n\tstruct ata_drv *drive;\n\n\tdrive = &ide->drive[GET_DRIVE_NUM(xd->dev)];\n\tstatus = 0;\n\n\twhile(xd->retries < xd->max_retries) {\n\t\txd->retries++;\n\t\tif(ide->irq_timeout) {\n\t\t\tide->irq_timeout = 0;\n\t\t\tstatus = inport_b(ide->base + ATA_STATUS);\n\t\t\tif((status & (ATA_STAT_RDY | ATA_STAT_DRQ)) != (ATA_STAT_RDY | ATA_STAT_DRQ)) {\n\t\t\t\tatapi_pio_read(ide, drive, xd);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\n\t\tstatus = inport_b(ide->base + ATA_STATUS);\n\t\tif(status & ATA_STAT_ERR) {\n\t\t\tatapi_pio_read(ide, drive, xd);\n\t\t\treturn 0;\n\t\t}\n\n\t\tif((status & (ATA_STAT_DRQ | ATA_STAT_BSY)) == 0) {\n\t\t\tbreak;\n\t\t}\n\n\t\tbytes = (inport_b(ide->base + ATA_HCYL) << 8) + inport_b(ide->base + ATA_LCYL);\n\t\tif(!bytes || bytes > xd->blksize) {\n\t\t\tbreak;\n\t\t}\n\n\t\tbytes = MAX(bytes, ATAPI_CD_SECTSIZE);\t/* only 2KB blocksize is supported */\n\t\tdrive->xfer.copy_read_fn(ide->base + ATA_DATA, (void *)xd->buffer, bytes / drive->xfer.copy_raw_factor);\n\t\t/* wait for another interrupt (FIXME: only if in PIO mode) */\n\t\treturn atapi_pio_read(ide, drive, xd);\n\t}\n\n\tif(status & ATA_STAT_ERR) {\n\t\terrno = inport_b(ide->base + ATA_ERROR);\n\t\tprintk(\"WARNING: %s(): error on cdrom device %d,%d, status=0x%x error=0x%x,\\n\", __FUNCTION__, MAJOR(xd->dev), MINOR(xd->dev), status, errno);\n\t\tif(xd->retries < xd->max_retries) {\n\t\t\txd->retries++;\n\t\t\tatapi_pio_read(ide, drive, xd);\n\t\t}\n\t\treturn 0;\n\t}\n\n\tif(xd->retries >= xd->max_retries) {\n\t\terrcode = inport_b(ide->base + ATA_ERROR);\n\t\tsense_key = (errcode & 0xF0) >> 4;\n\t\tprintk(\"WARNING: %s(): timeout on cdrom device %d,%d, status=0x%x.\\n\", __FUNCTION__, MAJOR(xd->dev), MINOR(xd->dev), status);\n\t\tprintk(\"\\tSense Key code indicates a '%s' condition.\\n\", sense_key_err[sense_key & 0xF]);\n\t\t/* no need to retry after an illegal request */\n\t\tif((sense_key & 0xF) == RS_ILLEGAL_REQUEST) {\n\t\t\treturn -EIO;\n\t\t}\n\t\t/* a drive reset may be required at this moment */\n\t\txd->retries = 0;\n\t\tif(xd->max_retries) {\n\t\t\txd->max_retries--;\n\t\t\tatapi_pio_read(ide, drive, xd);\n\t\t\treturn 0;\n\t\t}\n\t\treturn -EIO;\n\t}\n        drive->xd.count = drive->xd.sectors_to_io;\n\treturn ATAPI_CD_SECTSIZE;\n}\n\nstatic int request_sense(char *buffer, __dev_t dev, struct ide *ide, struct ata_drv *drive)\n{\n\tint errcode;\n\tint sense_key, sense_asc;\n\n\terrcode = inport_b(ide->base + ATA_ERROR);\n\tsense_key = (errcode & 0xF0) >> 4;\n\tprintk(\"\\tSense Key code indicates a '%s' condition.\\n\", sense_key_err[sense_key & 0xF]);\n\terrcode = atapi_cmd_reqsense(ide, drive);\n\tprintk(\"\\t\\treqsense() returned %d\\n\", errcode);\n\terrcode = atapi_pio_read(ide, drive, &drive->xd);\n\tprintk(\"\\t\\tatapi_pio_read() returned %d\\n\", errcode);\n\terrcode = (int)(buffer[0] & 0x7F);\n\tsense_key = (int)(buffer[2] & 0xF);\n\tsense_asc = (int)(buffer[12] & 0xFF);\n\tprintk(\"\\t\\terrcode = %x\\n\", errcode);\n\tprintk(\"\\t\\tsense_key = %x\\n\", sense_key);\n\tprintk(\"\\t\\tsense_asc = %x\\n\", sense_asc);\n\treturn errcode;\n}\n\nstatic void get_capacity(struct inode *i, struct ide *ide, struct ata_drv *drive)\n{\n\tstruct device *d;\n\tunsigned int lba, blocklen;\n\n\tif(atapi_cmd_get_capacity(ide, drive)) {\n\t\tprintk(\"WARNING: %s(): error on cdrom device %d,%d while trying to get capacity.\\n\", __FUNCTION__, MAJOR(i->rdev), MINOR(i->rdev));\n\t}\n\t/* this line just to catch interrupt */\n\tata_set_timeout(ide, WAIT_FOR_CD, WAKEUP_AND_RETURN);\n\tdrive->xfer.copy_read_fn(ide->base + ATA_DATA, (void *)&lba, 4 / drive->xfer.copy_raw_factor);\n\tdrive->xfer.copy_read_fn(ide->base + ATA_DATA, (void *)&blocklen, 4 / drive->xfer.copy_raw_factor);\n\td = ide->device;\n\t((unsigned int *)d->device_data)[MINOR(i->rdev)] = (__bswap32(lba) + 1) * (__bswap32(blocklen) / 1024);\n}\n\nint atapi_cd_open(struct inode *i, struct fd *f)\n{\n\tchar *buffer;\n\tint errcode;\n\tint sense_key, sense_asc;\n\tint retries;\n\tstruct ide *ide;\n\tstruct ata_drv *drive;\n\n\tif(!(ide = get_ide_controller(i->rdev))) {\n\t\treturn -EINVAL;\n\t}\n\n\tdrive = &ide->drive[GET_DRIVE_NUM(i->rdev)];\n\n\tif(!(buffer = (void *)kmalloc(PAGE_SIZE))) {\n\t\treturn -ENOMEM;\n\t}\n\n\tif((errcode = atapi_cmd_testunit(ide, drive))) {\n\t\tprintk(\"WARNING: %s(): cdrom device %d,%d is not ready for TEST_UNIT, error %d.\\n\", __FUNCTION__, MAJOR(i->rdev), MINOR(i->rdev), errcode);\n\t\trequest_sense(buffer, i->rdev, ide, drive);\n\t}\n\t/* this line just to catch interrupt */\n\tata_set_timeout(ide, WAIT_FOR_CD, WAKEUP_AND_RETURN);\n\n\tfor(retries = 0; retries < MAX_CD_ERR; retries++) {\n\t\tif(!(errcode = atapi_cmd_startstop(CD_LOAD, ide, drive))) {\n\t\t\tbreak;\n\t\t}\n\t\t/* FIXME: this code has not been tested */\n\t\tprintk(\"WARNING: %s(): cdrom device %d,%d is not ready for CD_LOAD, error %d.\\n\", __FUNCTION__, MAJOR(i->rdev), MINOR(i->rdev), errcode);\n\t\tatapi_pio_read(ide, drive, &drive->xd);\n\t\terrcode = request_sense(buffer, i->rdev, ide, drive);\n\t\tsense_key = (errcode & 0xF0) >> 4;\n\t\t/* trying to eject on slim drives may lead to an illegal request */\n\t\tif(!sense_key || sense_key == RS_ILLEGAL_REQUEST) {\n\t\t\tbreak;\n\t\t}\n\t\tif(errcode == 0x70 || errcode == 0x71) {\n\t\t\tsense_key = (int)(buffer[2] & 0xF);\n\t\t\tsense_asc = (int)(buffer[12] & 0xFF);\n\t\t\tif(sense_key == RS_NOT_READY && sense_asc == ASC_NO_MEDIUM) {\n\t\t\t\tkfree((unsigned int)buffer);\n\t\t\t\treturn -ENOMEDIUM;\n\t\t\t}\n\t\t}\n\t}\n\n\tif(retries == MAX_CD_ERR) {\n\t\tif(sense_key == RS_NOT_READY) {\n\t\t\tkfree((unsigned int)buffer);\n\t\t\treturn -ENOMEDIUM;\n\t\t}\n\t}\n\n\tif(atapi_cmd_mediumrm(CD_LOCK_MEDIUM, ide, drive)) {\n\t\tprintk(\"WARNING: %s(): error on cdrom device %d,%d while trying to lock medium.\\n\", __FUNCTION__, MAJOR(i->rdev), MINOR(i->rdev));\n\t\trequest_sense(buffer, i->rdev, ide, drive);\n\t}\n\t/* this line just to catch interrupt */\n\tata_set_timeout(ide, WAIT_FOR_CD, WAKEUP_AND_RETURN);\n\n\tget_capacity(i, ide, drive);\n\tkfree((unsigned int)buffer);\n\treturn 0;\n}\n\nint atapi_cd_close(struct inode *i, struct fd *f)\n{\n\tstruct ide *ide;\n\tstruct ata_drv *drive;\n\tstruct device *d;\n\n\tif(!(ide = get_ide_controller(i->rdev))) {\n\t\treturn -EINVAL;\n\t}\n\n\tdrive = &ide->drive[GET_DRIVE_NUM(i->rdev)];\n\n\t/* FIXME: only if device usage == 0 */\n\tinvalidate_buffers(i->rdev);\n\n\tif(atapi_cmd_mediumrm(CD_UNLOCK_MEDIUM, ide, drive)) {\n\t\tprintk(\"WARNING: %s(): error on cdrom device %d,%d during 0x%x command.\\n\", __FUNCTION__, MAJOR(i->rdev), MINOR(i->rdev), ATAPI_MEDIUM_REMOVAL);\n\t}\n\t/* this line just to catch interrupt */\n\tata_set_timeout(ide, WAIT_FOR_CD, WAKEUP_AND_RETURN);\n\n\td = ide->device;\n\t((unsigned int *)d->device_data)[MINOR(i->rdev)] = 0;\n\n\treturn 0;\n}\n\nint atapi_cd_read(__dev_t dev, __blk_t block, char *buffer, int blksize)\n{\n\treturn setup_transfer(BLK_READ, dev, block, buffer, blksize);\n}\n\nint atapi_cd_ioctl(struct inode *i, struct fd *f, int cmd, unsigned int arg)\n{\n\tstruct ide *ide;\n\tstruct device *d;\n\tint errno;\n\n\tif(!(ide = get_ide_controller(i->rdev))) {\n\t\treturn -EINVAL;\n\t}\n\n\tswitch(cmd) {\n\t\tcase BLKSSZGET:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned int)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\t*(int *)arg = 2048;\n\t\t\tbreak;\n\t\tcase BLKBSZGET:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned int)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\td = ide->device;\n\t\t\t*(int *)arg = ((unsigned int *)d->blksize)[MINOR(i->rdev)];\n\t\t\tbreak;\n\t\tdefault:\n\t\t\treturn -EINVAL;\n\t\t\tbreak;\n\t}\n\n\treturn 0;\n}\n\n__loff_t atapi_cd_llseek(struct inode *i, __loff_t offset)\n{\n\treturn offset;\n}\n\nint atapi_cd_init(struct ide *ide, struct ata_drv *drive)\n{\n\tstruct device *d;\n\tunsigned char minor;\n\n\tdrive->fsop = &atapi_cd_driver_fsop;\n\n\tminor = !drive->minor_shift ? 0 : 1 << drive->minor_shift;\n\n\tif(!(d = get_device(BLK_DEV, MKDEV(drive->major, minor)))) {\n\t\treturn -EINVAL;\n\t}\n\tSET_MINOR(d->minors, minor);\n\t((unsigned int *)d->blksize)[minor] = BLKSIZE_2K;\n\n\t/* default transfer mode */\n\tdrive->read_fn = atapi_pio_read;\n\tdrive->write_fn = NULL;\n\tdrive->read_end_fn = atapi_pio_read_end;\n\tdrive->write_end_fn = NULL;\n\treturn 0;\n}\n"
  },
  {
    "path": "drivers/block/blk_queue.c",
    "content": "/*\n * fiwix/drivers/block/blk_queue.c\n *\n * Copyright 2024, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/irq.h>\n#include <fiwix/blk_queue.h>\n#include <fiwix/buffer.h>\n#include <fiwix/devices.h>\n#include <fiwix/sleep.h>\n#include <fiwix/sched.h>\n#include <fiwix/errno.h>\n#include <fiwix/mm.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n/* append the request into the queue */\nvoid add_blk_request(struct blk_request *br)\n{\n\tunsigned int flags;\n\tstruct blk_request *h;\n\tstruct device *d;\n\n\td = br->device;\n\tSAVE_FLAGS(flags); CLI();\n\tif((h = (struct blk_request *)d->requests_queue)) {\n\t\twhile(h->next) {\n\t\t\th = h->next;\n\t\t}\n\t\th->next = br;\n\t} else {\n\t\td->requests_queue = (void *)br;\n\t}\n\tRESTORE_FLAGS(flags);\n}\n\nint do_blk_request(struct device *d, void *fn, struct buffer *buf)\n{\n\tstruct blk_request *br;\n\tint errno;\n\n\tif(!(br = (struct blk_request *)kmalloc(sizeof(struct blk_request)))) {\n\t\tprintk(\"WARNING: %s(): no more free memory for block requests.\\n\", __FUNCTION__);\n\t\treturn -ENOMEM;\n\t}\n\n\tmemset_b(br, 0, sizeof(struct blk_request));\n\tbr->dev = buf->dev;\n\tbr->block = buf->block;\n\tbr->size = buf->size;\n\tbr->buffer = buf;\n\tbr->device = d;\n\tbr->fn = fn;\n\n\tadd_blk_request(br);\n\trun_blk_request(d);\n\tif(br->status != BR_COMPLETED) {\n\t\tsleep(br, PROC_UNINTERRUPTIBLE);\n\t}\n\terrno = br->errno;\n\tif(!br->head_group) {\n\t\tkfree((unsigned int)br);\n\t}\n\treturn errno;\n}\n\nvoid run_blk_request(struct device *d)\n{\n\tunsigned int flags;\n\tstruct blk_request *br, *brh;\n\tint errno;\n\n\tSAVE_FLAGS(flags); CLI();\n\tbr = (struct blk_request *)d->requests_queue;\n\twhile(br) {\n\t\tif(br->status) {\n\t\t\tif(br->status == BR_COMPLETED) {\n\t\t\t\tprintk(\"%s(): status marked as BR_COMPLETED, picking the next one ...\\n\", __FUNCTION__);\n\t\t\t\td->requests_queue = (void *)br->next;\n\t\t\t\tbr = br->next;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tbr->status = BR_PROCESSING;\n\t\tif(!(errno = br->fn(br->dev, br->block, br->buffer->data, br->size))) {\n\t\t\treturn;\n\t\t}\n\t\tbr->errno = errno;\n\t\td->requests_queue = (void *)br->next;\n\t\tbr->status = BR_COMPLETED;\n\t\tif(br->head_group) {\n\t\t\tbrh = br->head_group;\n\t\t\tbrh->left--;\n\t\t\tbrh->errno = errno;\n\t\t\tif(!brh->left) {\n\t\t\t\twakeup(brh);\n\t\t\t}\n\t\t} else {\n\t\t\twakeup(br);\n\t\t}\n\t\tbr = br->next;\n\t}\n\tRESTORE_FLAGS(flags);\n}\n"
  },
  {
    "path": "drivers/block/dma.c",
    "content": "/*\n * fiwix/drivers/block/dma.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/dma.h>\n#include <fiwix/string.h>\n\n/*\n *  DMA Channel  Page  Address  Count\n *  ---------------------------------\n *  0 (8 bit)     87h       0h     1h\n *  1 (8 bit)     83h       2h     3h\n *  2 (8 bit)     81h       4h     5h\n *  3 (8 bit)     82h       6h     7h\n *  4 (16 bit)    8Fh      C0h    C2h\n *  5 (16 bit)    8Bh      C4h    C6h\n *  6 (16 bit)    89h      C8h    CAh\n *  7 (16 bit)    8Ah      CCh    CEh\n */\n\n#define LOW_BYTE(addr)\t(addr & 0x00FF)\n#define HIGH_BYTE(addr)\t((addr & 0xFF00) >> 8)\n\nunsigned char dma_mask[DMA_CHANNELS] =\n\t{ 0x0A, 0x0A, 0x0A, 0x0A, 0xD4, 0xD4, 0xD4, 0xD4 };\nunsigned char dma_mode[DMA_CHANNELS] =\n\t{ 0x0B, 0x0B, 0x0B, 0x0B, 0xD6, 0xD6, 0xD6, 0xD6 };\nunsigned char dma_clear[DMA_CHANNELS] =\n\t{ 0x0C, 0x0C, 0x0C, 0x0C, 0xD8, 0xD8, 0xD8, 0xD8 };\nunsigned char dma_page[DMA_CHANNELS] =\n\t{ 0x87, 0x83, 0x81, 0x82, 0x8F, 0x8B, 0x89, 0x8A };\nunsigned char dma_address[DMA_CHANNELS] =\n\t{ 0x00, 0x02, 0x04, 0x06, 0xC0, 0xC4, 0xC8, 0xCC };\nunsigned char dma_count[DMA_CHANNELS] =\n\t{ 0x01, 0x03, 0x05, 0x07, 0xC2, 0xC6, 0xCA, 0xCE };\n\nchar *dma_resources[DMA_CHANNELS];\n\n\nvoid start_dma(int channel, void *address, unsigned int count, int mode)\n{\n\t/* setup (mask) the DMA channel */\n\toutport_b(dma_mask[channel], DMA_MASK_CHANNEL | channel);\n\n\t/* clear any data transfers that are currently executing */\n\toutport_b(dma_clear[channel], 0);\n\n\t/* set the specified mode */\n\toutport_b(dma_mode[channel], mode | channel);\n\n\t/* set the offset address */\n\toutport_b(dma_address[channel], LOW_BYTE((unsigned int)address));\n\toutport_b(dma_address[channel], HIGH_BYTE((unsigned int)address));\n\n\t/* set the physical page */\n\toutport_b(dma_page[channel], (unsigned int)address >> 16);\n\n\t/* the true (internal) length sent to the DMA is actually length + 1 */\n\tcount--;\n\n\t/* set the length of the data */\n\toutport_b(dma_count[channel], LOW_BYTE(count));\n\toutport_b(dma_count[channel], HIGH_BYTE(count));\n\n\t/* clear the mask */\n\toutport_b(dma_mask[channel], DMA_UNMASK_CHANNEL | channel);\n}\n\nint dma_register(int channel, char *dev_name)\n{\n\tif(dma_resources[channel]) {\n\t\treturn 1;\n\t}\n\tdma_resources[channel] = dev_name;\n\treturn 0;\n}\n\nint dma_unregister(int channel)\n{\n\tif(!dma_resources[channel]) {\n\t\treturn 1;\n\t}\n\n\tdma_resources[channel] = NULL;\n\treturn 0;\n}\n\nvoid dma_init(void)\n{\n\tmemset_b(dma_resources, 0, sizeof(dma_resources));\n}\n"
  },
  {
    "path": "drivers/block/floppy.c",
    "content": "/*\n * fiwix/drivers/block/floppy.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/floppy.h>\n#include <fiwix/ioctl.h>\n#include <fiwix/devices.h>\n#include <fiwix/part.h>\n#include <fiwix/fs.h>\n#include <fiwix/buffer.h>\n#include <fiwix/sleep.h>\n#include <fiwix/timer.h>\n#include <fiwix/sched.h>\n#include <fiwix/errno.h>\n#include <fiwix/mm.h>\n#include <fiwix/pic.h>\n#include <fiwix/irq.h>\n#include <fiwix/cmos.h>\n#include <fiwix/dma.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#define WAIT_MOTOR_OFF\t(3 * HZ)\t/* time waiting to turn the motor off */\n#define WAIT_FDC\tWAIT_MOTOR_OFF\n\n#define INVALID_TRACK\t-1\n\n#define DEV_TYPE_SHIFT\t2\t\t/* right shift to match with the floppy\n\t\t\t\t\t   type when minor > 3 */\n\nstatic int need_reset = 0;\nstatic int fdc_wait_interrupt = 0;\nstatic int fdc_timeout = 0;\nstatic unsigned char fdc_results[MAX_FDC_RESULTS];\nstatic struct resource floppy_resource = { 0, 0 };\n\nstatic struct fddt fdd_type[] = {\n/*\n * R (data rate): 0 = 500Kb/s, 2 = 250Kb/s, 3 = 1Mb/s\n * SPEC(IFY) 0xAF: SRT = 6ms, HUT = 240ms (500Kb/s)\n * SPEC(IFY) 0xD7: SRT = 6ms, HUT = 240ms (250Kb/s)\n * SPEC(IFY) 0xDF: SRT = 3ms, HUT = 240ms (500Kb/s)\n * Head Load Time 0x02: HLT = 4ms (500Kb/s), Non-DMA = 0 (DMA enabled)\n *\n *        SIZE    KB   T   S  H  G_RW  G_FM  R  SPEC  HLT   NAME\n *        ---------------------------------------------------------------- */\n\t{    0,    0,  0,  0, 0, 0x00, 0x00, 0, 0x00, 0x00, NULL           },\n\t{  720,  360, 40,  9, 2, 0x2A, 0x50, 2, 0xD7, 0x02, \"360KB 5.25\\\"\" },\n\t{ 2400, 1200, 80, 15, 2, 0x2A, 0x50, 0, 0xAF, 0x02, \"1.2MB 5.25\\\"\" },\n\t{ 1440,  720, 80,  9, 2, 0x1B, 0x54, 2, 0xD7, 0x02, \"720KB 3.5\\\"\"  },\n\t{ 2880, 1440, 80, 18, 2, 0x1B, 0x54, 0, 0xAF, 0x02, \"1.44MB 3.5\\\"\" },\n/*\t{ 5760, 2880, 80, 36, 2, 0x38, 0x53, 3, 0xDF, 0x02, \"2.88MB 3.5\\\"\" },*/\n};\n\n/* buffer area used for I/O operations (1KB) */\nchar fdc_transfer_area[BPS * 2];\n\nstruct fdd_status {\n\tchar type;\t\t/* floppy disk drive type */\n\tchar motor;\n\tchar recalibrated;\n\tchar current_track;\n};\n\nstatic struct fdd_status fdd_status[] = {\n\t{ 0, 0, 0, INVALID_TRACK },\n\t{ 0, 0, 0, INVALID_TRACK },\n};\n\nstatic unsigned char current_fdd = 0;\nstatic struct fddt *current_fdd_type;\n\nstatic struct fs_operations fdc_driver_fsop = {\n\t0,\n\t0,\n\n\tfdc_open,\n\tfdc_close,\n\tNULL,\t\t\t/* read */\n\tNULL,\t\t\t/* write */\n\tfdc_ioctl,\n\tfdc_llseek,\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lockup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tfdc_read,\n\tfdc_write,\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nstatic struct device floppy_device = {\n\t\"floppy\",\n\tFDC_MAJOR,\n\t{ 0, 0, 0, 0, 0, 0, 0, 0 },\n\tNULL,\n\tNULL,\n\t&fdc_driver_fsop,\n\tNULL,\n\tNULL,\n\tNULL\n};\n\nstatic struct interrupt irq_config_floppy = { 0, \"floppy\", &irq_floppy, NULL };\n\nstatic int fdc_in(void)\n{\n\tint n;\n\tunsigned char status;\n\n\tif(need_reset) {\n\t\treturn -1;\n\t}\n\n\tfor(n = 0; n < 10000; n++) {\n\t\tstatus = inport_b(FDC_MSR) & (FDC_RQM | FDC_DIO);\n\t\tif(status == FDC_RQM) {\n\t\t\treturn 0;\n\t\t}\n\t\tif(status == (FDC_RQM | FDC_DIO)) {\n\t\t\treturn inport_b(FDC_DATA);\n\t\t}\n\t}\n\tneed_reset = 1;\n\tprintk(\"WARNING: %s(): fd%d: timeout on %s.\\n\", __FUNCTION__, current_fdd, floppy_device.name);\n\treturn -1;\n}\n\nstatic void fdc_out(unsigned char value)\n{\n\tint n;\n\tunsigned char status;\n\n\tif(need_reset) {\n\t\treturn;\n\t}\n\n\tfor(n = 0; n < 10000; n++) {\n\t\tstatus = inport_b(FDC_MSR) & (FDC_RQM | FDC_DIO);\n\t\tif(status == FDC_RQM) {\n\t\t\toutport_b(FDC_DATA, value);\n\t\t\treturn;\n\t\t}\n\t}\n\n\tneed_reset = 1;\n\tprintk(\"WARNING: %s(): fd%d: unable to send byte 0x%x on %s.\\n\", __FUNCTION__, current_fdd, value, floppy_device.name);\n}\n\nstatic void fdc_get_results(void)\n{\n\tint n;\n\n\tmemset_b(fdc_results, 0, sizeof(fdc_results));\n\tfor(n = 0; n < MAX_FDC_RESULTS; n++) {\n\t\tfdc_results[n] = fdc_in();\n\t}\n\treturn;\n}\n\nstatic int fdc_motor_on(void)\n{\n\tstruct callout_req creq;\n\tint errno;\n\n\tif(fdd_status[current_fdd].motor) {\n\t\treturn 0;\n\t}\n\n\t/* select floppy disk drive and turn on its motor */\n\toutport_b(FDC_DOR, (FDC_DRIVE0 << current_fdd) | FDC_DMA_ENABLE | FDC_ENABLE | current_fdd);\n\tfdd_status[current_fdd].motor = 1;\n\tfdd_status[!current_fdd].motor = 0;\n\n\t/* fixed spin-up time of 500ms for 3.5\" and 5.25\" */\n\tcreq.fn = fdc_timer;\n\tcreq.arg = FDC_TR_MOTOR;\n\tadd_callout(&creq, HZ / 2);\n\tsleep(&fdc_motor_on, PROC_UNINTERRUPTIBLE);\n\n\terrno = 0;\n\n\t/* check for a disk change */\n\tif(inport_b(FDC_DIR) & 0x80) {\n\t\terrno = 1;\n\t}\n\n\treturn errno;\n}\n\nstatic void do_motor_off(unsigned int fdd)\n{\n\toutport_b(FDC_DOR, FDC_DMA_ENABLE | FDC_ENABLE | fdd);\n\tfdd_status[fdd].motor = 0;\n\tfdd_status[0].motor = fdd_status[1].motor = 0;\n}\n\nstatic void fdc_motor_off(void)\n{\n\tstruct callout_req creq;\n\n\tcreq.fn = do_motor_off;\n\tcreq.arg = current_fdd;\n\tadd_callout(&creq, WAIT_FDC);\n}\n\nstatic void fdc_reset(void)\n{\n\tint n;\n\tstruct callout_req creq;\n\n\tneed_reset = 0;\n\n\tfdc_wait_interrupt = FDC_RESET;\n\toutport_b(FDC_DOR, 0);\t\t\t/* enter in reset mode */\n/*\toutport_b(FDC_DOR, FDC_DMA_ENABLE); */\n\tfor(n = 0; n < 1000; n++) {\t\t/* recovery time */\n\t\tNOP();\n\t}\n\toutport_b(FDC_DOR, FDC_DMA_ENABLE | FDC_ENABLE);\n\n\tcreq.fn = fdc_timer;\n\tcreq.arg = FDC_TR_DEFAULT;\n\tadd_callout(&creq, WAIT_FDC);\n\t/* avoid sleep if interrupt already happened */\n\tif(fdc_wait_interrupt) {\n\t\tsleep(&irq_floppy, PROC_UNINTERRUPTIBLE);\n\t}\n\tif(fdc_timeout) {\n\t\tneed_reset = 1;\n\t\tprintk(\"WARNING: %s(): fd%d: timeout on %s.\\n\", __FUNCTION__, current_fdd, floppy_device.name);\n\t}\n\tdel_callout(&creq);\n\n\tfdd_status[0].motor = fdd_status[1].motor = 0;\n\tfdd_status[current_fdd].recalibrated = 0;\n\n\t/* assumes drive polling mode is ON (by default) */\n\tfor(n = 0; n < 4; n++) {\n\t\tfdc_out(FDC_SENSEI);\n\t\tfdc_get_results();\n\t}\n\n\t/* keeps controller informed on the drive about to use */\n\tfdc_out(FDC_SPECIFY);\n\tfdc_out(current_fdd_type->spec);\n\tfdc_out(current_fdd_type->hlt);\n\n\t/* set data rate */\n\toutport_b(FDC_CCR, current_fdd_type->rate);\n}\n\nstatic int fdc_recalibrate(void)\n{\n\tstruct callout_req creq;\n\n\tif(need_reset) {\n\t\treturn 1;\n\t}\n\n\tfdc_wait_interrupt = FDC_RECALIBRATE;\n\tfdc_motor_on();\n\tfdc_out(FDC_RECALIBRATE);\n\tfdc_out(current_fdd);\n\n\tif(need_reset) {\n\t\treturn 1;\n\t}\n\n\tcreq.fn = fdc_timer;\n\tcreq.arg = FDC_TR_DEFAULT;\n\tadd_callout(&creq, WAIT_FDC);\n\t/* avoid sleep if interrupt already happened */\n\tif(fdc_wait_interrupt) {\n\t\tsleep(&irq_floppy, PROC_UNINTERRUPTIBLE);\n\t}\n\tif(fdc_timeout) {\n\t\tneed_reset = 1;\n\t\tprintk(\"WARNING: %s(): fd%d: timeout on %s.\\n\", __FUNCTION__, current_fdd, floppy_device.name);\n\t\treturn 1;\n\t}\n\n\tdel_callout(&creq);\n\tfdc_out(FDC_SENSEI);\n\tfdc_get_results();\n\n\t/* PCN must be 0 indicating a successful position to track 0 */\n\tif((fdc_results[ST0] & (ST0_IC | ST0_SE | ST0_UC | ST0_NR)) != ST0_RECALIBRATE || fdc_results[ST_PCN]) {\n\t\tneed_reset = 1;\n\t\tprintk(\"WARNING: %s(): fd%d: unable to recalibrate on %s.\\n\", __FUNCTION__, current_fdd, floppy_device.name);\n\t\treturn 1;\n\t}\n\n\tfdd_status[current_fdd].current_track = INVALID_TRACK;\n\tfdd_status[current_fdd].recalibrated = 1;\n\tfdc_motor_off();\n\treturn 0;\n}\n\nstatic int fdc_seek(int track, int head)\n{\n\tstruct callout_req creq;\n\n\tif(need_reset) {\n\t\treturn 1;\n\t}\n\n\tif(!fdd_status[current_fdd].recalibrated) {\n\t\tif(fdc_recalibrate()) {\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\tif(fdd_status[current_fdd].current_track == track) {\n\t\treturn 0;\n\t}\n\n\tfdc_wait_interrupt = FDC_SEEK;\n\tfdc_motor_on();\n\tfdc_out(FDC_SEEK);\n\tfdc_out((head << 2) | current_fdd);\n\tfdc_out(track);\n\n\tif(need_reset) {\n\t\treturn 1;\n\t}\n\n\tcreq.fn = fdc_timer;\n\tcreq.arg = FDC_TR_DEFAULT;\n\tadd_callout(&creq, WAIT_FDC);\n\t/* avoid sleep if interrupt already happened */\n\tif(fdc_wait_interrupt) {\n\t\tsleep(&irq_floppy, PROC_UNINTERRUPTIBLE);\n\t}\n\tif(fdc_timeout) {\n\t\tneed_reset = 1;\n\t\tprintk(\"WARNING: %s(): fd%d: timeout on %s.\\n\", __FUNCTION__, current_fdd, floppy_device.name);\n\t\treturn 1;\n\t}\n\n\tdel_callout(&creq);\n\tfdc_out(FDC_SENSEI);\n\tfdc_get_results();\n\n\tif((fdc_results[ST0] & (ST0_IC | ST0_SE | ST0_UC | ST0_NR)) != ST0_SEEK || fdc_results[ST_PCN] != track) {\n\t\tneed_reset = 1;\n\t\tprintk(\"WARNING: %s(): fd%d: unable to seek on %s.\\n\", __FUNCTION__, current_fdd, floppy_device.name);\n\t\treturn 1;\n\t}\n\n\tfdc_motor_off();\n\tfdd_status[current_fdd].current_track = track;\n\treturn 0;\n}\n\nstatic int fdc_get_chip(void)\n{\n\tunsigned char version, fifo, id;\n\n\tfdc_out(FDC_VERSION);\n\tversion = fdc_in();\n\tfdc_out(FDC_LOCK);\n\tfifo = fdc_in();\n\tfdc_out(FDC_PARTID);\n\tid = fdc_in();\n\n\tif(version == 0x80) {\n\t\tif(fifo == 0x80) {\n\t\t\tprintk(\"(NEC D765/Intel 8272A/compatible)\\n\");\n\t\t\treturn 0;\n\t\t}\n\t\tif(fifo == 0) {\n\t\t\tprintk(\"(Intel 82072)\\n\");\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tif(version == 0x81) {\n\t\tprintk(\"(Very Early Intel 82077/compatible)\\n\");\n\t\treturn 0;\n\t}\n\n\tif(version == 0x90) {\n\t\tif(fifo == 0x80) {\n\t\t\tprintk(\"(Old Intel 82077, no FIFO)\\n\");\n\t\t\treturn 0;\n\t\t}\n\t\tif(fifo == 0) {\n\t\t\tif(id == 0x80) {\n\t\t\t\tprintk(\"(New Intel 82077)\\n\");\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif(id == 0x41) {\n\t\t\t\tprintk(\"(Intel 82078)\\n\");\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif(id == 0x73) {\n\t\t\t\tprintk(\"(National Semiconductor PC87306)\\n\");\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tprintk(\"(Intel 82078 compatible)\\n\");\n\t\t\treturn 0;\n\t\t}\n\t\tprintk(\"(NEC 72065B)\\n\");\n\t\treturn 0;\n\t}\n\n\tif(version == 0xA0) {\n\t\tprintk(\"(SMC FDC37c65C+)\\n\");\n\t\treturn 0;\n\t}\n\tprintk(\"(unknown controller chip)\\n\");\n\treturn 1;\n}\n\nstatic int fdc_block2chs(__blk_t block, int blksize, int *cyl, int *head, int *sector)\n{\n\tint spb = blksize / FDC_SECTSIZE;\n\n\t*cyl = (block * spb) / (current_fdd_type->spt * current_fdd_type->heads);\n\t*head = ((block * spb) % (current_fdd_type->spt * current_fdd_type->heads)) / current_fdd_type->spt;\n\t*sector = (((block * spb) % (current_fdd_type->spt * current_fdd_type->heads)) % current_fdd_type->spt) + 1;\n\n\tif(*cyl >= current_fdd_type->tracks || *head >= current_fdd_type->heads || *sector > current_fdd_type->spt) {\n\t\treturn 1;\n\t}\n\n\treturn 0;\n}\n\nstatic void set_current_fdd_type(int minor)\n{\n\tcurrent_fdd = minor & 1;\n\n\t/* minors 0 and 1 are directly assigned */\n\tif(minor < 2) {\n\t\tcurrent_fdd_type = &fdd_type[(int)fdd_status[current_fdd].type];\n\t} else {\n\t\tcurrent_fdd_type = &fdd_type[minor >> DEV_TYPE_SHIFT];\n\t}\n}\n\nstatic int setup_transfer(int mode, __dev_t dev, __blk_t block, char *buffer, int blksize)\n{\n\tunsigned char minor;\n\tunsigned int sectors_io;\n\tint cyl, head, sector;\n\tint retries;\n\tstruct callout_req creq;\n\tstruct device *d;\n\tchar *op;\n\n\tminor = MINOR(dev);\n\tif(!TEST_MINOR(floppy_device.minors, minor)) {\n\t\treturn -ENXIO;\n\t}\n\n\tif(!blksize) {\n\t\tif(!(d = get_device(BLK_DEV, dev))) {\n\t\t\treturn -EINVAL;\n\t\t}\n\t\tblksize = ((unsigned int *)d->blksize)[MINOR(dev)];\n\t}\n\tblksize = blksize ? blksize : BLKSIZE_1K;\n\n\tlock_resource(&floppy_resource);\n\tset_current_fdd_type(minor);\n\n\tif(mode == BLK_READ) {\n\t\top = \"fdc_read\";\n\t} else {\n\t\top = \"fdc_write\";\n\t}\n\n\tif(fdc_block2chs(block, blksize, &cyl, &head, &sector)) {\n\t\tprintk(\"WARNING: %s(): fd%d: invalid block number %d on %s device %d,%d.\\n\", op, current_fdd, block, floppy_device.name, MAJOR(dev), MINOR(dev));\n\t\tunlock_resource(&floppy_resource);\n\t\treturn -EINVAL;\n\t}\n\n\tfor(retries = 0; retries < MAX_FDC_ERR; retries++) {\n\t\tif(need_reset) {\n\t\t\tfdc_reset();\n\t\t}\n\t\tif(fdc_motor_on()) {\n\t\t\tprintk(\"%s(): %s disk was changed in device %d,%d!\\n\", op, floppy_device.name, MAJOR(dev), MINOR(dev));\n\t\t\tinvalidate_buffers(dev);\n\t\t\tfdd_status[current_fdd].recalibrated = 0;\n\t\t}\n\n\t\tif(fdc_seek(cyl, head)) {\n\t\t\tprintk(\"WARNING: %s(): fd%d: seek error on %s device %d,%d.\\n\", op, current_fdd, floppy_device.name, MAJOR(dev), MINOR(dev));\n\t\t\tcontinue;\n\t\t}\n\n\t\tif(mode == BLK_READ) {\n\t\t\tstart_dma(FLOPPY_DMA, fdc_transfer_area, blksize, DMA_MODE_WRITE | DMA_MODE_SINGLE);\n\t\t\tfdc_wait_interrupt = FDC_READ;\n\t\t\tfdc_out(FDC_READ);\n\t\t} else {\n\t\t\tstart_dma(FLOPPY_DMA, fdc_transfer_area, blksize, DMA_MODE_READ | DMA_MODE_SINGLE);\n\t\t\tmemcpy_b((void *)fdc_transfer_area, buffer, blksize);\n\t\t\tfdc_wait_interrupt = FDC_WRITE;\n\t\t\tfdc_out(FDC_WRITE);\n\t\t}\n\t\tfdc_out((head << 2) | current_fdd);\n\t\tfdc_out(cyl);\n\t\tfdc_out(head);\n\t\tfdc_out(sector);\n\t\tfdc_out(2);\t/* sector size is 512 bytes */\n\t\tfdc_out(current_fdd_type->spt);\n\t\tfdc_out(current_fdd_type->gpl1);\n\t\tfdc_out(0xFF);\t/* sector size is 512 bytes */\n\n\t\tif(need_reset) {\n\t\t\tprintk(\"WARNING: %s(): fd%d: needs reset on %s device %d,%d.\\n\", op, current_fdd, floppy_device.name, MAJOR(dev), MINOR(dev));\n\t\t\tcontinue;\n\t\t}\n\t\tcreq.fn = fdc_timer;\n\t\tcreq.arg = FDC_TR_DEFAULT;\n\t\tadd_callout(&creq, WAIT_FDC);\n\t\t/* avoid sleep if interrupt already happened */\n\t\tif(fdc_wait_interrupt) {\n\t\t\tsleep(&irq_floppy, PROC_UNINTERRUPTIBLE);\n\t\t}\n\t\tif(fdc_timeout) {\n\t\t\tneed_reset = 1;\n\t\t\tprintk(\"WARNING: %s(): fd%d: timeout on %s device %d,%d.\\n\", op, current_fdd, floppy_device.name, MAJOR(dev), MINOR(dev));\n\t\t\tcontinue;\n\t\t}\n\t\tdel_callout(&creq);\n\t\tfdc_get_results();\n\t\tif(mode == BLK_WRITE) {\n\t\t\tif(fdc_results[ST1] & ST1_NW) {\n\t\t\t\tunlock_resource(&floppy_resource);\n\t\t\t\tfdc_motor_off();\n\t\t\t\treturn -EROFS;\n\t\t\t}\n\t\t}\n\t\tif(fdc_results[ST0] & (ST0_IC | ST0_UC | ST0_NR)) {\n\t\t\tneed_reset = 1;\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\n\tif(retries >= MAX_FDC_ERR) {\n\t\tprintk(\"WARNING: %s(): fd%d: error on %s device %d,%d,\\n\", op, current_fdd, floppy_device.name, MAJOR(dev), MINOR(dev));\n\t\tprintk(\"\\tblock=%d, sector=%d, cylinder/head=%d/%d\\n\", block, sector, cyl, head);\n\t\tunlock_resource(&floppy_resource);\n\t\tfdc_motor_off();\n\t\treturn -EIO;\n\t}\n\n\tfdc_motor_off();\n\tsectors_io = (fdc_results[ST_CYL] - cyl) * (current_fdd_type->heads * current_fdd_type->spt);\n\tsectors_io += (fdc_results[ST_HEAD] - head) * current_fdd_type->spt;\n\tsectors_io += fdc_results[ST_SECTOR] - sector;\n\tif(sectors_io * BPS != blksize) {\n\t\tprintk(\"WARNING: %s(): fd%d: error on %s device %d,%d (%d sectors I/O),\\n\", op, current_fdd, floppy_device.name, MAJOR(dev), MINOR(dev), sectors_io);\n\t\tprintk(\"\\tblock=%d, sector=%d, cylinder/head=%d/%d\\n\", block, sector, cyl, head);\n\t\tunlock_resource(&floppy_resource);\n\t\tfdc_motor_off();\n\t\treturn -EIO;\n\t}\n\n\tif(mode == BLK_READ) {\n\t\tmemcpy_b(buffer, (void *)fdc_transfer_area, blksize);\n\t}\n\n\tunlock_resource(&floppy_resource);\n\treturn sectors_io * BPS;\n}\n\nvoid irq_floppy(int num, struct sigcontext *sc)\n{\n\tif(!fdc_wait_interrupt) {\n\t\tprintk(\"WARNING: %s(): fd%d: unexpected interrupt!\\n\", __FUNCTION__, current_fdd);\n\t\tneed_reset = 1;\n\t} else {\n\t\tfdc_timeout = fdc_wait_interrupt = 0;\n\t\twakeup(&irq_floppy);\n\t}\n}\n\nvoid fdc_timer(unsigned int reason)\n{\n\tswitch(reason) {\n\t\tcase FDC_TR_DEFAULT:\n\t\t\tfdc_timeout = 1;\n\t\t\tfdc_wait_interrupt = 0;\n\t\t\twakeup(&irq_floppy);\n\t\t\tbreak;\n\t\tcase FDC_TR_MOTOR:\n\t\t\twakeup(&fdc_motor_on);\n\t\t\tbreak;\n\t}\n}\n\nint fdc_open(struct inode *i, struct fd *f)\n{\n\tunsigned char minor;\n\n\tminor = MINOR(i->rdev);\n\tif(!TEST_MINOR(floppy_device.minors, minor)) {\n\t\treturn -ENXIO;\n\t}\n\n\tlock_resource(&floppy_resource);\n\tset_current_fdd_type(minor);\n\tunlock_resource(&floppy_resource);\n\n\treturn 0;\n}\n\nint fdc_close(struct inode *i, struct fd *f)\n{\n\tunsigned char minor;\n\n\tminor = MINOR(i->rdev);\n\tif(!TEST_MINOR(floppy_device.minors, minor)) {\n\t\treturn -ENXIO;\n\t}\n\n\tsync_buffers(i->rdev);\n\tlock_resource(&floppy_resource);\n\tset_current_fdd_type(minor);\n\tunlock_resource(&floppy_resource);\n\n\treturn 0;\n}\n\nint fdc_read(__dev_t dev, __blk_t block, char *buffer, int blksize)\n{\n\treturn setup_transfer(BLK_READ, dev, block, buffer, blksize);\n}\n\nint fdc_write(__dev_t dev, __blk_t block, char *buffer, int blksize)\n{\n\treturn setup_transfer(BLK_WRITE, dev, block, buffer, blksize);\n}\n\nint fdc_ioctl(struct inode *i, struct fd *f, int cmd, unsigned int arg)\n{\n\tunsigned char minor;\n\tstruct hd_geometry *geom;\n\tstruct device *d;\n\tint errno, size;\n\n\tminor = MINOR(i->rdev);\n\tif(!TEST_MINOR(floppy_device.minors, minor)) {\n\t\treturn -ENXIO;\n\t}\n\tif(!(d = get_device(BLK_DEV, i->rdev))) {\n\t\treturn -EINVAL;\n\t}\n\tsize = ((unsigned int *)d->device_data)[MINOR(i->rdev)];\n\n\tlock_resource(&floppy_resource);\n\tset_current_fdd_type(minor);\n\tunlock_resource(&floppy_resource);\n\n\tswitch(cmd) {\n\t\tcase HDIO_GETGEO:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(struct hd_geometry)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tgeom = (struct hd_geometry *)arg;\n\t\t\tgeom->heads = current_fdd_type->heads;\n\t\t\tgeom->sectors = current_fdd_type->spt;\n\t\t\tgeom->cylinders = current_fdd_type->tracks;\n\t\t\tgeom->start = 0;\n\t\t\tbreak;\n\t\tcase BLKRRPART:\n\t\t\tbreak;\n\t\tcase BLKGETSIZE:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned int)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\t*(int *)arg = size * 2;\n\t\t\tbreak;\n\t\tcase BLKSSZGET:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned int)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\t*(int *)arg = 512;\n\t\t\tbreak;\n\t\tcase BLKBSZGET:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned int)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\t*(int *)arg = ((unsigned int *)d->blksize)[MINOR(i->rdev)];\n\t\t\tbreak;\n\t\tcase BLKFLSBUF:\n\t\t\tsync_buffers(i->rdev);\n\t\t\tinvalidate_buffers(i->rdev);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\treturn -EINVAL;\n\t}\n\treturn 0;\n}\n\n__loff_t fdc_llseek(struct inode *i, __loff_t offset)\n{\n\tunsigned char minor;\n\n\tminor = MINOR(i->rdev);\n\tif(!TEST_MINOR(floppy_device.minors, minor)) {\n\t\treturn -ENXIO;\n\t}\n\n\tlock_resource(&floppy_resource);\n\tset_current_fdd_type(minor);\n\tunlock_resource(&floppy_resource);\n\n\treturn offset;\n}\n\nvoid floppy_init(void)\n{\n\tshort int cmosval, master, slave;\n\tint n;\n\n\tcmosval = cmos_read(CMOS_FDDTYPE);\n\tset_current_fdd_type(0);\t/* sets /dev/fd0 by default */\n\n\t/* the high nibble describes the 'master' floppy drive */\n\tmaster = cmosval >> 4;\n\n\t/* \n\t * Some BIOS may return the value 0x05 (for 2.88MB floppy type) which is\n\t * not supported by Fiwix. This prevents from using an unexistent type\n\t * in the fdd_type structure if this happens.\n\t */\n\tif(master > 4) {\n\t\tmaster = 4;\n\t}\n\n\tfloppy_device.blksize = (unsigned int *)kmalloc(MAX_MINORS * sizeof(unsigned int));\n\tfloppy_device.device_data = (unsigned int *)kmalloc(MAX_MINORS * sizeof(unsigned int));\n\tmemset_l(floppy_device.blksize, 0, MAX_MINORS);\n\tmemset_l(floppy_device.device_data, 0, MAX_MINORS);\n\n\tif(master) {\n\t\tif(!register_irq(FLOPPY_IRQ, &irq_config_floppy)) {\n\t\t\tenable_irq(FLOPPY_IRQ);\n\t\t}\n\t\tprintk(\"fd0       0x%04x-0x%04x     %d\\t\", FDC_SRA, FDC_CCR, FLOPPY_IRQ);\n\t\tprintk(\"%s \", fdd_type[master].name);\n\t\tfdd_status[0].type = fdd_status[1].type = master;\n\t\tfor(n = 0; n < 18; n += 4) {\n\t\t\tSET_MINOR(floppy_device.minors, n);\n\t\t\t((unsigned int *)floppy_device.blksize)[n] = BLKSIZE_1K;\n\t\t}\n\t\t((unsigned int *)floppy_device.device_data)[0] = fdd_type[master].sizekb;\n\t\t((unsigned int *)floppy_device.device_data)[4] = fdd_type[1].sizekb;\n\t\t((unsigned int *)floppy_device.device_data)[8] = fdd_type[2].sizekb;\n\t\t((unsigned int *)floppy_device.device_data)[12] = fdd_type[3].sizekb;\n\t\t((unsigned int *)floppy_device.device_data)[16] = fdd_type[4].sizekb;\n\t\tfdc_reset();\n\t\tfdc_get_chip();\n\t}\n\n\t/* the low nibble is for the 'slave' floppy drive */\n\tslave = cmosval & 0x0F;\n\tif(slave) {\n\t\tif(!master) {\n\t\t\tif(!register_irq(FLOPPY_IRQ, &irq_config_floppy)) {\n\t\t\t\tenable_irq(FLOPPY_IRQ);\n\t\t\t}\n\t\t}\n\t\tprintk(\"fd1       0x%04x-0x%04x     %d\\t\", FDC_SRA, FDC_CCR, FLOPPY_IRQ);\n\t\tprintk(\"%s  \", fdd_type[slave].name);\n\t\tfdd_status[1].type = slave;\n\t\tfor(n = 1; n < 18; n += 4) {\n\t\t\tSET_MINOR(floppy_device.minors, n);\n\t\t\t((unsigned int *)floppy_device.blksize)[n] = BLKSIZE_1K;\n\t\t}\n\t\t((unsigned int *)floppy_device.device_data)[1] = fdd_type[master].sizekb;\n\t\t((unsigned int *)floppy_device.device_data)[5] = fdd_type[1].sizekb;\n\t\t((unsigned int *)floppy_device.device_data)[9] = fdd_type[2].sizekb;\n\t\t((unsigned int *)floppy_device.device_data)[13] = fdd_type[3].sizekb;\n\t\t((unsigned int *)floppy_device.device_data)[17] = fdd_type[4].sizekb;\n\t\tif(!master) {\n\t\t\tfdc_get_chip();\n\t\t} else {\n\t\t\tprintk(\"\\n\");\n\t\t}\n\t}\n\n\tif(master || slave) {\n\t\tneed_reset = 1;\n\t\tdma_init();\n\t\tif(dma_register(FLOPPY_DMA, floppy_device.name)) {\n\t\t\tprintk(\"WARNING: %s(): fd%d: unable to register DMA channel on %s.\\n\", __FUNCTION__, current_fdd, floppy_device.name);\n\t\t} else  {\n\t\t\tif(!register_device(BLK_DEV, &floppy_device)) {\n\t\t\t\tdo_motor_off(current_fdd);\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "drivers/block/part.c",
    "content": "/*\n * fiwix/drivers/block/part.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/ata.h>\n#include <fiwix/ata_hd.h>\n#include <fiwix/fs.h>\n#include <fiwix/part.h>\n#include <fiwix/buffer.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nint read_msdos_partition(__dev_t dev, struct partition *part)\n{\n\tstruct buffer *buf;\n\tstruct device *d;\n\tint blksize;\n\n\tif(!(d = get_device(BLK_DEV, dev))) {\n\t\treturn -ENXIO;\n\t}\n\n\tblksize = ((unsigned int *)d->blksize)[MINOR(dev)];\n\tif(!(buf = bread(dev, PARTITION_BLOCK, blksize))) {\n\t\tprintk(\"WARNING: %s(): unable to read partition block in device %d,%d.\\n\", __FUNCTION__, MAJOR(dev), MINOR(dev));\n\t\treturn -EIO;\n\t}\n\n\tmemcpy_b(part, (void *)(buf->data + MBR_CODE_SIZE), sizeof(struct partition) * NR_PARTITIONS);\n\tbrelse(buf);\n\treturn 0;\n}\n"
  },
  {
    "path": "drivers/block/ramdisk.c",
    "content": "/*\n * fiwix/drivers/block/ramdisk.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/ramdisk.h>\n#include <fiwix/ioctl.h>\n#include <fiwix/devices.h>\n#include <fiwix/part.h>\n#include <fiwix/fs.h>\n#include <fiwix/buffer.h>\n#include <fiwix/errno.h>\n#include <fiwix/mm.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nint ramdisk_minors;\nstruct ramdisk ramdisk_table[RAMDISK_TOTAL];\n\nstatic struct fs_operations ramdisk_driver_fsop = {\n\t0,\n\t0,\n\n\tramdisk_open,\n\tramdisk_close,\n\tNULL,\t\t\t/* read */\n\tNULL,\t\t\t/* write */\n\tramdisk_ioctl,\n\tramdisk_llseek,\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lockup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tramdisk_read,\n\tramdisk_write,\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nstatic struct device ramdisk_device = {\n\t\"ramdisk\",\n\tRAMDISK_MAJOR,\n\t{ 0, 0, 0, 0, 0, 0, 0, 0 },\n\tNULL,\n\tNULL,\n\t&ramdisk_driver_fsop,\n\tNULL,\n\tNULL,\n\tNULL\n};\n\nstatic struct ramdisk *get_ramdisk(int minor)\n{\n\tif(TEST_MINOR(ramdisk_device.minors, minor)) {\n\t\treturn &ramdisk_table[minor];\n\t}\n\treturn NULL;\n}\n\nint ramdisk_open(struct inode *i, struct fd *f)\n{\n\tif(!get_ramdisk(MINOR(i->rdev))) {\n\t\treturn -ENXIO;\n\t}\n\treturn 0;\n}\n\nint ramdisk_close(struct inode *i, struct fd *f)\n{\n\tif(!get_ramdisk(MINOR(i->rdev))) {\n\t\treturn -ENXIO;\n\t}\n\tsync_buffers(i->rdev);\n\treturn 0;\n}\n\nint ramdisk_read(__dev_t dev, __blk_t block, char *buffer, int blksize)\n{\n\tint size;\n\t__off_t offset;\n\tstruct ramdisk *ramdisk;\n\tstruct device *d;\n\n\tif(!(ramdisk = get_ramdisk(MINOR(dev)))) {\n\t\treturn -ENXIO;\n\t}\n\tif(!(d = get_device(BLK_DEV, dev))) {\n\t\treturn -EINVAL;\n\t}\n\n\tsize = ((unsigned int *)d->device_data)[MINOR(dev)] * 1024;\n\toffset = block * blksize;\n\tif(offset > size) {\n\t\tprintk(\"%s(): block %d is beyond the size of the ramdisk.\\n\", __FUNCTION__, block);\n\t\treturn -EIO;\n\t}\n\tblksize = MIN(blksize, size - offset);\n\tmemcpy_b((void *)buffer, ramdisk->addr + offset, blksize);\n\treturn blksize;\n}\n\nint ramdisk_write(__dev_t dev, __blk_t block, char *buffer, int blksize)\n{\n\tint size;\n\t__off_t offset;\n\tstruct ramdisk *ramdisk;\n\tstruct device *d;\n\n\tif(!(ramdisk = get_ramdisk(MINOR(dev)))) {\n\t\treturn -ENXIO;\n\t}\n\tif(!(d = get_device(BLK_DEV, dev))) {\n\t\treturn -EINVAL;\n\t}\n\n\tsize = ((unsigned int *)d->device_data)[MINOR(dev)] * 1024;\n\toffset = block * blksize;\n\tif(offset > size) {\n\t\tprintk(\"%s(): block %d is beyond the size of the ramdisk.\\n\", __FUNCTION__, block);\n\t\treturn -EIO;\n\t}\n\tblksize = MIN(blksize, size - offset);\n\tmemcpy_b(ramdisk->addr + offset, buffer, blksize);\n\treturn blksize;\n}\n\nint ramdisk_ioctl(struct inode *i, struct fd *f, int cmd, unsigned int arg)\n{\n\tstruct hd_geometry *geom;\n\tstruct device *d;\n\tint errno, size;\n\n\tif(!get_ramdisk(MINOR(i->rdev))) {\n\t\treturn -ENXIO;\n\t}\n\tif(!(d = get_device(BLK_DEV, i->rdev))) {\n\t\treturn -EINVAL;\n\t}\n\tsize = ((unsigned int *)d->device_data)[MINOR(i->rdev)];\n\n\tswitch(cmd) {\n\t\tcase HDIO_GETGEO:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(struct hd_geometry)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tgeom = (struct hd_geometry *)arg;\n\t\t\tgeom->heads = 63;\n\t\t\tgeom->sectors = 16;\n\t\t\tgeom->cylinders = size * 1024 / BPS;\n\t\t\tgeom->cylinders /= (geom->heads * geom->sectors);\n\t\t\tgeom->start = 0;\n\t\t\tbreak;\n\t\tcase BLKRRPART:\n\t\t\tbreak;\n\t\tcase BLKGETSIZE:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned int)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\t*(int *)arg = size * 2;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\treturn -EINVAL;\n\t}\n\treturn 0;\n}\n\n__loff_t ramdisk_llseek(struct inode *i, __loff_t offset)\n{\n\treturn offset;\n}\n\nvoid ramdisk_init(void)\n{\n\tint n;\n\tstruct ramdisk *ramdisk;\n\n\tif(ramdisk_minors) {\n\t\tramdisk_device.blksize = (unsigned int *)kmalloc(MAX_MINORS * sizeof(unsigned int));\n\t\tramdisk_device.device_data = (unsigned int *)kmalloc(MAX_MINORS * sizeof(unsigned int));\n\t\tmemset_l(ramdisk_device.blksize, 0, MAX_MINORS);\n\t\tmemset_l(ramdisk_device.device_data, 0, MAX_MINORS);\n\t\tfor(n = 0; n < ramdisk_minors; n++) {\n\t\t\tSET_MINOR(ramdisk_device.minors, n);\n\t\t\tramdisk = get_ramdisk(n);\n\t\t\t((unsigned int *)ramdisk_device.blksize)[n] = BLKSIZE_1K;\n\t\t\t((unsigned int *)ramdisk_device.device_data)[n] = ramdisk->size;\n\t\t\tprintk(\"ram%d      0x%08x-0x%08x RAMdisk of %dKB size, %dKB blocksize\\n\", n, ramdisk->addr, ramdisk->addr + (ramdisk->size * 1024), ramdisk->size, BLKSIZE_1K / 1024);\n\t\t}\n\t\tregister_device(BLK_DEV, &ramdisk_device);\n\t}\n}\n"
  },
  {
    "path": "drivers/char/Makefile",
    "content": "# fiwix/drivers/char/Makefile\n#\n# Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n# Distributed under the terms of the Fiwix License.\n#\n\n.c.o:\n\t$(CC) $(CFLAGS) -c -o $@ $<\n\nOBJS = console.o tty.o charq.o vt.o ps2.o defkeymap.o keyboard.o psaux.o \\\n       memdev.o serial.o lp.o fb.o sysrq.o pty.o\n\nall:\t$(OBJS)\n\nclean:\n\trm -f *.o\n\n"
  },
  {
    "path": "drivers/char/charq.c",
    "content": "/*\n * fiwix/drivers/char/charq.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/charq.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n/*\n * charq.c implements a queue using a static-sized doubly linked list of a\n * central pool of buffers which covers all ttys.\n *\n *  head                                     tail\n * +--------------+  +--------------+  ...  +--------------+\n * |prev|data|next|  |prev|data|next|  ...  |prev|data|next|\n * | /  |    |  -->  <--  |    |  -->  ...  <--  |    |  / |\n * +--------------+  +--------------+  ...  +--------------+\n *  (cblock)          (cblock)               (cblock)\n */\n\n#define CB_POOL_SIZE\t64\t/* number of cblocks in the central pool */\n\nstruct cblock cblock_pool[CB_POOL_SIZE];\nstruct cblock *cblock_pool_head;\n\nstatic struct cblock *get_free_cblock(void)\n{\n\tstruct cblock *new = NULL;\n\n\tif(cblock_pool_head) {\n\t\tnew = cblock_pool_head;\n\t\tcblock_pool_head = cblock_pool_head->next;\n\t\tnew->prev = new->next = NULL;\n\t}\n\treturn new;\n}\n\nstatic void put_free_cblock(struct cblock *old)\n{\n\told->prev = NULL;\n\told->next = cblock_pool_head;\n\tcblock_pool_head = old;\n}\n\n/*\nstatic struct cblock *insert_cblock_in_head(struct clist *q)\n{\n\tstruct cblock *cb;\n\n\tif(q->cb_num >= NR_CB_QUEUE) {\n\t\treturn NULL;\n\t}\n\tif(!(cb = get_free_cblock())) {\n\t\treturn NULL;\n\t}\n\n\tcb->start_off = cb->end_off = 0;\n\tmemset_b(cb->data, 0, CBSIZE);\n\tcb->prev = cb->next = NULL;\n\tq->cb_num++;\n\n\tif(!q->head) {\n\t\tq->head = q->tail = cb;\n\t} else {\n\t\tcb->prev = NULL;\n\t\tcb->next = q->head;\n\t\tq->head->prev = cb;\n\t\tq->head = cb;\n\t}\n\treturn cb;\n}\n*/\n\nstatic struct cblock *insert_cblock_in_tail(struct clist *q)\n{\n\tstruct cblock *cb;\n\n\tif(q->cb_num >= NR_CB_QUEUE) {\n\t\treturn NULL;\n\t}\n\tif(!(cb = get_free_cblock())) {\n\t\treturn NULL;\n\t}\n\n\t/* initialize cblock */\n\tcb->start_off = cb->end_off = 0;\n\tmemset_b(cb->data, 0, CBSIZE);\n\tcb->prev = cb->next = NULL;\n\tq->cb_num++;\n\n\tif(!q->tail) {\n\t\tq->head = q->tail = cb;\n\t} else {\n\t\tcb->prev = q->tail;\n\t\tcb->next = NULL;\n\t\tq->tail->next = cb;\n\t\tq->tail = cb;\n\t}\n\treturn cb;\n}\n\nstatic void delete_cblock_from_head(struct clist *q)\n{\n\tstruct cblock *tmp;\n\n\tif(!q->head) {\n\t\treturn;\n\t}\n\n\ttmp = q->head;\n\tif(q->head == q->tail) {\n\t\tq->head = q->tail = NULL;\n\t} else {\n\t\tq->head = q->head->next;\n\t\tq->head->prev = NULL;\n\t}\n\n\tq->count -= tmp->end_off - tmp->start_off;\n\tq->cb_num--;\n\tput_free_cblock(tmp);\n}\n\nstatic void delete_cblock_from_tail(struct clist *q)\n{\n\tstruct cblock *tmp;\n\n\tif(!q->tail) {\n\t\treturn;\n\t}\n\n\ttmp = q->tail;\n\tif(q->head == q->tail) {\n\t\tq->head = q->tail = NULL;\n\t} else {\n\t\tq->tail = q->tail->prev;\n\t\tq->tail->next = NULL;\n\t}\n\n\tq->count -= tmp->end_off - tmp->start_off;\n\tq->cb_num--;\n\tput_free_cblock(tmp);\n}\n\nint charq_putchar(struct clist *q, unsigned char ch)\n{\n\tunsigned int flags;\n\tstruct cblock *cb;\n\tint errno;\n\n\tSAVE_FLAGS(flags); CLI();\n\n\tcb = q->tail;\n\tif(!cb) {\n\t\tcb = insert_cblock_in_tail(q);\n\t\tif(!cb) {\n\t\t\tRESTORE_FLAGS(flags);\n\t\t\treturn -EAGAIN;\n\t\t}\n\t}\n\n\tif(cb->end_off < CBSIZE) {\n\t\tcb->data[cb->end_off] = ch;\n\t\tcb->end_off++;\n\t\tq->count++;\n\t\terrno = 0;\n\t} else if(insert_cblock_in_tail(q)) {\n\t\tcharq_putchar(q, ch);\n\t\terrno = 0;\n\t} else {\n\t\terrno = -EAGAIN;\n\t}\n\n\tRESTORE_FLAGS(flags);\n\treturn errno;\n}\n\nint charq_unputchar(struct clist *q)\n{\n\tunsigned int flags;\n\tstruct cblock *cb;\n\tunsigned char ch;\n\n\tSAVE_FLAGS(flags); CLI();\n\n\tch = 0;\n\tcb = q->tail;\n\tif(cb) {\n\t\tif(cb->end_off > cb->start_off) {\n\t\t\tch = cb->data[cb->end_off - 1];\n\t\t\tcb->end_off--;\n\t\t\tq->count--;\n\t\t}\n\t\tif(cb->end_off - cb->start_off == 0) {\n\t\t\tdelete_cblock_from_tail(q);\n\t\t}\n\t}\n\n\tRESTORE_FLAGS(flags);\n\treturn ch;\n}\n\nunsigned char charq_getchar(struct clist *q)\n{\n\tunsigned int flags;\n\tstruct cblock *cb;\n\tunsigned char ch;\n\n\tSAVE_FLAGS(flags); CLI();\n\n\tch = 0;\n\tcb = q->head;\n\tif(cb) {\n\t\tif(cb->start_off < cb->end_off) {\n\t\t\tch = cb->data[cb->start_off];\n\t\t\tcb->start_off++;\n\t\t\tq->count--;\n\t\t}\n\t\tif(cb->end_off - cb->start_off == 0) {\n\t\t\tdelete_cblock_from_head(q);\n\t\t}\n\t}\n\n\tRESTORE_FLAGS(flags);\n\treturn ch;\n}\n\nvoid charq_flush(struct clist *q)\n{\n\tunsigned int flags;\n\n\tSAVE_FLAGS(flags); CLI();\n\n\twhile(q->head != NULL) {\n\t\tdelete_cblock_from_head(q);\n\t}\n\n\tRESTORE_FLAGS(flags);\n}\n\nint charq_room(struct clist *q)\n{\n\treturn (NR_CB_QUEUE * CBSIZE) - q->count;\n}\n\nvoid charq_init(void)\n{\n\tint n;\n\tstruct cblock *cb;\n\n\tmemset_b(cblock_pool, 0, sizeof(cblock_pool));\n\n\t/* cblock free list initialization */\n\tcblock_pool_head = NULL;\n\tn = CB_POOL_SIZE;\n\twhile(n--) {\n\t\tcb = &cblock_pool[n];\n\t\tput_free_cblock(cb);\n\t}\n}\n"
  },
  {
    "path": "drivers/char/console.c",
    "content": "/*\n * fiwix/drivers/char/console.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/ctype.h>\n#include <fiwix/console.h>\n#include <fiwix/devices.h>\n#include <fiwix/tty.h>\n#include <fiwix/keyboard.h>\n#include <fiwix/sleep.h>\n#include <fiwix/pit.h>\n#include <fiwix/timer.h>\n#include <fiwix/process.h>\n#include <fiwix/mm.h>\n#include <fiwix/sched.h>\n#include <fiwix/kd.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n#include <fiwix/fbcon.h>\n#include <fiwix/sysconsole.h>\n\n#define CSI_J_CUR2END\t0\t/* clear from cursor to end of screen */\n#define CSI_J_STA2CUR\t1\t/* clear from start of screen to cursor */\n#define CSI_J_SCREEN\t2\t/* clear entire screen */\n\n#define CSI_K_CUR2END\t0\t/* clear from cursor to end of line */\n#define CSI_K_STA2CUR\t1\t/* clear from start of line to cursor */\n#define CSI_K_LINE\t2\t/* clear entire line */\n\n#define CSE\t\tvc->esc = 0\t/* Code Set End */\n\n/* VT100 ID string generated by <ESC>Z or <ESC>[c */\n#define VT100ID\t\t\"\\033[?1;2c\"\n\n/* VT100 report status generated by <ESC>[5n */\n#define DEVICE_OK\t\"\\033[0n\"\n#define DEVICE_NOT_OK\t\"\\033[3n\"\n\n#define SCREEN_SIZE\t(video.columns * video.lines)\n#define VC_BUF_LINES\t(video.lines * SCREENS_LOG)\n\n\nshort int current_cons;\nshort int *vc_screen[NR_VCONSOLES + 1];\nshort int *vcbuf;\n\nstruct video_parms video;\nstruct vconsole vc[NR_VCONSOLES + 1];\n\nstatic struct fs_operations tty_driver_fsop = {\n\t0,\n\t0,\n\n\ttty_open,\n\ttty_close,\n\ttty_read,\n\ttty_write,\n\ttty_ioctl,\n\ttty_llseek,\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\ttty_select,\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lookup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nstatic struct device tty_device = {\n\t\"vconsole\",\n\tVCONSOLES_MAJOR,\n\t{ 0, 0, 0, 0, 0, 0, 0, 0 },\n\tNULL,\n\tNULL,\n\t&tty_driver_fsop,\n\tNULL,\n\tNULL,\n\tNULL\n};\n\nstatic struct device console_device = {\n\t\"console\",\n\tSYSCON_MAJOR,\n\t{ 0, 0, 0, 0, 0, 0, 0, 0 },\n\tNULL,\n\tNULL,\n\t&tty_driver_fsop,\n\tNULL,\n\tNULL,\n\tNULL\n};\n\nunsigned short int ansi_color_table[] = {\n\tCOLOR_BLACK,\n\tCOLOR_RED,\n\tCOLOR_GREEN,\n\tCOLOR_BROWN,\n\tCOLOR_BLUE,\n\tCOLOR_MAGENTA,\n\tCOLOR_CYAN,\n\tCOLOR_WHITE\n};\n\nstatic int is_vconsole(__dev_t dev)\n{\n\tif(MAJOR(dev) == VCONSOLES_MAJOR && MINOR(dev) <= NR_VCONSOLES) {\n\t\treturn 1;\n\t}\n\n\treturn 0;\n}\n\nstatic void adjust(struct vconsole *vc, int x, int y)\n{\n\tif(x < 0) {\n\t\tx = 0;\n\t}\n\tif(x >= vc->columns) {\n\t\tx = vc->columns - 1;\n\t}\n\tif(y < 0) {\n\t\ty = 0;\n\t}\n\tif(y >= vc->lines) {\n\t\ty = vc->lines - 1;\n\t}\n\tvc->x = x;\n\tvc->y = y;\n}\n\nstatic void cr(struct vconsole *vc)\n{\n\tvc->x = 0;\n}\n\nstatic void lf(struct vconsole *vc)\n{\n\tif(vc->y == vc->lines) {\n\t\tvideo.scroll_screen(vc, 0, SCROLL_UP);\n\t} else {\n\t\tvc->y++;\n\t}\n}\n\nstatic void ri(struct vconsole *vc)\n{\n\tvideo.scroll_screen(vc, 0, SCROLL_DOWN);\n}\n\nstatic void csi_J(struct vconsole *vc, int mode)\n{\n\tint from, count;\n\n\tswitch(mode) {\n\t\tcase CSI_J_CUR2END:\t/* Erase Down <ESC>[J */\n\t\t\tfrom = (vc->y * vc->columns) + vc->x;\n\t\t\tcount = vc->columns - vc->x;\n\t\t\tvideo.write_screen(vc, from, count, vc->color_attr);\n\t\t\tfrom = ((vc->y + 1) * vc->columns);\n\t\t\tcount = SCREEN_SIZE - from;\n\t\t\tbreak;\n\t\tcase CSI_J_STA2CUR:\t/* Erase Up <ESC>[1J */\n\t\t\tfrom = vc->y * vc->columns;\n\t\t\tcount = vc->x + 1;\n\t\t\tvideo.write_screen(vc, from, count, vc->color_attr);\n\t\t\tfrom = 0;\n\t\t\tcount = vc->y * vc->columns;\n\t\t\tbreak;\n\t\tcase CSI_J_SCREEN:\t/* Erase Screen <ESC>[2J */\n\t\t\tfrom = 0;\n\t\t\tcount = SCREEN_SIZE;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\treturn;\n\t}\n\tvideo.write_screen(vc, from, count, vc->color_attr);\n}\n\nstatic void csi_K(struct vconsole *vc, int mode)\n{\n\tint from, count;\n\n\tswitch(mode) {\n\t\tcase CSI_K_CUR2END:\t/* Erase End of Line <ESC>[K */\n\t\t\tfrom = (vc->y * vc->columns) + vc->x;\n\t\t\tcount = vc->columns - vc->x;\n\t\t\tbreak;\n\t\tcase CSI_K_STA2CUR:\t/* Erase Start of Line <ESC>[1K */\n\t\t\tfrom = vc->y * vc->columns;\n\t\t\tcount = vc->x + 1;\n\t\t\tbreak;\n\t\tcase CSI_K_LINE:\t/* Erase Line <ESC>[2K */\n\t\t\tfrom = vc->y * vc->columns;\n\t\t\tcount = vc->columns;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\treturn;\n\t}\n\tvideo.write_screen(vc, from, count, vc->color_attr);\n}\n\nstatic void csi_X(struct vconsole *vc, int count)\n{\n\tint from;\n\n\tfrom = (vc->y * vc->columns) + vc->x;\n\tcount = count > (vc->columns - vc->x) ? vc->columns - vc->x : count;\n\tvideo.write_screen(vc, from, count, vc->color_attr);\n}\n\nstatic void csi_L(struct vconsole *vc, int count)\n{\n\tif(count > (vc->lines - vc->top)) {\n\t\tcount = vc->lines - vc->top;\n\t}\n\twhile(count--) {\n\t\tvideo.scroll_screen(vc, vc->y, SCROLL_DOWN);\n\t}\n}\n\nstatic void csi_M(struct vconsole *vc, int count)\n{\n\tif(count > (vc->lines - vc->top)) {\n\t\tcount = vc->lines - vc->top;\n\t}\n\twhile(count--) {\n\t\tvideo.scroll_screen(vc, vc->y, SCROLL_UP);\n\t}\n}\n\nstatic void csi_P(struct vconsole *vc, int count)\n{\n\tif(count > vc->columns) {\n\t\tcount = vc->columns;\n\t}\n\twhile(count--) {\n\t\tvideo.delete_char(vc);\n\t}\n}\n\nstatic void csi_at(struct vconsole *vc, int count)\n{\n\tif(count > vc->columns) {\n\t\tcount = vc->columns;\n\t}\n\twhile(count--) {\n\t\tvideo.insert_char(vc);\n\t}\n}\n\nstatic void default_color_attr(struct vconsole *vc)\n{\n\tvc->color_attr = DEF_MODE;\n\tvc->bold = 0;\n\tvc->underline = 0;\n\tvc->blink = 0;\n\tvc->reverse = 0;\n}\n\n/* Select Graphic Rendition */\nstatic void csi_m(struct vconsole *vc)\n{\n\tint n;\n\n\tif(vc->reverse) {\n\t\tvc->color_attr = ((vc->color_attr & 0x7000) >> 4) | ((vc->color_attr & 0x0700) << 4) | (vc->color_attr & 0x8800); \n\t}\n\n\tfor(n = 0; n < vc->nparms; n++) {\n\t\tswitch(vc->parms[n]) {\n\t\t\tcase SGR_DEFAULT:\n\t\t\t\tdefault_color_attr(vc);\n\t\t\t\tbreak;\n\t\t\tcase SGR_BOLD:\n\t\t\t\tvc->bold = 1;\n\t\t\t\tbreak;\n\t\t\tcase SGR_BLINK:\n\t\t\t\tvc->blink = 1;\n\t\t\t\tbreak;\n\t\t\tcase SGR_REVERSE:\n\t\t\t\tvc->reverse = 1;\n\t\t\t\tbreak;\n\t\t\t/* normal intensity */\n\t\t\tcase 21:\n\t\t\tcase 22:\n\t\t\t\tvc->bold = 0;\n\t\t\t\tbreak;\n\t\t\tcase SGR_BLINK_OFF:\n\t\t\t\tvc->blink = 0;\n\t\t\t\tbreak;\n\t\t\tcase SGR_REVERSE_OFF:\n\t\t\t\tvc->reverse = 0;\n\t\t\t\tbreak;\n\t\t\tcase SGR_BLACK_FG:\n\t\t\tcase SGR_RED_FG:\n\t\t\tcase SGR_GREEN_FG:\n\t\t\tcase SGR_BROWN_FG:\n\t\t\tcase SGR_BLUE_FG:\n\t\t\tcase SGR_MAGENTA_FG:\n\t\t\tcase SGR_CYAN_FG:\n\t\t\tcase SGR_WHITE_FG:\n\t\t\t\tvc->color_attr = (vc->color_attr & 0xF8FF) | (ansi_color_table[vc->parms[n] - 30]);\n\t\t\t\tbreak;\n\t\t\tcase SGR_DEFAULT_FG_U_ON:\n\t\t\tcase SGR_DEFAULT_FG_U_OFF:\n\t\t\t\t/* not supported yet */\n\t\t\t\tbreak;\n\t\t\tcase SGR_BLACK_BG:\n\t\t\tcase SGR_RED_BG:\n\t\t\tcase SGR_GREEN_BG:\n\t\t\tcase SGR_BROWN_BG:\n\t\t\tcase SGR_BLUE_BG:\n\t\t\tcase SGR_MAGENTA_BG:\n\t\t\tcase SGR_CYAN_BG:\n\t\t\tcase SGR_WHITE_BG:\n\t\t\t\tvc->color_attr = (vc->color_attr & 0x8FFF) | ((ansi_color_table[vc->parms[n] - 40]) << 4);\n\t\t\t\tbreak;\n\t\t\tcase SGR_DEFAULT_BG:\n\t\t\t\t/* not supported yet */\n\t\t\t\tbreak;\n\t\t}\n\t}\n\tif(vc->bold) {\n\t\tvc->color_attr |= 0x0800;\n\t} else {\n\t\tvc->color_attr &= ~0x0800;\n\t}\n\tif(vc->blink) {\n\t\tvc->color_attr |= 0x8000;\n\t} else {\n\t\tvc->color_attr &= ~0x8000;\n\t}\n\tif(vc->reverse) {\n\t\tvc->color_attr = ((vc->color_attr & 0x7000) >> 4) | ((vc->color_attr & 0x0700) << 4) | (vc->color_attr & 0x8800); \n\t}\n}\n\nstatic void init_vt(struct vconsole *vc)\n{\n\tvc->vt_mode.mode = VT_AUTO;\n\tvc->vt_mode.waitv = 0;\n\tvc->vt_mode.relsig = 0;\n\tvc->vt_mode.acqsig = 0;\n\tvc->vt_mode.frsig = 0;\n\tvc->vc_mode = KD_TEXT;\n\tvc->tty->pid = 0;\n\tvc->switchto_tty = -1;\n}\n\nstatic void insert_seq(struct tty *tty, char *buf, int count)\n{\n\twhile(count--) {\n\t\tcharq_putchar(&tty->read_q, *(buf++));\n\t}\n\ttty->input(tty);\n}\n\nstatic void vcbuf_scroll_up(void)\n{\n\tmemcpy_w(vcbuf, vcbuf + video.columns, (VC_BUF_SIZE - video.columns) * 2);\n}\n\nstatic void vcbuf_refresh(struct vconsole *vc)\n{\n\tshort int *screen;\n\n\tscreen = (short int *)vc->screen;\n\tmemset_w(vcbuf, BLANK_MEM, VC_BUF_SIZE);\n\tmemcpy_w(vcbuf, screen, SCREEN_SIZE);\n}\n\nstatic void echo_char(struct vconsole *vc, unsigned char *buf, unsigned int count)\n{\n\tunsigned char ch;\n\tunsigned int flags;\n\n\tSAVE_FLAGS(flags); CLI();\n\tif(vc->flags & CONSOLE_HAS_FOCUS) {\n\t\tif(video.buf_top) {\n\t\t\tvideo.restore_screen(vc);\n\t\t\tvideo.show_cursor(vc, ON);\n\t\t\tvideo.buf_top = 0;\n\t\t}\n\t}\n\n\twhile(count--) {\n\t\tch = *buf++;\n\t\tif(ch == '\\0') {\n\t\t\tcontinue;\n\n\t\t} else if(ch == '\\b') {\n\t\t\tif(vc->x) {\n\t\t\t\tvc->x--;\n\t\t\t}\n\n\t\t} else if(ch == '\\a') {\n\t\t\tvconsole_beep();\n\n\t\t} else if(ch == '\\r') {\n\t\t\tcr(vc);\n\n\t\t} else if(ch == '\\n') {\n\t\t\tcr(vc);\n\t\t\tvc->y++;\n\t\t\tif(vc->flags & CONSOLE_HAS_FOCUS) {\n\t\t\t\tvideo.buf_y++;\n\t\t\t}\n\n\t\t} else if(ch == '\\t') {\n\t\t\twhile(vc->x < (vc->columns - 1)) {\n\t\t\t\tif(vc->tty->tab_stop[++vc->x]) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n/*\t\t\tvc->x += TAB_SIZE - (vc->x % TAB_SIZE); */\n\t\t\tvc->check_x = 1;\n\n\t\t} else {\n\t\t\tif((vc->x == vc->columns - 1) && vc->check_x) {\n\t\t\t\tvc->x = 0;\n\t\t\t\tvc->y++;\n\t\t\t\tif(vc->flags & CONSOLE_HAS_FOCUS) {\n\t\t\t\t\tvideo.buf_y++;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(vc->y >= vc->lines) {\n\t\t\t\tvideo.scroll_screen(vc, 0, SCROLL_UP);\n\t\t\t\tvc->y--;\n\t\t\t}\n\t\t\tvideo.put_char(vc, ch);\n\t\t\tif(vc->x < vc->columns - 1) {\n\t\t\t\tvc->check_x = 0;\n\t\t\t\tvc->x++;\n\t\t\t} else {\n\t\t\t\tvc->check_x = 1;\n\t\t\t}\n\t\t}\n\t\tif(vc->y >= vc->lines) {\n\t\t\tvideo.scroll_screen(vc, 0, SCROLL_UP);\n\t\t\tvc->y--;\n\t\t}\n\t\tif(vc->flags & CONSOLE_HAS_FOCUS) {\n\t\t\tif(video.buf_y >= VC_BUF_LINES) {\n\t\t\t\tvcbuf_scroll_up();\n\t\t\t\tvideo.buf_y--;\n\t\t\t}\n\t\t}\n\t}\n\tvideo.update_curpos(vc);\n\tRESTORE_FLAGS(flags);\n}\n\nvoid vconsole_reset(struct tty *tty)\n{\n\tint n;\n\tstruct vconsole *vc;\n\n\tvc = (struct vconsole *)tty->driver_data;\n\n\tvc->top = 0;\n\tvc->lines = video.lines;\n\tvc->columns = video.columns;\n\tvc->check_x = 0;\n\tvc->led_status = 0;\n\tset_leds(vc->led_status);\n\tvc->scrlock = vc->numlock = vc->capslock = 0;\n\tvc->esc = vc->sbracket = vc->semicolon = vc->question = 0;\n\tvc->parmv1 = vc->parmv2 = 0;\n\tvc->nparms = 0;\n\tmemset_b(vc->parms, 0, sizeof(vc->parms));\n\tdefault_color_attr(vc);\n\tvc->saved_x = vc->saved_y = 0;\n\n\tfor(n = 0; n < MAX_TAB_COLS; n++) {\n\t\tif(!(n % TAB_SIZE)) {\n\t\t\tvc->tty->tab_stop[n] = 1;\n\t\t} else {\n\t\t\tvc->tty->tab_stop[n] = 0;\n\t\t}\n\t}\n\n\ttty_reset(tty);\n\tvc->tty->winsize.ws_row = vc->lines - vc->top;\n\tvc->tty->winsize.ws_col = vc->columns;\n\n\tinit_vt(vc);\n\tvc->flags &= ~CONSOLE_BLANKED;\n\tvideo.update_curpos(vc);\n}\n\n/* https://vt100.net/docs/vt100-ug/chapter3.html */\nvoid vconsole_write(struct tty *tty)\n{\n\tint n;\n\tunsigned char ch;\n\tint numeric;\n\tstruct vconsole *vc;\n\n\tvc = (struct vconsole *)tty->driver_data;\n\n\tif(vc->flags & CONSOLE_HAS_FOCUS) {\n\t\tif(video.buf_top) {\n\t\t\tvideo.restore_screen(vc);\n\t\t\tvideo.buf_top = 0;\n\t\t\tvideo.show_cursor(vc, ON);\n\t\t\tvideo.update_curpos(vc);\n\t\t}\n\t}\n\n\tch = numeric = 0;\n\n\twhile(!vc->scrlock && tty->write_q.count > 0) {\n\t\tch = charq_getchar(&tty->write_q);\n\n\t\tif(vc->esc) {\n\t\t\tif(vc->sbracket) {\n\t\t\t\tif(ISDIGIT(ch)) {\n\t\t\t\t\tnumeric = 1;\n\t\t\t\t\tif(vc->semicolon) {\n\t\t\t\t\t\tvc->parmv2 *= 10;\n\t\t\t\t\t\tvc->parmv2 += ch - '0';\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvc->parmv1 *= 10;\n\t\t\t\t\t\tvc->parmv1 += ch - '0';\n\t\t\t\t\t}\n\t\t\t\t\tvc->parms[vc->nparms] *= 10;\n\t\t\t\t\tvc->parms[vc->nparms] += ch - '0';\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tswitch(ch) {\n\t\t\t\t\tcase ';':\n\t\t\t\t\t\tvc->semicolon = 1;\n\t\t\t\t\t\tvc->parmv2 = 0;\n\t\t\t\t\t\tvc->nparms++;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase '?':\n\t\t\t\t\t\tvc->question = 1;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase '@':\t/* Insert Character(s) <ESC>[ n @ */\n\t\t\t\t\t\tvc->parmv1 = !vc->parmv1 ? 1 : vc->parmv1;\n\t\t\t\t\t\tcsi_at(vc, vc->parmv1);\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'A':\t/* Cursor Up <ESC>[ n A */\n\t\t\t\t\t\tvc->parmv1 = !vc->parmv1 ? 1 : vc->parmv1;\n\t\t\t\t\t\tadjust(vc, vc->x, vc->y - vc->parmv1);\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'B':\t/* Cursor Down <ESC>[ n B */\n\t\t\t\t\t\tvc->parmv1 = !vc->parmv1 ? 1 : vc->parmv1;\n\t\t\t\t\t\tadjust(vc, vc->x, vc->y + vc->parmv1);\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'C':\t/* Cursor Forward <ESC>[ n C */\n\t\t\t\t\t\tvc->parmv1 = !vc->parmv1 ? 1 : vc->parmv1;\n\t\t\t\t\t\tadjust(vc, vc->x + vc->parmv1, vc->y);\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'D':\t/* Cursor Backward <ESC>[ n D */\n\t\t\t\t\t\tvc->parmv1 = !vc->parmv1 ? 1 : vc->parmv1;\n\t\t\t\t\t\tadjust(vc, vc->x - vc->parmv1, vc->y);\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'E':\t/* Cursor Next Line(s) <ESC>[ n E */\n\t\t\t\t\t\tvc->parmv1 = !vc->parmv1 ? 1 : vc->parmv1;\n\t\t\t\t\t\tadjust(vc, 0, vc->y + vc->parmv1);\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'F':\t/* Cursor Previous Line(s) <ESC>[ n F */\n\t\t\t\t\t\tvc->parmv1 = !vc->parmv1 ? 1 : vc->parmv1;\n\t\t\t\t\t\tadjust(vc, 0, vc->y - vc->parmv1);\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'G':\t/* Cursor Horizontal Position <ESC>[ n G */\n\t\t\t\t\tcase '`':\n\t\t\t\t\t\tvc->parmv1 = vc->parmv1 ? vc->parmv1 - 1 : vc->parmv1;\n\t\t\t\t\t\tadjust(vc, vc->parmv1, vc->y);\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'H':\t/* Cursor Home <ESC>[ ROW ; COLUMN H */\n\t\t\t\t\tcase 'f':\t/* Horizontal Vertical Position <ESC>[ ROW ; COLUMN f */\n\t\t\t\t\t\tvc->parmv1 = vc->parmv1 ? vc->parmv1 - 1 : vc->parmv1;\n\t\t\t\t\t\tvc->parmv2 = vc->parmv2 ? vc->parmv2 - 1 : vc->parmv2;\n\t\t\t\t\t\tadjust(vc, vc->parmv2, vc->parmv1);\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'I':\t/* Cursor Forward Tabulation <ESC>[ n I */\n\t\t\t\t\t\tvc->parmv1 = !vc->parmv1 ? 1 : vc->parmv1;\n\t\t\t\t\t\twhile(vc->parmv1--){\n\t\t\t\t\t\t\twhile(vc->x < (vc->columns - 1)) {\n\t\t\t\t\t\t\t\tif(vc->tty->tab_stop[++vc->x]) {\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tadjust(vc, vc->x, vc->y);\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'J':\t/* Erase (Down/Up/Screen) <ESC>[J */\n\t\t\t\t\t\tcsi_J(vc, vc->parmv1);\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'K':\t/* Erase (End of/Start of/) Line <ESC>[K */\n\t\t\t\t\t\tcsi_K(vc, vc->parmv1);\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'L':\t/* Insert Line(s) <ESC>[ n L */\n\t\t\t\t\t\tvc->parmv1 = !vc->parmv1 ? 1 : vc->parmv1;\n\t\t\t\t\t\tcsi_L(vc, vc->parmv1);\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'M':\t/* Delete Line(s) <ESC>[ n M */\n\t\t\t\t\t\tvc->parmv1 = !vc->parmv1 ? 1 : vc->parmv1;\n\t\t\t\t\t\tcsi_M(vc, vc->parmv1);\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'P':\t/* Delete Character(s) <ESC>[ n P */\n\t\t\t\t\t\tvc->parmv1 = !vc->parmv1 ? 1 : vc->parmv1;\n\t\t\t\t\t\tcsi_P(vc, vc->parmv1);\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'S':\t/* Scroll Up <ESC>[ n S */\n\t\t\t\t\t\tvc->parmv1 = !vc->parmv1 ? 1 : vc->parmv1;\n\t\t\t\t\t\twhile(vc->parmv1--) {\n\t\t\t\t\t\t\tvideo.scroll_screen(vc, 0, SCROLL_UP);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'T':\t/* Scroll Down <ESC>[ n T */\n\t\t\t\t\t\tvc->parmv1 = !vc->parmv1 ? 1 : vc->parmv1;\n\t\t\t\t\t\twhile(vc->parmv1--) {\n\t\t\t\t\t\t\tvideo.scroll_screen(vc, 0, SCROLL_DOWN);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'X':\t/* Erase Character(s) <ESC>[ n X */\n\t\t\t\t\t\tvc->parmv1 = !vc->parmv1 ? 1 : vc->parmv1;\n\t\t\t\t\t\tcsi_X(vc, vc->parmv1);\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'c':\t/* Query Device Code <ESC>[c */\n\t\t\t\t\t\tif(!numeric) {\n\t\t\t\t\t\t\tinsert_seq(tty, VT100ID, 7);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'd':\t/* Cursor Vertical Position <ESC>[ n d */\n\t\t\t\t\t\tvc->parmv1 = vc->parmv1 ? vc->parmv1 - 1 : vc->parmv1;\n\t\t\t\t\t\tadjust(vc, vc->x, vc->parmv1);\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'g':\n\t\t\t\t\t\tswitch(vc->parmv1) {\n\t\t\t\t\t\t\tcase 0:\t/* Clear Tab <ESC>[g */\n\t\t\t\t\t\t\t\tvc->tty->tab_stop[vc->x] = 0;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase 3:\t/* Clear All Tabs <ESC>[3g */\n\t\t\t\t\t\t\tcase 5:\t/* Clear All Tabs <ESC>[5g */\n\t\t\t\t\t\t\t\tfor(n = 0; n < MAX_TAB_COLS; n++)\n\t\t\t\t\t\t\t\t\tvc->tty->tab_stop[n] = 0;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'h':\n\t\t\t\t\t\tif(vc->question) {\n\t\t\t\t\t\t\tswitch(vc->parmv1) {\n\t\t\t\t\t\t\t\t/* DEC modes */\n\t\t\t\t\t\t\t\tcase 25: /* Switch Cursor Visible <ESC>[?25h */\n\t\t\t\t\t\t\t\t\tvideo.show_cursor(vc, ON);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'l':\n\t\t\t\t\t\tif(vc->question) {\n\t\t\t\t\t\t\tswitch(vc->parmv1) {\n\t\t\t\t\t\t\t\t/* DEC modes */\n\t\t\t\t\t\t\t\tcase 25: /* Switch Cursor Invisible <ESC>[?25l */\n\t\t\t\t\t\t\t\t\tvideo.show_cursor(vc, OFF);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'm':\t/* Select Graphic Rendition <ESC> n ... m */\n\t\t\t\t\t\tvc->nparms++;\n\t\t\t\t\t\tcsi_m(vc);\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'n':\n\t\t\t\t\t\tif(!vc->question) {\n\t\t\t\t\t\t\tswitch(vc->parmv1) {\n\t\t\t\t\t\t\t\tcase 5:\t/* Query Device Status <ESC>[5n */\n\t\t\t\t\t\t\t\t\tinsert_seq(tty, DEVICE_OK, 4);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\tcase 6:\t/* Query Cursor Position <ESC>[6n */\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tchar curpos[8];\n\t\t\t\t\t\t\t\t\t\tchar len;\n\t\t\t\t\t\t\t\t\t\tlen = sprintk(curpos, \"\\033[%d;%dR\", vc->y, vc->x);\n\t\t\t\t\t\t\t\t\t\tinsert_seq(tty, curpos, len);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'r':\t/* Top and Bottom Margins <ESC>[r  / <ESC>[{start};{end}r */\n\t\t\t\t\t\tif(!vc->parmv1) {\n\t\t\t\t\t\t\tvc->parmv1++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(!vc->parmv2) {\n\t\t\t\t\t\t\tvc->parmv2 = video.lines;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(vc->parmv1 < vc->parmv2 && vc->parmv2 <= video.lines) {\n\t\t\t\t\t\t\tvc->top = vc->parmv1 - 1;\n\t\t\t\t\t\t\tvc->lines = vc->parmv2;\n\t\t\t\t\t\t\tadjust(vc, 0, 0);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 's':\t/* Save Cursor <ESC>[s */\n\t\t\t\t\t\tvc->saved_x = vc->x;\n\t\t\t\t\t\tvc->saved_y = vc->y;\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'u':\t/* Restore Cursor <ESC>[u */\n\t\t\t\t\t\tvc->x = vc->saved_x;\n\t\t\t\t\t\tvc->y = vc->saved_y;\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tswitch(ch) {\n\t\t\t\t\tcase '[':\n\t\t\t\t\t\tvc->sbracket = 1;\n\t\t\t\t\t\tvc->semicolon = 0;\n\t\t\t\t\t\tvc->question = 0;\n\t\t\t\t\t\tvc->parmv1 = vc->parmv2 = 0;\n\t\t\t\t\t\tvc->nparms = 0;\n\t\t\t\t\t\tmemset_b(vc->parms, 0, sizeof(vc->parms));\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase '7':\t/* Save Cursor & Attrs <ESC>7 */\n\t\t\t\t\t\tvc->saved_x = vc->x;\n\t\t\t\t\t\tvc->saved_y = vc->y;\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase '8':\t/* Restore Cursor & Attrs <ESC>8 */\n\t\t\t\t\t\tvc->x = vc->saved_x;\n\t\t\t\t\t\tvc->y = vc->saved_y;\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'D':\t/* Scroll Up <ESC>D */\n\t\t\t\t\t\tlf(vc);\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'E':\t/* Move To Next Line <ESC>E */\n\t\t\t\t\t\tcr(vc);\n\t\t\t\t\t\tlf(vc);\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'H':\t/* Set Tab <ESC>H */\n\t\t\t\t\t\tvc->tty->tab_stop[vc->x] = 1;\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'M':\t/* Scroll Down <ESC>M */\n\t\t\t\t\t\tri(vc);\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'Z':\t/* Identify Terminal <ESC>Z */\n\t\t\t\t\t\tinsert_seq(tty, VT100ID, 7);\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tcase 'c':\t/* Reset Device <ESC>c */\n\t\t\t\t\t\tvconsole_reset(vc->tty);\n\t\t\t\t\t\tvc->x = vc->y = 0;\n\t\t\t\t\t\tcsi_J(vc, CSI_J_SCREEN);\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tCSE;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tswitch(ch) {\n\t\t\tcase '\\033':\n\t\t\t\tvc->esc = 1;\n\t\t\t\tvc->sbracket = 0;\n\t\t\t\tvc->semicolon = 0;\n\t\t\t\tvc->question = 0;\n\t\t\t\tvc->parmv1 = vc->parmv2 = 0;\n\t\t\t\tcontinue;\n\t\t\tdefault:\n\t\t\t\techo_char(vc, &ch, 1);\n\t\t\t\tcontinue;\n\t\t}\n\t}\n\tif(ch) {\n\t\tif(vc->vc_mode != KD_GRAPHICS) {\n\t\t\tvideo.update_curpos(vc);\n\t\t}\n\t\twakeup(&tty->write_q);\n\t}\n}\n\nvoid vconsole_select(int new_cons)\n{\n\tnew_cons++;\n\tif(new_cons > NR_VCONSOLES) {\n\t\treturn;\n\t}\n\n\tif(current_cons != new_cons) {\n\t\tif(vc[current_cons].vt_mode.mode == VT_PROCESS) {\n\t\t\tif(!kill_pid(vc[current_cons].tty->pid, vc[current_cons].vt_mode.relsig, KERNEL)) {\n\t\t\t\tvc[current_cons].switchto_tty = new_cons;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tinit_vt(&vc[current_cons]);\n\t\t}\n\t\tif(vc[current_cons].vc_mode == KD_GRAPHICS) {\n\t\t\treturn;\n\t\t}\n\t\tvconsole_select_final(new_cons);\n\t}\n}\n\nvoid vconsole_select_final(int new_cons)\n{\n\tif(current_cons != new_cons) {\n\t\tif(vc[new_cons].vt_mode.mode == VT_PROCESS) {\n\t\t\tif(kill_pid(vc[new_cons].tty->pid, vc[new_cons].vt_mode.acqsig, KERNEL)) {\n\t\t\t\tinit_vt(&vc[new_cons]);\n\t\t\t}\n\t\t}\n\t\tif(video.buf_top) {\n\t\t\tvideo.buf_top = 0;\n\t\t\tvideo.show_cursor(&vc[current_cons], ON);\n\t\t\tvideo.update_curpos(&vc[current_cons]);\n\t\t}\n\t\tvc[current_cons].vidmem = NULL;\n\t\tvc[current_cons].flags &= ~CONSOLE_HAS_FOCUS;\n\t\tvc[new_cons].vidmem = (unsigned char *)video.address;\n\t\tvc[new_cons].flags |= CONSOLE_HAS_FOCUS;\n\t\tcurrent_cons = new_cons;\n\t\tvideo.update_curpos(&vc[current_cons]);\n\t\tvideo.restore_screen(&vc[current_cons]);\n\t\tset_leds(vc[current_cons].led_status);\n\n\t\tvideo.buf_y = vc[current_cons].y;\n\t\tvideo.buf_top = 0;\n\t\tvcbuf_refresh(&vc[current_cons]);\n\t\tvideo.show_cursor(&vc[current_cons], COND);\n\t\tvideo.cursor_blink((unsigned int)&vc[current_cons]);\n\t}\n}\n\nvoid unblank_screen(struct vconsole *vc)\n{\n\tif(!(vc->flags & CONSOLE_BLANKED)) {\n\t\treturn;\n\t}\n\tvideo.restore_screen(vc);\n\tvc->flags &= ~CONSOLE_BLANKED;\n\tvideo.show_cursor(vc, ON);\n}\n\nvoid vconsole_start(struct tty *tty)\n{\n\tstruct vconsole *vc;\n\n\tvc = (struct vconsole *)tty->driver_data;\n\tif(!vc->scrlock) {\n\t\treturn;\n\t}\n\tvc->led_status &= ~SCRLBIT;\n\tvc->scrlock = 0;\n\tset_leds(vc->led_status);\n}\n\nvoid vconsole_stop(struct tty *tty)\n{\n\tstruct vconsole *vc;\n\n\tvc = (struct vconsole *)tty->driver_data;\n\tif(vc->scrlock) {\n\t\treturn;\n\t}\n\tvc->led_status |= SCRLBIT;\n\tvc->scrlock = 1;\n\tset_leds(vc->led_status);\n}\n\nvoid vconsole_beep(void)\n{\n\tstruct callout_req creq;\n\n\tpit_beep_on();\n\tcreq.fn = pit_beep_off;\n\tcreq.arg = 0;\n\tadd_callout(&creq, HZ / 8);\n}\n\nvoid vconsole_deltab(struct tty *tty)\n{\n\tint col, n;\n\tunsigned char count;\n\tstruct vconsole *vc;\n\tstruct cblock *cb;\n\tunsigned char ch;\n\n\tvc = (struct vconsole *)tty->driver_data;\n\tcb = tty->cooked_q.head;\n\tcol = count = 0;\n\n\twhile(cb) {\n\t\tfor(n = 0; n < cb->end_off; n++) {\n\t\t\tif(n >= cb->start_off) {\n\t\t\t\tch = cb->data[n];\n\t\t\t\tif(ch == '\\t') {\n\t\t\t\t\twhile(!vc->tty->tab_stop[++col]);\n\t\t\t\t} else {\n\t\t\t\t\tcol++;\n\t\t\t\t\tif(ISCNTRL(ch) && !ISSPACE(ch) && tty->termios.c_lflag & ECHOCTL) {\n\t\t\t\t\t\tcol++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcol %= vc->columns;\n\t\t\t}\n\t\t}\n\t\tcb = cb->next;\n\t}\n\tcount = vc->x - col;\n\n\twhile(count--) {\n\t\tcharq_putchar(&tty->write_q, '\\b');\n\t}\n}\n\nvoid console_init(void)\n{\n\tint syscon, n;\n\tstruct tty *tty;\n\n\tif(video.flags & VPF_VGA) {\n\t\tprintk(\"console   0x%04x-0x%04x     -\\t%s\\n\", video.port, video.port + 1, video.signature);\n\t}\n\tif(video.flags & VPF_VESAFB) {\n\t\tprintk(\"console                     -\\tcolor framebuffer, screen=%dx%d, font=%dx%d\\n\", video.columns, video.lines, video.fb_char_width, video.fb_char_height);\n\t}\n\n\tfor(n = 1; n <= NR_VCONSOLES; n++) {\n\t\tif((tty = register_tty(MKDEV(VCONSOLES_MAJOR, n)))) {\n\t\t\ttty->driver_data = (void *)&vc[n];\n\t\t\ttty->stop = vconsole_stop;\n\t\t\ttty->start = vconsole_start;\n\t\t\ttty->deltab = vconsole_deltab;\n\t\t\ttty->reset = vconsole_reset;\n\t\t\ttty->input = do_cook;\n\t\t\ttty->output = vconsole_write;\n\t\t\tvc[n].tty = tty;\n\t\t\tif(video.flags & VPF_VGA) {\n\t\t\t\tvc[n].screen = (short int *)kmalloc(PAGE_SIZE);\n\t\t\t}\n\t\t\tif(video.flags & VPF_VESAFB) {\n\t\t\t\tvc[n].screen = vc_screen[n];\n\t\t\t}\n\t\t\tvc[n].vidmem = NULL;\n\t\t\tmemset_w(vc[n].screen, BLANK_MEM, SCREEN_SIZE);\n\t\t\tvconsole_reset(tty);\n\t\t}\n\t}\n\tprintk(\"\\t\\t\\t\\t%d virtual consoles\\n\", NR_VCONSOLES);\n\n#ifdef CONFIG_QEMU_DEBUGCON\n\tif(kstat.flags & KF_HAS_DEBUGCON) {\n\t\tprintk(\"\\t\\t\\t\\tQEMU Bochs-style debug console emulation enabled\\n\");\n\t}\n#endif /* CONFIG_QEMU_DEBUGCON */\n\n\tcurrent_cons = 1;\n\tvideo.show_cursor(&vc[current_cons], ON);\n\tvc[current_cons].vidmem = (unsigned char *)video.address;\n\tvc[current_cons].flags |= CONSOLE_HAS_FOCUS;\n\n\tif(video.flags & VPF_VGA) {\n\t\tmemcpy_w(vc[current_cons].screen, video.address, SCREEN_SIZE);\n\t}\n\n\tvideo.get_curpos(&vc[current_cons]);\n\tvideo.update_curpos(&vc[current_cons]);\n\tvideo.buf_y = vc[current_cons].y;\n\tvideo.buf_top = 0;\n\n\tSET_MINOR(console_device.minors, 0);\n\tSET_MINOR(console_device.minors, 1);\n\tfor(n = 0; n <= NR_VCONSOLES; n++) {\n\t\tSET_MINOR(tty_device.minors, n);\n\t}\n\n\tregister_device(CHR_DEV, &console_device);\n\tregister_device(CHR_DEV, &tty_device);\n\n\t/* check if a vconsole will act as a system console */\n\tfor(n = 0, syscon = 0; n < NR_SYSCONSOLES; n++) {\n\t\tif(is_vconsole(sysconsole_table[n].dev)) {\n\t\t\tif((tty = get_tty(sysconsole_table[n].dev))) {\n\t\t\t\tif(!syscon) {\n\t\t\t\t\tsyscon = tty->dev;\n\t\t\t\t}\n\t\t\t\tregister_console(tty);\n\t\t\t}\n\t\t}\n\t}\n\tif(syscon) {\n\t\t/* flush early log into the first console */\n\t\ttty = get_tty(syscon);\n\t\tflush_log_buf(tty);\n\t}\n}\n"
  },
  {
    "path": "drivers/char/defkeymap.c",
    "content": "/*\n * fiwix/drivers/char/defkeymap.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/keyboard.h>\n#include <fiwix/string.h>\n\n#define BS\t127\t/* backspace */\n\n__key_t keymap[NR_MODIFIERS * NR_SCODES] = {\n/*\n * Standard US keyboard (default keymap) with 16 modifiers\n *\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tShift\n *\t\t\t\t\t\t\t\t\t\tShift\t\t\t\tShift\t\tShift\tAltGr\tAltGr\n * SCAN\t\t\t\t\t\tShift\t\tShift\tAltGr\tAltGr\t\tShift\tAltGr\tAltGr\tCtrl\tCtrl\tCtrl\tCtrl\n * CODE  KEY\t\tBase\tShift\tAltGr\tAltGr\tCtrl\tCtrl\tCtrl\tCtrl\tAlt\tAlt\tAlt\tAlt\tAlt\tAlt\tAlt\tAlt\n * ==================================================================================================================================================== */\n/*  00 - 0\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  01 - ESC\t*/\tC('['),\tC('['),\t0,\t0,\t0,\t0,\t0,\t0,\tA('['),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  02 - 1\t*/\t'1',\t'!',\t0,\t0,\t0,\t0,\t0,\t0,\tA('1'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  03 - 2\t*/\t'2',\t'@',\t'@',\t0,\t0,\t0,\t0,\t0,\tA('2'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  04 - 3\t*/\t'3',\t'#',\t0,\t0,\tC('['),\t0,\t0,\t0,\tA('3'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  05 - 4\t*/\t'4',\t'$',\t'$',\t0,\tC('\\\\'),0,\t0,\t0,\tA('4'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  06 - 5\t*/\t'5',\t'%',\t0,\t0,\tC(']'),\t0,\t0,\t0,\tA('5'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  07 - 6\t*/\t'6',\t'^',\t0,\t0,\tC('^'),\t0,\t0,\t0,\tA('6'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  08 - 7\t*/\t'7',\t'&',\t'{',\t0,\tC('_'),\t0,\t0,\t0,\tA('7'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  09 - 8\t*/\t'8',\t'*',\t'[',\t0,\tBS,\t0,\t0,\t0,\tA('8'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  10 - 9\t*/\t'9',\t'(',\t']',\t0,\t0,\t0,\t0,\t0,\tA('9'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  11 - 0\t*/\t'0',\t')',\t'}',\t0,\t0,\t0,\t0,\t0,\tA('0'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  12 - -_\t*/\t'-',\t'_',\t'\\\\',\t0,\tC('_'),\t0,\t0,\t0,\tA('-'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  13 - =+\t*/\t'=',\t'+',\t0,\t0,\t0,\t0,\t0,\t0,\tA('='),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  14 - BS\t*/\tBS,\tBS,\t0,\t0,\t0,\t0,\t0,\t0,\tA(BS),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  15 - TAB\t*/\t'\\t',\t'\\t',\t0,\t0,\t0,\t0,\t0,\t0,\tA('\\t'),0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  16 - q\t*/\tL('q'),\tL('Q'),\tL('q'),\tL('Q'),\tC('Q'),\t0,\t0,\t0,\tA('q'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  17 - w\t*/\tL('w'),\tL('W'),\tL('w'),\tL('W'),\tC('W'),\t0,\t0,\t0,\tA('w'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  18 - e\t*/\tL('e'),\tL('E'),\tL('e'),\tL('E'),\tC('E'),\t0,\t0,\t0,\tA('e'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  19 - r\t*/\tL('r'),\tL('R'),\tL('r'),\tL('R'),\tC('R'),\t0,\t0,\t0,\tA('r'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  20 - t\t*/\tL('t'),\tL('T'),\tL('t'),\tL('T'),\tC('T'),\t0,\t0,\t0,\tA('t'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  21 - y\t*/\tL('y'),\tL('Y'),\tL('y'),\tL('Y'),\tC('Y'),\t0,\t0,\t0,\tA('y'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  22 - u\t*/\tL('u'),\tL('U'),\tL('u'),\tL('U'),\tC('U'),\t0,\t0,\t0,\tA('u'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  23 - i\t*/\tL('i'),\tL('I'),\tL('i'),\tL('I'),\tC('I'),\t0,\t0,\t0,\tA('i'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  24 - o\t*/\tL('o'),\tL('O'),\tL('o'),\tL('O'),\tC('O'),\t0,\t0,\t0,\tA('o'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  25 - p\t*/\tL('p'),\tL('P'),\tL('p'),\tL('P'),\tC('P'),\t0,\t0,\t0,\tA('p'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  26 - [{\t*/\t'[',\t'{',\t0,\t0,\tC('['),\t0,\t0,\t0,\tA('['),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  27 - ]}\t*/\t']',\t'}',\t'~',\t0,\tC(']'),\t0,\t0,\t0,\tA(']'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  28 - CR\t*/\tCR,\tCR,\tCR,\tCR,\tCR,\t0,\t0,\t0,\tA(CR),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  29 - LCTRL\t*/\tLCTRL,\tLCTRL,\tLCTRL,\tLCTRL,\tLCTRL,\t0,\t0,\t0,\tLCTRL,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  30 - a\t*/\tL('a'),\tL('A'),\tL('a'),\tL('A'),\tC('A'),\t0,\t0,\t0,\tA('a'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  31 - s\t*/\tL('s'),\tL('S'),\tL('s'),\tL('S'),\tC('S'),\t0,\t0,\t0,\tA('s'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  32 - d\t*/\tL('d'),\tL('D'),\tL('d'),\tL('D'),\tC('D'),\t0,\t0,\t0,\tA('d'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  33 - f\t*/\tL('f'),\tL('F'),\tL('f'),\tL('F'),\tC('F'),\t0,\t0,\t0,\tA('f'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  34 - g\t*/\tL('g'),\tL('G'),\tL('g'),\tL('G'),\tC('G'),\t0,\t0,\t0,\tA('g'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  35 - h\t*/\tL('h'),\tL('H'),\tL('h'),\tL('H'),\tC('H'),\t0,\t0,\t0,\tA('h'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  36 - j\t*/\tL('j'),\tL('J'),\tL('j'),\tL('J'),\tC('J'),\t0,\t0,\t0,\tA('j'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  37 - k\t*/\tL('k'),\tL('K'),\tL('k'),\tL('K'),\tC('K'),\t0,\t0,\t0,\tA('k'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  38 - l\t*/\tL('l'),\tL('L'),\tL('l'),\tL('L'),\tC('L'),\t0,\t0,\t0,\tA('l'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  39 - ;:\t*/\t';',\t':',\t0,\t0,\t0,\t0,\t0,\t0,\tA(';'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  40 - '\"\t*/\t'\\'',\t'\"',\t0,\t0,\tC('G'),\t0,\t0,\t0,\tA('\\''),0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  41 - `~\t*/\t'`',\t'~',\t0,\t0,\t0,\t0,\t0,\t0,\tA('`'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  42 - LSHF\t*/\tLSHIFT,\tLSHIFT,\tLSHIFT,\tLSHIFT,\tLSHIFT,\t0,\t0,\t0,\tLSHIFT,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  43 - \\|\t*/\t'\\\\',\t'|',\t0,\t0,\tC('\\\\'),0,\t0,\t0,\tA('\\\\'),0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  44 - z\t*/\tL('z'),\tL('Z'),\tL('z'),\tL('Z'),\tC('Z'),\t0,\t0,\t0,\tA('z'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  45 - x\t*/\tL('x'),\tL('X'),\tL('x'),\tL('X'),\tC('X'),\t0,\t0,\t0,\tA('x'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  46 - c\t*/\tL('c'),\tL('C'),\tL('c'),\tL('C'),\tC('C'),\t0,\t0,\t0,\tA('c'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  47 - v\t*/\tL('v'),\tL('V'),\tL('v'),\tL('V'),\tC('V'),\t0,\t0,\t0,\tA('v'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  48 - b\t*/\tL('b'),\tL('B'),\tL('b'),\tL('B'),\tC('B'),\t0,\t0,\t0,\tA('b'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  49 - n\t*/\tL('n'),\tL('N'),\tL('n'),\tL('N'),\tC('N'),\t0,\t0,\t0,\tA('n'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  50 - m\t*/\tL('m'),\tL('M'),\tL('m'),\tL('M'),\tC('M'),\t0,\t0,\t0,\tA('m'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  51 - ,<\t*/\t',',\t'<',\t0,\t0,\t0,\t0,\t0,\t0,\tA(','),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  52 - .>\t*/\t'.',\t'>',\t0,\t0,\t0,\t0,\t0,\t0,\tA('.'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  53 - /?\t*/\tSLASH,\t'?',\t0,\t0,\tBS,\t0,\t0,\t0,\tA('/'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  54 - RSHF\t*/\tRSHIFT,\tRSHIFT,\tRSHIFT,\tRSHIFT,\tRSHIFT,\t0,\t0,\t0,\tRSHIFT,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  55 - *\t*/\tASTSK,\tASTSK,\tASTSK,\tASTSK,\tASTSK,\t0,\t0,\t0,\tASTSK,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  56 - ALT\t*/\tALT,\tALT,\tALT,\tALT,\tALT,\t0,\t0,\t0,\tALT,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  57 - SPC\t*/\t' ',\t' ',\t0,\t0,\t0,\t0,\t0,\t0,\tA(' '),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  58 - CAPS\t*/\tCAPS,\tCAPS,\tCAPS,\tCAPS,\tCAPS,\t0,\t0,\t0,\tCAPS,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  59 - F1\t*/\tF1,\tSF1,\t0,\t0,\tF1,\t0,\t0,\t0,\tAF1,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  60 - F2\t*/\tF2,\tSF2,\t0,\t0,\tF2,\t0,\t0,\t0,\tAF2,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  61 - F3\t*/\tF3,\tSF3,\t0,\t0,\tF3,\t0,\t0,\t0,\tAF3,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  62 - F4\t*/\tF4,\tSF4,\t0,\t0,\tF4,\t0,\t0,\t0,\tAF4,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  63 - F5\t*/\tF5,\tSF5,\t0,\t0,\tF5,\t0,\t0,\t0,\tAF5,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  64 - F6\t*/\tF6,\tSF6,\t0,\t0,\tF6,\t0,\t0,\t0,\tAF6,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  65 - F7\t*/\tF7,\tSF7,\t0,\t0,\tF7,\t0,\t0,\t0,\tAF7,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  66 - F8\t*/\tF8,\tSF8,\t0,\t0,\tF8,\t0,\t0,\t0,\tAF8,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  67 - F9\t*/\tF9,\tSF9,\t0,\t0,\tF9,\t0,\t0,\t0,\tAF9,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  68 - F10\t*/\tF10,\tSF10,\t0,\t0,\tF10,\t0,\t0,\t0,\tAF10,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  69 - NUMS\t*/\tNUMS,\tNUMS,\tNUMS,\tNUMS,\tNUMS,\t0,\t0,\t0,\tNUMS,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  70 - SCRL\t*/\tSCRL,\tSCRL3,\tSCRL2,\t0,\tSCRL4,\t0,\t0,\t0,\tSCRL,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  71 - HOME/7\t*/\tHOME,\tHOME,\tHOME,\tHOME,\tHOME,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  72 - UP  /8\t*/\tUP,\tUP,\tUP,\tUP,\tUP,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  73 - PGUP/9\t*/\tPGUP,\tPGUP,\tPGUP,\tPGUP,\tPGUP,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  74 - MINUS\t*/\tMINUS,\tMINUS,\tMINUS,\tMINUS,\tMINUS,\t0,\t0,\t0,\tMINUS,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  75 - LEFT/4\t*/\tLEFT,\tLEFT,\tLEFT,\tLEFT,\tLEFT,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  76 - MID /5\t*/\tMID,\tMID,\tMID,\tMID,\tMID,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  77 - RIGH/6\t*/\tRIGHT,\tRIGHT,\tRIGHT,\tRIGHT,\tRIGHT,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  78 - PLUS\t*/\tPLUS,\tPLUS,\tPLUS,\tPLUS,\tPLUS,\t0,\t0,\t0,\tPLUS,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  79 - END /1\t*/\tEND,\tEND,\tEND,\tEND,\tEND,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  80 - DOWN/2\t*/\tDOWN,\tDOWN,\tDOWN,\tDOWN,\tDOWN,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  81 - PGDN/3\t*/\tPGDN,\tPGDN,\tPGDN,\tPGDN,\tPGDN,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  82 - INS /0\t*/\tINS,\tINS,\tINS,\tINS,\tINS,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  83 - DEL /.\t*/\tDEL,\tDEL,\tDEL,\tDEL,\tDEL,\t0,\t0,\t0,\tDEL,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  84 - SYSRQ\t*/\tSYSRQ,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\tSYSRQ,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  85 -\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  86 - <>\t*/\t'<',\t'>',\t'|',\t0,\t0,\t0,\t0,\t0,\tA('<'),\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  87 - F11\t*/\tSF1,\tSF1,\t0,\t0,\tF11,\t0,\t0,\t0,\tAF11,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  88 - F12\t*/\tSF2,\tSF2,\t0,\t0,\tF12,\t0,\t0,\t0,\tAF12,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  89 -\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  90 -\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  91 -\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  92 -\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  93 -\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  94 -\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  95 -\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  96 - E0ENTER*/\tE0ENTER,E0ENTER,E0ENTER,E0ENTER,E0ENTER,0,\t0,\t0,\tE0ENTER,0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  97 - RCTRL\t*/\tRCTRL,\tRCTRL,\tRCTRL,\tRCTRL,\tRCTRL,\t0,\t0,\t0,\tRCTRL,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  98 - E0SLASH*/\tE0SLASH,E0SLASH,E0SLASH,E0SLASH,E0SLASH,0,\t0,\t0,\tE0SLASH,0,\t0,\t0,\t0,\t0,\t0,\t0,\n/*  99 -\t*/\t0,\t0,\t0,\t0,\tC('\\\\'),0,\t0,\t0,\tC('\\\\'),0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 100 - ALTGR\t*/\tALTGR,\tALTGR,\tALTGR,\tALTGR,\tALTGR,\t0,\t0,\t0,\tALTGR,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 101 -\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 102 - E0HOME\t*/\tE0HOME,\tE0HOME,\tE0HOME,\tE0HOME,\tE0HOME,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 103 - E0UP  \t*/\tE0UP,\tE0UP,\tE0UP,\tE0UP,\tE0UP,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 104 - E0PGUP\t*/\tE0PGUP,\tE0PGUP,\tE0PGUP,\tE0PGUP,\tE0PGUP,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 105 - E0LEFT\t*/\tE0LEFT,\tE0LEFT,\tE0LEFT,\tE0LEFT,\tE0LEFT,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 106 - E0RIGHT*/\tE0RIGHT,E0RIGHT,E0RIGHT,E0RIGHT,E0RIGHT,0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 107 - E0END\t*/\tE0END,\tE0END,\tE0END,\tE0END,\tE0END,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 108 - E0DOWN\t*/\tE0DOWN,\tE0DOWN,\tE0DOWN,\tE0DOWN,\tE0DOWN,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 109 - E0PGDN\t*/\tE0PGDN,\tE0PGDN,\tE0PGDN,\tE0PGDN,\tE0PGDN,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 110 - E0INS\t*/\tE0INS,\tE0INS,\tE0INS,\tE0INS,\tE0INS,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 111 - E0DEL\t*/\tE0DEL,\tE0DEL,\tE0DEL,\tE0DEL,\tE0DEL,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 112 -\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 113 -\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 114 -\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 115 -\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 116 -\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 117 -\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 118 -\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 119 -\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 120 -\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 121 -\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 122 -\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 123 -\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 124 -\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 125 -\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 126 -\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n/* 127 -\t*/\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\t0,\n};\n"
  },
  {
    "path": "drivers/char/fb.c",
    "content": "/*\n * fiwix/drivers/char/fb.c\n *\n * Copyright 2021-2022, Jordi Sanfeliu. All rights reserved.\n * Portions Copyright 2024, Greg Haerr.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/fb.h>\n#include <fiwix/devices.h>\n#include <fiwix/fs.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n#include <fiwix/fb.h>\n#include <fiwix/pci.h>\n#include <fiwix/mm.h>\n#include <fiwix/mman.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/bios.h>\n\n#define IO_FB_XRES\t2\t/* TODO(ghaerr): to be removed shortly */\n#define IO_FB_YRES\t3\n\nstatic struct fs_operations fb_driver_fsop = {\n\t0,\n\t0,\n\n\tfb_open,\n\tfb_close,\n\tfb_read,\n\tfb_write,\n\tfb_ioctl,\n\tfb_llseek,\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tfb_mmap,\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lockup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nstatic struct device fb_device = {\n\t\"fb\",\n\tFB_MAJOR,\n\t{ 0, 0, 0, 0, 0, 0, 0, 0 },\n\tNULL,\n\tNULL,\n\t&fb_driver_fsop,\n\tNULL,\n\tNULL,\n\tNULL\n};\n\nint fb_open(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\nint fb_close(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\nint fb_read(struct inode *i, struct fd *f, char *buffer, __size_t count)\n{\n\tunsigned int addr;\n\n\tif(f->offset >= video.memsize) {\n\t\treturn 0;\n\t}\n\n\taddr = (unsigned int)video.address + f->offset;\n\tcount = MIN(count, video.memsize - f->offset);\n\tmemcpy_b(buffer, (void *)addr, count);\n\tf->offset += count;\n\treturn count;\n}\n\nint fb_write(struct inode *i, struct fd *f, const char *buffer, __size_t count)\n{\n\tunsigned int addr;\n\n\tif(f->offset >= video.memsize) {\n\t\treturn -ENOSPC;\n\t}\n\n\taddr = (unsigned int)video.address + f->offset;\n\tcount = MIN(count, video.memsize - f->offset);\n\tmemcpy_b((void *)addr, buffer, count);\n\tf->offset += count;\n\treturn count;\n}\n\nint fb_mmap(struct inode *i, struct vma *vma)\n{\n\tunsigned int fbaddr, addr;\n\n\tfbaddr = (unsigned int)video.address;\n\tfor (addr = vma->start; addr < vma->end; addr += 4096) {\n\t\t/* map framebuffer physaddr into user space without page allocations */\n\t\tmap_page_flags(current, addr, fbaddr, PROT_READ|PROT_WRITE, PAGE_NOALLOC);\n\t\tfbaddr += 4096;\n\t}\n\treturn 0;\n}\n\nint fb_ioctl(struct inode *i, struct fd *f, int cmd, unsigned int arg)\n{\n\tswitch (cmd) {\n\t\tcase IO_FB_XRES:\n\t\t\treturn video.fb_width;\n\t\tcase IO_FB_YRES:\n\t\t\treturn video.fb_height;\n\t\tdefault:\n\t\t\treturn -EINVAL;\n\t}\n}\n\n__loff_t fb_llseek(struct inode *i, __loff_t offset)\n{\n\treturn offset;\n}\n\nvoid fb_init(void)\n{\n\tunsigned int limit, from;\n\n\tSET_MINOR(fb_device.minors, FB_MINOR);\n\tlimit = (unsigned int)video.address + video.memsize - 1;\n\n\t/*\n\t * Frame buffer memory must be marked as reserved because its memory\n\t * range (e.g: 0xFD000000-0xFDFFFFFF) might conflict with the physical\n\t * memory below 1GB (e.g: 0x3D000000-0x3DFFFFFF + PAGE_OFFSET).\n\t */\n\tfrom = (unsigned int)video.address - PAGE_OFFSET;\n\tbios_map_reserve(from, from + video.memsize);\n\n\tprintk(\"fb0       0x%08x-0x%08x\\ttype=%s %x.%x resolution=%dx%dx%d size=%dMB\\n\",\n\t\tvideo.address,\n\t\tlimit,\n\t\tvideo.signature,\n\t\tvideo.fb_version >> 8,\n\t\tvideo.fb_version & 0xFF,\n\t\tvideo.fb_width,\n\t\tvideo.fb_height,\n\t\tvideo.fb_bpp,\n\t\tvideo.memsize / 1024 / 1024\n\t);\n#ifdef CONFIG_PCI\n\tif(video.pci_dev) {\n\t\tpci_show_desc(video.pci_dev);\n\t}\n#endif /* CONFIG_PCI */\n\tif(register_device(CHR_DEV, &fb_device)) {\n\t\tprintk(\"ERROR: %s(): unable to register fb device.\\n\", __FUNCTION__);\n\t\treturn;\n\t}\n}\n"
  },
  {
    "path": "drivers/char/keyboard.c",
    "content": "/*\n * fiwix/drivers/char/keyboard.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/limits.h>\n#include <fiwix/ps2.h>\n#include <fiwix/keyboard.h>\n#include <fiwix/reboot.h>\n#include <fiwix/console.h>\n#include <fiwix/vgacon.h>\n#include <fiwix/pic.h>\n#include <fiwix/irq.h>\n#include <fiwix/signal.h>\n#include <fiwix/process.h>\n#include <fiwix/sleep.h>\n#include <fiwix/kd.h>\n#include <fiwix/sysrq.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#define DELAY_250\t0x00\t/* typematic delay at 250ms (default) */\n#define DELAY_500\t0x40\t/* typematic delay at 500ms */\n#define DELAY_750\t0x80\t/* typematic delay at 750ms */\n#define DELAY_1000\t0xC0\t/* typematic delay at 1000ms */\n#define RATE_30\t\t0x00\t/* typematic rate at 30.0 reports/sec (default) */\n\n#define EXTKEY\t\t0xE0\t/* extended key (AltGr, Ctrl-Print, etc.) */\n\n__key_t *keymap_line;\n\nstatic unsigned char e0_keys[128] = {\n\t0, 0, 0, 0, 0, 0, 0, 0,\t\t\t\t/* 0x00-0x07 */\n\t0, 0, 0, 0, 0, 0, 0, 0,\t\t\t\t/* 0x08-0x0F */\n\t0, 0, 0, 0, 0, 0, 0, 0,\t\t\t\t/* 0x10-0x17 */\n\t0, 0, 0, 0, E0ENTER, RCTRL, 0, 0,\t\t/* 0x18-0x1F */\n\t0, 0, 0, 0, 0, 0, 0, 0,\t\t\t\t/* 0x20-0x27 */\n\t0, 0, 0, 0, 0, 0, 0, 0,\t\t\t\t/* 0x28-0x2F */\n\t0, 0, 0, 0, 0, E0SLASH, 0, 0,\t\t\t/* 0x30-0x37 */\n\tALTGR, 0, 0, 0, 0, 0, 0, 0,\t\t\t/* 0x38-0x3F */\n\t0, 0, 0, 0, 0, 0, 0, E0HOME,\t\t\t/* 0x40-0x47 */\n\tE0UP, E0PGUP, 0, E0LEFT, 0, E0RIGHT, 0, E0END,\t/* 0x48-0x4F */\n\tE0DOWN, E0PGDN, E0INS, E0DEL, 0, 0, 0, 0,\t/* 0x50-0x57 */\n\t0, 0, 0, 0, 0, 0, 0, 0,\t\t\t\t/* 0x58-0x5f */\n\t0, 0, 0, 0, 0, 0, 0, 0,\t\t\t\t/* 0x60-0x67 */\n\t0, 0, 0, 0, 0, 0, 0, 0,\t\t\t\t/* 0x68-0x6F */\n\t0, 0, 0, 0, 0, 0, 0, 0,\t\t\t\t/* 0x70-0x77 */\n\t0, 0, 0, 0, 0, 0, 0, 0\t\t\t\t/* 0x78-0x7F */\n};\n\nstatic unsigned char leds = 0;\nstatic unsigned char shift = 0;\nstatic unsigned char altgr = 0;\nstatic unsigned char ctrl = 0;\nstatic unsigned char alt = 0;\nstatic unsigned char extkey = 0;\nstatic unsigned char deadkey = 0;\nstatic unsigned char altsysrq = 0;\nstatic int sysrq_op = 0;\nstatic unsigned char kb_identify[2] = {0, 0};\nstatic unsigned char is_ps2 = 0;\nstatic unsigned char orig_scan_set = 0;\nvolatile unsigned char ack = 0;\n\nstatic char do_switch_console = -1;\nstatic unsigned char do_buf_scroll = 0;\nstatic unsigned char do_setleds = 0;\nstatic unsigned char do_tty_stop = 0;\nstatic unsigned char do_tty_start = 0;\nstatic unsigned char do_sysrq = 0;\n\nchar ctrl_alt_del = 1;\nchar any_key_to_reboot = 0;\n\nstatic struct bh keyboard_bh = { 0, &irq_keyboard_bh, NULL };\nstatic struct interrupt irq_config_keyboard = { 0, \"keyboard\", &irq_keyboard, NULL };\n\nstruct diacritic *diacr;\nstatic char *diacr_chars = \"`'^~\\\"\";\nstruct diacritic grave_table[NR_DIACR] = {\n\t{ 'A', '\\300' },\n\t{ 'E', '\\310' },\n\t{ 'I', '\\314' },\n\t{ 'O', '\\322' },\n\t{ 'U', '\\331' },\n\t{ 'a', '\\340' },\n\t{ 'e', '\\350' },\n\t{ 'i', '\\354' },\n\t{ 'o', '\\362' },\n\t{ 'u', '\\371' },\n};\nstruct diacritic acute_table[NR_DIACR] = {\n\t{ 'A', '\\301' },\n\t{ 'E', '\\311' },\n\t{ 'I', '\\315' },\n\t{ 'O', '\\323' },\n\t{ 'U', '\\332' },\n\t{ 'a', '\\341' },\n\t{ 'e', '\\351' },\n\t{ 'i', '\\355' },\n\t{ 'o', '\\363' },\n\t{ 'u', '\\372' },\n};\nstruct diacritic circm_table[NR_DIACR] = {\n\t{ 'A', '\\302' },\n\t{ 'E', '\\312' },\n\t{ 'I', '\\316' },\n\t{ 'O', '\\324' },\n\t{ 'U', '\\333' },\n\t{ 'a', '\\342' },\n\t{ 'e', '\\352' },\n\t{ 'i', '\\356' },\n\t{ 'o', '\\364' },\n\t{ 'u', '\\373' },\n};\nstruct diacritic tilde_table[NR_DIACR] = {\n\t{ 'A', '\\303' },\n\t{ 'N', '\\321' },\n\t{ 'O', '\\325' },\n\t{ 'a', '\\343' },\n\t{ 'n', '\\361' },\n\t{ 'o', '\\365' },\n};\nstruct diacritic diere_table[NR_DIACR] = {\n\t{ 'A', '\\304' },\n\t{ 'E', '\\313' },\n\t{ 'I', '\\317' },\n\t{ 'O', '\\326' },\n\t{ 'U', '\\334' },\n\t{ 'a', '\\344' },\n\t{ 'e', '\\353' },\n\t{ 'i', '\\357' },\n\t{ 'o', '\\366' },\n\t{ 'u', '\\374' },\n};\n\nstatic char *pad_chars = \"0123456789+-*/\\015,.\";\n\nstatic char *pad_seq[] = {\n\t\"\\033[2~\",\t/* INS */\n\t\"\\033[4~\",\t/* END */\n\t\"\\033[B\" ,\t/* DOWN */\n\t\"\\033[6~\",\t/* PGDN */\n\t\"\\033[D\" ,\t/* LEFT */\n\t\"\\033[G\" ,\t/* MID */\n\t\"\\033[C\" ,\t/* RIGHT */\n\t\"\\033[1~\",\t/* HOME */\n\t\"\\033[A\" ,\t/* UP */\n\t\"\\033[5~\",\t/* PGUP */\n\t\"+\",\t\t/* PLUS */\n\t\"-\",\t\t/* MINUS */\n\t\"*\",\t\t/* ASTERISK */\n\t\"/\",\t\t/* SLASH */\n\t\"'\\n'\",\t\t/* ENTER */\n\t\",\",\t\t/* COMMA */\n\t\"\\033[3~\",\t/* DEL */\n};\n\nstatic char *fn_seq[] = {\n\t\"\\033[[A\",\t/* F1 */\n\t\"\\033[[B\",\t/* F2 */\n\t\"\\033[[C\",\t/* F3 */\n\t\"\\033[[D\",\t/* F4 */\n\t\"\\033[[E\",\t/* F5 */\n\t\"\\033[17~\",\t/* F6 */\n\t\"\\033[18~\",\t/* F7 */\n\t\"\\033[19~\",\t/* F8 */\n\t\"\\033[20~\",\t/* F9 */\n\t\"\\033[21~\",\t/* F10 */\n\t\"\\033[23~\",\t/* F11, SF1 */\n\t\"\\033[24~\",\t/* F12, SF2 */\n\t\"\\033[25~\",\t/* SF3 */\n\t\"\\033[26~\",\t/* SF4 */\n\t\"\\033[28~\",\t/* SF5 */\n\t\"\\033[29~\",\t/* SF6 */\n\t\"\\033[31~\",\t/* SF7 */\n\t\"\\033[32~\",\t/* SF8 */\n\t\"\\033[33~\",\t/* SF9 */\n\t\"\\033[34~\",\t/* SF10 */\n};\n\nstatic void keyboard_identify(void)\n{\n\tchar config;\n\n\t/* disable */\n\tps2_write(PS2_DATA, PS2_KB_DISABLE);\n\tif(ps2_wait_ack()) {\n\t\tprintk(\"WARNING: %s(): ACK not received on disable command!\\n\", __FUNCTION__);\n\t} else {\n\t\tis_ps2++;\n\t}\n\n\t/* identify */\n\tps2_write(PS2_DATA, PS2_DEV_IDENTIFY);\n\tif(ps2_wait_ack()) {\n\t\tprintk(\"WARNING: %s(): ACK not received on identify command!\\n\", __FUNCTION__);\n\t} else {\n\t\tis_ps2++;\n\t}\n\tkb_identify[0] = ps2_read(PS2_DATA);\n\tkb_identify[1] = ps2_read(PS2_DATA);\n\n\t/* get scan code */\n\tps2_write(PS2_COMMAND, PS2_CMD_RECV_CONFIG);\n\tconfig = ps2_read(PS2_DATA);\t/* save state */\n\tps2_write(PS2_COMMAND, PS2_CMD_SEND_CONFIG);\n\tps2_write(PS2_DATA, config & ~0x40);\t/* unset translation */\n\tps2_write(PS2_DATA, PS2_KB_GETSETSCAN);\n\tif(ps2_wait_ack()) {\n\t\tprintk(\"WARNING: %s(): ACK not received on get scan code command!\\n\", __FUNCTION__);\n\t}\n\tps2_write(PS2_DATA, 0);\n\tif(ps2_wait_ack()) {\n\t\tprintk(\"WARNING: %s(): ACK not received on get scan code command!\\n\", __FUNCTION__);\n\t}\n\torig_scan_set = ps2_read(PS2_DATA);\n\tif(orig_scan_set != 2) {\n\t\tps2_write(PS2_DATA, PS2_KB_GETSETSCAN);\n\t\tps2_write(PS2_DATA, 2);\n\t\tif(ps2_wait_ack()) {\n\t\t\tprintk(\"WARNING: %s(): ACK not received on set scan code command!\\n\", __FUNCTION__);\n\t\t}\n\t}\n\tps2_write(PS2_COMMAND, PS2_CMD_SEND_CONFIG);\n\tps2_write(PS2_DATA, config);\t/* restore state */\n\n\t/* enable */\n\tps2_write(PS2_DATA, PS2_DEV_ENABLE);\n\tif(ps2_wait_ack()) {\n\t\tprintk(\"WARNING: %s(): ACK not received on enable command!\\n\", __FUNCTION__);\n\t}\n\tps2_clear_buffer();\n}\n\nstatic void putc(struct tty *tty, unsigned char ch)\n{\n\tif(tty->count) {\n\t\tif(charq_putchar(&tty->read_q, ch) < 0) {\n\t\t\tif(tty->termios.c_iflag & IMAXBEL) {\n\t\t\t\tvconsole_beep();\n\t\t\t}\n\t\t}\n\t}\n}\n\nstatic void puts(struct tty *tty, char *seq)\n{\n\tchar ch;\n\n\tif(tty->count) {\n\t\twhile((ch = *(seq++))) {\n\t\t\tputc(tty, ch);\n\t\t}\n\t}\n}\n\nvoid set_leds(unsigned char led_status)\n{\n\tps2_write(PS2_DATA, PS2_KB_SETLED);\n\tps2_wait_ack();\n\n\tps2_write(PS2_DATA, led_status);\n\tps2_wait_ack();\n}\n\nvoid irq_keyboard(int num, struct sigcontext *sc)\n{\n\t__key_t key, type;\n\tunsigned char scode, mod;\n\tstruct tty *tty;\n\tstruct vconsole *vc;\n\tunsigned char c;\n\tint n;\n\n\ttty = get_tty(MKDEV(VCONSOLES_MAJOR, current_cons));\n\tvc = (struct vconsole *)tty->driver_data;\n\n\tscode = inport_b(PS2_DATA);\n\n\t/* keyboard controller said 'acknowledge!' */\n\tif(scode == DEV_ACK) {\n\t\tack = 1;\n\t\treturn;\n\t}\n\n\tkeyboard_bh.flags |= BH_ACTIVE;\n\n\t/* if in pure raw mode just queue the scan code and return */\n\tif(tty->kbd.mode == K_RAW) {\n\t\tputc(tty, scode);\n\t\treturn;\n\t}\n\n\tif(scode == EXTKEY) {\n\t\textkey = 1;\n\t\treturn;\n\t}\n\t\n\tif(extkey) {\n\t\tkey = e0_keys[scode & 0x7F];\n\t} else {\n\t\tkey = scode & 0x7F;\n\t}\n\n\tif(tty->kbd.mode == K_MEDIUMRAW) {\n\t\tputc(tty, key | (scode & 0x80));\n\t\textkey = 0;\n\t\treturn;\n\t}\n\n\tkey = keymap[NR_MODIFIERS * (scode & 0x7F)];\n\n\t/* bit 7 enabled means a key has been released */\n\tif(scode & NR_SCODES) {\n\t\tswitch(key) {\n\t\t\tcase CTRL:\n\t\t\tcase LCTRL:\n\t\t\tcase RCTRL:\n\t\t\t\tctrl = 0;\n\t\t\t\tbreak;\n\t\t\tcase ALT:\n\t\t\t\tif(!extkey) {\n\t\t\t\t\talt = 0;\n\t\t\t\t\taltsysrq = 0;\n\t\t\t\t} else {\n\t\t\t\t\taltgr = 0;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase SHIFT:\n\t\t\tcase LSHIFT:\n\t\t\tcase RSHIFT:\n\t\t\t\tif(!extkey) {\n\t\t\t\t\tshift = 0;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase CAPS:\n\t\t\tcase NUMS:\n\t\t\tcase SCRL:\n\t\t\t\tleds = 0;\n\t\t\t\tbreak;\n\t\t}\n\t\textkey = 0;\n\t\treturn;\n\t}\n\n\tswitch(key) {\n\t\tcase CAPS:\n\t\t\tif(!leds) {\n\t\t\t\tvc->led_status ^= CAPSBIT;\n\t\t\t\tvc->capslock = !vc->capslock;\n\t\t\t\tdo_setleds = 1;\n\t\t\t}\n\t\t\tleds = 1;\n\t\t\treturn;\n\t\tcase NUMS:\n\t\t\tif(!leds) {\n\t\t\t\tvc->led_status ^= NUMSBIT;\n\t\t\t\tvc->numlock = !vc->numlock;\n\t\t\t\tdo_setleds = 1;\n\t\t\t}\n\t\t\tleds = 1;\n\t\t\treturn;\n\t\tcase SCRL:\n\t\t\tif(!leds) {\n\t\t\t\tif(vc->scrlock) {\n\t\t\t\t\tdo_tty_start = 1;\n\t\t\t\t} else {\n\t\t\t\t\tdo_tty_stop = 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\tleds = 1;\n\t\t\treturn;\n\t\tcase CTRL:\n\t\tcase LCTRL:\n\t\tcase RCTRL:\n\t\t\tctrl = 1;\n\t\t\treturn;\n\t\tcase ALT:\n\t\t\tif(!extkey) {\n\t\t\t\talt = 1;\n\t\t\t} else {\n\t\t\t\taltgr = 1;\n\t\t\t}\n\t\t\treturn;\n\t\tcase SHIFT:\n\t\tcase LSHIFT:\n\t\tcase RSHIFT:\n\t\t\tshift = 1;\n\t\t\textkey = 0;\n\t\t\treturn;\n\t}\n\n\tif(ctrl && alt && key == DEL) {\n\t\tif(ctrl_alt_del) {\n\t\t\treboot();\n\t\t} else {\n\t\t\tsend_sig(&proc_table[INIT], SIGINT);\n\t\t}\n\t\treturn;\n\t}\n\n\tkeymap_line = &keymap[(scode & 0x7F) * NR_MODIFIERS];\n\tmod = 0;\n\n\tif(vc->capslock && (keymap_line[MOD_BASE] & LETTER_KEYS)) {\n\t\tmod = !vc->capslock ? shift : vc->capslock - shift;\n\t} else {\n\t\tif(shift && !extkey) {\n\t\t\tmod = 1;\n\t\t}\n\t}\n\tif(altgr) {\n\t\tmod = 2;\n\t}\n\tif(ctrl) {\n\t\tmod = 4;\n\t}\n\tif(alt) {\n\t\tmod = 8;\n\t}\n\n\tkey = keymap_line[mod];\n\n\tif(key >= AF1 && key <= AF12) {\n\t\tdo_switch_console = key - CONS_KEYS;\n\t\treturn;\n\t}\n\n\tif(shift && (key == PGUP)) {\n\t\tdo_buf_scroll = SCROLL_UP;\n\t\treturn;\n\t}\n\n\tif(shift && (key == PGDN)) {\n\t\tdo_buf_scroll = SCROLL_DOWN;\n\t\treturn;\n\t}\n\n\tif(extkey && (scode == SLASH_NPAD)) {\n\t\tkey = SLASH;\n\t}\n\n\tif(any_key_to_reboot) {\n\t\treboot();\n\t}\n\n\n\ttype = key & 0xFF00;\n\tc = key & 0xFF;\n\n\tif(altsysrq) {\n\t\t/* treat 0-9 and a-z keys as normal */\n\t\ttype &= ~META_KEYS;\n\t}\n\n\tswitch(type) {\n\t\tcase FN_KEYS:\n\t\t\tif(c > sizeof(fn_seq) / sizeof(char *)) {\n\t\t\t\tprintk(\"WARNING: %s(): unrecognized function key.\\n\", __FUNCTION__);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tputs(tty, fn_seq[c]);\n\t\t\tbreak;\n\n\t\tcase SPEC_KEYS:\n\t\t\tswitch(key) {\n\t\t\t\tcase CR:\n\t\t\t\t\tputc(tty, C('M'));\n\t\t\t\t\tbreak;\n\t\t\t\tcase SYSRQ:\n\t\t\t\t\taltsysrq = 1;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase PAD_KEYS:\n\t\t\tif(!vc->numlock) {\n\t\t\t\tputs(tty, pad_seq[c]);\n\t\t\t} else {\n\t\t\t\tputc(tty, pad_chars[c]);\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase DEAD_KEYS:\n\t\t\tif(!deadkey) {\n\t\t\t\tswitch(c) {\n\t\t\t\t\tcase GRAVE ^ DEAD_KEYS:\n\t\t\t\t\t\tdeadkey = 1;\n\t\t\t\t\t\tdiacr = grave_table;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase ACUTE ^ DEAD_KEYS:\n\t\t\t\t\t\tdeadkey = 2;\n\t\t\t\t\t\tdiacr = acute_table;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase CIRCM ^ DEAD_KEYS:\n\t\t\t\t\t\tdeadkey = 3;\n\t\t\t\t\t\tdiacr = circm_table;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase TILDE ^ DEAD_KEYS:\n\t\t\t\t\t\tdeadkey = 4;\n\t\t\t\t\t\tdiacr = tilde_table;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase DIERE ^ DEAD_KEYS:\n\t\t\t\t\t\tdeadkey = 5;\n\t\t\t\t\t\tdiacr = diere_table;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tc = diacr_chars[c];\n\t\t\tdeadkey = 0;\n\t\t\tputc(tty, c);\n\n\t\t\tbreak;\n\n\t\tcase META_KEYS:\n\t\t\tputc(tty, '\\033');\n\t\t\tputc(tty, c);\n\t\t\tbreak;\n\n\t\tcase LETTER_KEYS:\n\t\t\tif(deadkey) {\n\t\t\t\tfor(n = 0; n < NR_DIACR; n++) {\n\t\t\t\t\tif(diacr[n].letter == c) {\n\t\t\t\t\t\tc = diacr[n].code;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tputc(tty, c);\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tif(altsysrq) {\n\t\t\t\tswitch(c) {\n\t\t\t\t\tcase 'l':\n\t\t\t\t\t\tsysrq_op = SYSRQ_STACK;\n\t\t\t\t\t\tdo_sysrq = 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'm':\n\t\t\t\t\t\tsysrq_op = SYSRQ_MEMORY;\n\t\t\t\t\t\tdo_sysrq = 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 't':\n\t\t\t\t\t\tsysrq_op = SYSRQ_TASKS;\n\t\t\t\t\t\tdo_sysrq = 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tsysrq_op = SYSRQ_UNDEF;\n\t\t\t\t\t\tdo_sysrq = 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif(deadkey && c == ' ') {\n\t\t\t\tc = diacr_chars[deadkey - 1];\n\t\t\t}\n\t\t\tputc(tty, c);\n\t\t\tbreak;\n\t}\n\n\tdeadkey = 0;\n}\n\nvoid irq_keyboard_bh(struct sigcontext *sc)\n{\n\tstruct tty *tty;\n\tstruct vconsole *vc;\n\tchar value;\n\n\ttty = get_tty(MKDEV(VCONSOLES_MAJOR, current_cons));\n\tvc = (struct vconsole *)tty->driver_data;\n\n\tvideo.screen_on(vc);\n\n\tif(do_switch_console >= 0) {\n\t\tvalue = do_switch_console;\n\t\tdo_switch_console = -1;\n\t\tvconsole_select(value);\n\t}\n\n\tif(do_buf_scroll) {\n\t\tvalue = do_buf_scroll;\n\t\tdo_buf_scroll = 0;\n\t\tvideo.buf_scroll(vc, value);\n\t}\n\n\tif(do_setleds) {\n\t\tdo_setleds = 0;\n\t\tset_leds(vc->led_status);\n\t}\n\n\tif(do_tty_start) {\n\t\tdo_tty_start = do_tty_stop = 0;\n\t\ttty->start(tty);\n\t}\n\n\tif(do_tty_stop) {\n\t\tdo_tty_start = do_tty_stop = 0;\n\t\ttty->stop(tty);\n\t}\n\n\tif(do_sysrq) {\n\t\tdo_sysrq = 0;\n\t\tsysrq(sysrq_op);\n\t}\n\n\tfor(tty = tty_table; tty; tty = tty->next) {\n\t\tif(MAJOR(tty->dev) == VCONSOLES_MAJOR && MINOR(tty->dev) < NR_VCONSOLES) {\n\t\t\tif(!tty->read_q.count) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif(tty->kbd.mode == K_RAW || tty->kbd.mode == K_MEDIUMRAW) {\n\t\t\t\twakeup(&tty->read_q);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif(!can_lock_area(AREA_TTY_READ)) {\n\t\t\t\tkeyboard_bh.flags |= BH_ACTIVE;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\ttty->input(tty);\n\t\t\tunlock_area(AREA_TTY_READ);\n\t\t}\n\t}\n}\n\nvoid keyboard_init(void)\n{\n\tstruct tty *tty;\n\tstruct vconsole *vc;\n\tint errno;\n\n\ttty = get_tty(MKDEV(VCONSOLES_MAJOR, current_cons));\n\tvc = (struct vconsole *)tty->driver_data;\n\tvideo.screen_on(vc);\n\tvideo.cursor_blink((unsigned int)vc);\n\n\tadd_bh(&keyboard_bh);\n\tif(!register_irq(KEYBOARD_IRQ, &irq_config_keyboard)) {\n\t\tenable_irq(KEYBOARD_IRQ);\n\t}\n\n\t/* reset device */\n\tps2_write(PS2_DATA, PS2_DEV_RESET);\n\tif(ps2_wait_ack()) {\n\t\tprintk(\"WARNING: %s(): ACK not received on reset command!\\n\", __FUNCTION__);\n\t}\n\tif((errno = ps2_read(PS2_DATA)) != DEV_RESET_OK) {\n\t\t/* some keyboards return an ID byte before 0xAA */\n\t\tif((errno = ps2_read(PS2_DATA)) != DEV_RESET_OK) {\n\t\t\tprintk(\"WARNING: %s(): keyboard returned 0x%x on reset (1).\\n\", __FUNCTION__, errno);\n\t\t}\n\t}\n\n\tps2_clear_buffer();\n\tkeyboard_identify();\n\tprintk(\"keyboard  0x%04x-0x%04x     %d\", 0x60, 0x64, KEYBOARD_IRQ);\n\tprintk(\"\\ttype=%s %s\", kb_identify[0] == 0xAB ? \"MF2\" : \"unknown\", is_ps2 ? \"PS/2\" : \"\");\n\tprintk(\" %s\", (kb_identify[1] == 0x41 || kb_identify[1] == 0xC1) ? \"translated\" : \"\");\n\tprintk(\" scan set 2\");\n\tif(orig_scan_set != 2) {\n\t\tprintk(\" (was %d)\", orig_scan_set);\n\t}\n\tprintk(\"\\n\");\n\n\tps2_write(PS2_DATA, PS2_DEV_RATE);\n\tps2_wait_ack();\n\tps2_write(PS2_DATA, DELAY_250 | RATE_30);\n\tps2_wait_ack();\n}\n"
  },
  {
    "path": "drivers/char/lp.c",
    "content": "/*\n * fiwix/drivers/char/lp.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/devices.h>\n#include <fiwix/fs.h>\n#include <fiwix/errno.h>\n#include <fiwix/lp.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstruct lp lp_table[LP_MINORS];\n\nstatic struct fs_operations lp_driver_fsop = {\n\t0,\n\t0,\n\n\tlp_open,\n\tlp_close,\n\tNULL,\t\t\t/* read */\n\tlp_write,\n\tNULL,\t\t\t/* ioctl */\n\tNULL,\t\t\t/* llseek */\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lockup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nstatic struct device lp_device = {\n\t\"lp\",\n\tLP_MAJOR,\n\t{ 0, 0, 0, 0, 0, 0, 0, 0 },\n\tNULL,\n\tNULL,\n\t&lp_driver_fsop,\n\tNULL,\n\tNULL,\n\tNULL\n};\n\nstruct lp lp_table[LP_MINORS] = {\n\t{ LP0_ADDR, LP0_ADDR + 1, LP0_ADDR + 2, 0 }\n};\n\nstatic void lp_delay(void)\n{\n\tint n;\n\n\tfor(n = 0; n < 10000; n++) {\n\t\tNOP();\n\t}\n}\n\nstatic int lp_ready(int minor)\n{\n\tint n;\n\n\tfor(n = 0; n < LP_RDY_RETR; n++) {\n\t\tif(inport_b(lp_table[minor].stat) & LP_STAT_BUS) {\n\t\t\tbreak;\n\t\t}\n\t\tlp_delay();\n\t}\n\tif(n == LP_RDY_RETR) {\n\t\treturn 0;\n\t}\n\treturn 1;\n}\n\nstatic int lp_probe(int minor)\n{\n\t/* first check */\n\toutport_b(lp_table[minor].data, 0x55);\n\tlp_delay();\n\tif(inport_b(lp_table[minor].data) != 0x55) {\n\t\treturn 1;\t\t/* did not retain data */\n\t}\n\n\t/* second check */\n\toutport_b(lp_table[minor].data, 0xAA);\n\tlp_delay();\n\tif(inport_b(lp_table[minor].data) != 0xAA) {\n\t\treturn 1;\t\t/* did not retain data */\n\t}\n\treturn 0;\n}\n\nstatic int lp_write_data(int minor, unsigned char c)\n{\n\tunsigned char ctrl;\n\n\tif(!lp_ready(minor)) {\n\t\treturn -EBUSY;\n\t}\n\toutport_b(lp_table[minor].data, c);\n\tctrl = inport_b(lp_table[minor].ctrl);\n\toutport_b(lp_table[minor].ctrl, ctrl | LP_CTRL_STR);\n\tlp_delay();\n\toutport_b(lp_table[minor].ctrl, ctrl);\n\tif(!lp_ready(minor)) {\n\t\treturn -EBUSY;\n\t}\n\treturn 1;\n}\n\nint lp_open(struct inode *i, struct fd *f)\n{\n\tint minor;\n\n\tminor = MINOR(i->rdev);\n\tif(!TEST_MINOR(lp_device.minors, minor)) {\n\t\treturn -ENXIO;\n\t}\n\tif(!(lp_table[minor].flags & LP_CTRL_SEL)) {\n\t\treturn -ENXIO;\n\t}\n\tif(lp_table[minor].flags & LP_STAT_BUS) {\n\t\treturn -EBUSY;\n\t}\n\tlp_table[minor].flags |= LP_STAT_BUS;\n\treturn 0;\n}\n\nint lp_close(struct inode *i, struct fd *f)\n{\n\tint minor;\n\n\tminor = MINOR(i->rdev);\n\tif(!TEST_MINOR(lp_device.minors, minor)) {\n\t\treturn -ENXIO;\n\t}\n\tlp_table[minor].flags &= ~LP_STAT_BUS;\n\treturn 0;\n}\n\nint lp_write(struct inode *i, struct fd *f, const char *buffer, __size_t count)\n{\n\tunsigned int n;\n\tint bytes_written, total_written;\n\tint minor;\n\n\tminor = MINOR(i->rdev);\n\tif(!TEST_MINOR(lp_device.minors, minor)) {\n\t\treturn -ENXIO;\n\t}\n\n\ttotal_written = 0;\n\tfor(n = 0; n < count; n++) {\n\t\tbytes_written = lp_write_data(minor, buffer[n]);\n\t\tif(bytes_written != 1) {\n\t\t\tbreak;\n\t\t}\n\t\ttotal_written += bytes_written;\n\t}\n\n\treturn total_written;\n}\n\nvoid lp_init(void)\n{\n\tint n;\n\tunsigned char ctrl;\n\n\tfor(n = 0; n < LP_MINORS; n++) {\n\t\tif(!lp_probe(n)) {\n\t\t\tctrl = inport_b(lp_table[n].ctrl);\n\t\t\tctrl &= ~LP_CTRL_AUT;\t/* disable auto LF */\n\t\t\tctrl |= LP_CTRL_INI;\t/* initialize */\n\t\t\tctrl |= LP_CTRL_SEL;\t/* select in */\n\t\t\tctrl &= ~LP_CTRL_IRQ;\t/* disable IRQ */\n\t\t\tctrl &= ~LP_CTRL_BID;\t/* disable bidirectional mode */\n\t\t\toutport_b(lp_table[n].ctrl, ctrl);\n\t\t\tlp_table[n].flags |= LP_CTRL_SEL;\n\t\t\tprintk(\"lp%d       0x%04x-0x%04x     -\\n\", n, lp_table[n].data, lp_table[n].data + 2);\n\t\t\tSET_MINOR(lp_device.minors, n);\n\t\t}\n\t}\n\n\tfor(n = 0; n < LP_MINORS; n++) {\n\t\tif(lp_table[n].flags & LP_CTRL_SEL) {\n\t\t\tif(register_device(CHR_DEV, &lp_device)) {\n\t\t\t\tprintk(\"WARNING: %s(): unable to register lp device.\\n\", __FUNCTION__);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "drivers/char/memdev.c",
    "content": "/*\n * fiwix/drivers/char/memdev.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/memdev.h>\n#include <fiwix/devices.h>\n#include <fiwix/fs.h>\n#include <fiwix/errno.h>\n#include <fiwix/mm.h>\n#include <fiwix/mman.h>\n#include <fiwix/bios.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstatic struct fs_operations mem_driver_fsop = {\n\t0,\n\t0,\n\n\tmem_open,\n\tmem_close,\n\tmem_read,\n\tmem_write,\n\tNULL,\t\t\t/* ioctl */\n\tmem_llseek,\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tmem_mmap,\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lockup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nstatic struct fs_operations kmem_driver_fsop = {\n\t0,\n\t0,\n\n\tkmem_open,\n\tkmem_close,\n\tkmem_read,\n\tkmem_write,\n\tNULL,\t\t\t/* ioctl */\n\tkmem_llseek,\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tmem_mmap,\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lockup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nstatic struct fs_operations null_driver_fsop = {\n\t0,\n\t0,\n\n\tnull_open,\n\tnull_close,\n\tnull_read,\n\tnull_write,\n\tNULL,\t\t\t/* ioctl */\n\tnull_llseek,\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lockup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nstatic struct fs_operations port_driver_fsop = {\n\t0,\n\t0,\n\n\tport_open,\n\tport_close,\n\tport_read,\n\tport_write,\n\tNULL,\t\t\t/* ioctl */\n\tport_llseek,\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lockup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nstatic struct fs_operations zero_driver_fsop = {\n\t0,\n\t0,\n\n\tzero_open,\n\tzero_close,\n\tzero_read,\n\tzero_write,\n\tNULL,\t\t\t/* ioctl */\n\tzero_llseek,\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lockup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nstatic struct fs_operations full_driver_fsop = {\n\t0,\n\t0,\n\n\tfull_open,\n\tfull_close,\n\tfull_read,\n\tfull_write,\n\tNULL,\t\t\t/* ioctl */\n\tfull_llseek,\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lockup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nstatic struct fs_operations urandom_driver_fsop = {\n\t0,\n\t0,\n\n\turandom_open,\n\turandom_close,\n\turandom_read,\n\turandom_write,\n\tNULL,\t\t\t/* ioctl */\n\turandom_llseek,\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lockup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nstatic struct fs_operations memdev_driver_fsop = {\n\t0,\n\t0,\n\n\tmemdev_open,\n\tNULL,\t\t\t/* close */\n\tNULL,\t\t\t/* read */\n\tNULL,\t\t\t/* write */\n\tNULL,\t\t\t/* ioctl */\n\tNULL,\t\t\t/* llseek */\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lockup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nstatic struct device memdev_device = {\n\t\"mem\",\n\tMEMDEV_MAJOR,\n\t{ 0, 0, 0, 0, 0, 0, 0, 0 },\n\tNULL,\n\tNULL,\n\t&memdev_driver_fsop,\n\tNULL,\n\tNULL,\n\tNULL\n};\n\nint mem_open(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\nint mem_close(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\nint mem_read(struct inode *i, struct fd *f, char *buffer, __size_t count)\n{\n\tunsigned int physical_memory;\n\n\tphysical_memory = (kstat.physical_pages << PAGE_SHIFT);\n\tif(f->offset >= physical_memory) {\n\t\treturn 0;\n\t}\n\tcount = MIN(count, physical_memory - f->offset);\n\tmemcpy_b(buffer, (void *)P2V((unsigned int)f->offset), count);\n\tf->offset += count;\n\treturn count;\n}\n\nint mem_write(struct inode *i, struct fd *f, const char *buffer, __size_t count)\n{\n\tunsigned int physical_memory;\n\n\tphysical_memory = (kstat.physical_pages << PAGE_SHIFT);\n\tif(f->offset >= physical_memory) {\n\t\treturn 0;\n\t}\n\tcount = MIN(count, physical_memory - f->offset);\n\tmemcpy_b((void *)P2V((unsigned int)f->offset), buffer, count);\n\tf->offset += count;\n\treturn count;\n}\n\n__loff_t mem_llseek(struct inode *i, __loff_t offset)\n{\n\treturn offset;\n}\n\nint kmem_open(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\nint kmem_close(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\nint kmem_read(struct inode *i, struct fd *f, char *buffer, __size_t count)\n{\n\tunsigned int physical_memory;\n\n\tphysical_memory = P2V((kstat.physical_pages << PAGE_SHIFT));\n\tif(P2V(f->offset + count) < physical_memory) {\n\t\tmemcpy_b(buffer, (void *)P2V((unsigned int)f->offset), count);\n\t\tf->offset += count;\n\t} else {\n\t\tcount = 0;\n\t}\n\treturn count;\n}\n\nint kmem_write(struct inode *i, struct fd *f, const char *buffer, __size_t count)\n{\n\tunsigned int physical_memory;\n\n\tphysical_memory = P2V((kstat.physical_pages << PAGE_SHIFT));\n\tif(P2V(f->offset + count) < physical_memory) {\n\t\tmemcpy_b((void *)P2V((unsigned int)f->offset), buffer, count);\n\t\tf->offset += count;\n\t} else {\n\t\tcount = 0;\n\t}\n\treturn count;\n}\n\n__loff_t kmem_llseek(struct inode *i, __loff_t offset)\n{\n\treturn offset;\n}\n\nint null_open(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\nint null_close(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\nint null_read(struct inode *i, struct fd *f, char *buffer, __size_t count)\n{\n\treturn 0;\n}\n\nint null_write(struct inode *i, struct fd *f, const char *buffer, __size_t count)\n{\n\treturn count;\n}\n\n__loff_t null_llseek(struct inode *i, __loff_t offset)\n{\n\treturn offset;\n}\n\nint port_open(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\nint port_close(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\nint port_read(struct inode *i, struct fd *f, char *buffer, __size_t count)\n{\n\tunsigned int n;\n\n\tif(f->offset >= 65535) {\n\t\treturn 0;\n\t}\n\tcount = MIN(count, 65536 - f->offset);\n\tfor(n = f->offset; n < (f->offset + count); n++, buffer++) {\n\t\t*buffer = inport_b(n);\n\t}\n\tf->offset += count;\n\treturn count;\n}\n\nint port_write(struct inode *i, struct fd *f, const char *buffer, __size_t count)\n{\n\tunsigned int n;\n\n\tif(f->offset >= 65535) {\n\t\treturn 0;\n\t}\n\tcount = MIN(count, 65536 - f->offset);\n\tfor(n = f->offset; n < (f->offset + count); n++, buffer++) {\n\t\toutport_b(n, *buffer);\n\t}\n\tf->offset += count;\n\treturn count;\n}\n\n__loff_t port_llseek(struct inode *i, __loff_t offset)\n{\n\treturn offset;\n}\n\nint zero_open(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\nint zero_close(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\nint zero_read(struct inode *i, struct fd *f, char *buffer, __size_t count)\n{\n\tmemset_b(buffer, 0, count);\n\treturn count;\n}\n\nint zero_write(struct inode *i, struct fd *f, const char *buffer, __size_t count)\n{\n\treturn count;\n}\n\n__loff_t zero_llseek(struct inode *i, __loff_t offset)\n\n{\n\treturn offset;\n}\n\nint full_open(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\nint full_close(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\nint full_read(struct inode *i, struct fd *f, char *buffer, __size_t count)\n{\n\tmemset_b(buffer, 0, count);\n\treturn count;\n}\n\nint full_write(struct inode *i, struct fd *f, const char *buffer, __size_t count)\n{\n\treturn -ENOSPC;\n}\n\n__loff_t full_llseek(struct inode *i, __loff_t offset)\n{\n\treturn offset;\n}\n\nint urandom_open(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\nint urandom_close(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\nint urandom_read(struct inode *i, struct fd *f, char *buffer, __size_t count)\n{\n\tint n;\n\n\tfor(n = 0; n < count; n++) {\n\t\tkstat.random_seed = kstat.random_seed * 1103515245 + 12345;\n\t\t*buffer = (char)(unsigned int)(kstat.random_seed / 65536) % 256;\n\t\tbuffer++;\n\t}\n\treturn count;\n}\n\nint urandom_write(struct inode *i, struct fd *f, const char *buffer, __size_t count)\n{\n\treturn count;\n}\n\n__loff_t urandom_llseek(struct inode *i, __loff_t offset)\n{\n\treturn offset;\n}\n\nint memdev_open(struct inode *i, struct fd *f)\n{\n\tunsigned char minor;\n\n\tminor = MINOR(i->rdev);\n\tswitch(minor) {\n\t\tcase MEMDEV_MEM:\n\t\t\ti->fsop = &mem_driver_fsop;\n\t\t\tbreak;\n\t\tcase MEMDEV_KMEM:\n\t\t\ti->fsop = &kmem_driver_fsop;\n\t\t\tbreak;\n\t\tcase MEMDEV_NULL:\n\t\t\ti->fsop = &null_driver_fsop;\n\t\t\tbreak;\n\t\tcase MEMDEV_PORT:\n\t\t\ti->fsop = &port_driver_fsop;\n\t\t\tbreak;\n\t\tcase MEMDEV_ZERO:\n\t\t\ti->fsop = &zero_driver_fsop;\n\t\t\tbreak;\n\t\tcase MEMDEV_FULL:\n\t\t\ti->fsop = &full_driver_fsop;\n\t\t\tbreak;\n\t\tcase MEMDEV_RANDOM:\n\t\t\ti->fsop = &urandom_driver_fsop;\n\t\t\tbreak;\n\t\tcase MEMDEV_URANDOM:\n\t\t\ti->fsop = &urandom_driver_fsop;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\treturn -ENXIO;\n\t}\n\treturn i->fsop->open(i, f);\n}\n\n/*\n * This function maps a range of physical addresses marked as not available for\n * use in the BIOS memory map, like the video RAM.\n */\nint mem_mmap(struct inode *i, struct vma *vma)\n{\n\tunsigned int addr, length;\n\n\tlength = (vma->end - vma->start) & PAGE_MASK;\n\n\t/* this breaks down the range in 4KB chunks */\n\tfor(addr = 0; addr < length; addr += PAGE_SIZE) {\n\t\t/* map the page only if is NOT available in the BIOS map */\n\t\tif(!is_addr_in_bios_map(vma->offset + addr)) {\n\t\t\tif(!map_page(current, (vma->start + addr) & PAGE_MASK, (vma->offset + addr) & PAGE_MASK, PROT_READ | PROT_WRITE)) {\n\t\t\t\treturn -ENOMEM;\n\t\t\t}\n\t\t} else {\n\t\t\tprintk(\"ERROR: %s(): mapping AVAILABLE pages in BIOS memory map isn't supported.\\n\", __FUNCTION__);\n\t\t\tprintk(\"\\tinvalid mapping: 0x%08x -> 0x%08x\\n\", (vma->start + addr) & PAGE_MASK, (vma->offset + addr) & PAGE_MASK);\n\t\t\treturn -EAGAIN;\n\t\t}\n\t}\n\tinvalidate_tlb();\n\treturn 0;\n}\n\nvoid memdev_init(void)\n{\n\tSET_MINOR(memdev_device.minors, MEMDEV_MEM);\n\tSET_MINOR(memdev_device.minors, MEMDEV_KMEM);\n\tSET_MINOR(memdev_device.minors, MEMDEV_NULL);\n\tSET_MINOR(memdev_device.minors, MEMDEV_PORT);\n\tSET_MINOR(memdev_device.minors, MEMDEV_ZERO);\n\tSET_MINOR(memdev_device.minors, MEMDEV_FULL);\n\tSET_MINOR(memdev_device.minors, MEMDEV_RANDOM);\n\tSET_MINOR(memdev_device.minors, MEMDEV_URANDOM);\n\n\tif(register_device(CHR_DEV, &memdev_device)) {\n\t\tprintk(\"ERROR: %s(): unable to register memory devices.\\n\", __FUNCTION__);\n\t\treturn;\n\t}\n}\n"
  },
  {
    "path": "drivers/char/ps2.c",
    "content": "/*\n * fiwix/drivers/char/ps2.c\n *\n * Copyright 2024, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/kparms.h>\n#include <fiwix/config.h>\n#include <fiwix/ps2.h>\n#include <fiwix/keyboard.h>\n#include <fiwix/psaux.h>\n#include <fiwix/stdio.h>\n\n/*\n * PS/2 System Control Port A bits\n * -------------------------------\n * #7 RW:fixed disk activity led\n * #6 RW:fixed disk activity led\n * #5 RW:reserved\n * #4 RW:watchdog timer status\n * #3 RW:security lock latch\n * #2 RW:reserved\n * #1 RW:alternate gate A20\n * #0 RW:alternate hot reset\n */\n#define PS2_SYSCTRL_A\t0x92\t/* PS/2 system control port A (R/W) */\n\nextern volatile unsigned char ack;\n\n/* wait controller output buffer to be full or for controller acknowledge */\nstatic int is_ready_to_read(void)\n{\n\tint n;\n\n\tfor(n = 0; n < PS2_TIMEOUT; n++) {\n\t\tif(ack) {\n\t\t\treturn 1;\n\t\t}\n\t\tif(inport_b(PS2_STATUS) & PS2_STAT_OUTBUSY) {\n\t\t\treturn 1;\n\t\t}\n\t}\n\tprintk(\"WARNING: PS/2 controller not ready to read.\\n\");\n\treturn 0;\n}\n\n/* wait controller input buffer to be clear */\nstatic int is_ready_to_write(void)\n{\n\tint n;\n\n\tfor(n = 0; n < PS2_TIMEOUT; n++) {\n\t\tif(!(inport_b(PS2_STATUS) & PS2_STAT_INBUSY)) {\n\t\t\treturn 1;\n\t\t}\n\t}\n\treturn 0;\n}\n\nstatic void ps2_delay(void)\n{\n\tint n;\n\n\tfor(n = 0; n < 1000; n++) {\n\t\tNOP();\n\t}\n}\n\nint ps2_wait_ack(void)\n{\n\tint n;\n\n\tif(is_ready_to_read()) {\n\t\tfor(n = 0; n < 1000; n++) {\n\t\t\tif(inport_b(PS2_DATA) == DEV_ACK) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tps2_delay();\n\t\t}\n\t}\n\treturn 1;\n}\n\nvoid ps2_write(const unsigned char port, const unsigned char byte)\n{\n\tack = 0;\n\n\tif(is_ready_to_write()) {\n\t\toutport_b(port, byte);\n\t}\n}\n\nunsigned char ps2_read(const unsigned char port)\n{\n\tif(is_ready_to_read()) {\n\t\treturn inport_b(port);\n\t}\n\treturn 0;\n}\n\nvoid ps2_clear_buffer(void)\n{\n\tint n;\n\n\tfor(n = 0; n < 1000; n++) {\n\t\tps2_delay();\n\t\tif(inport_b(PS2_STATUS) & PS2_STAT_OUTBUSY) {\n\t\t\tps2_read(PS2_DATA);\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n}\n\nvoid reboot(void)\n{\n\tCLI();\n\tps2_write(PS2_SYSCTRL_A, 0x01);\t\t\t/* Fast Hot Reset */\n\tps2_write(PS2_COMMAND, PS2_CMD_HOTRESET);\t/* Hot Reset */\n\tHLT();\n}\n\nvoid ps2_init(void)\n{\n\tint errno;\n\tunsigned char config, config2;\n\tchar type, supp_ports;\n\n\ttype = supp_ports = 0;\n\n\t/* disable device(s) */\n\tps2_write(PS2_COMMAND, PS2_CMD_DISABLE_CH1);\n\tps2_write(PS2_COMMAND, PS2_CMD_DISABLE_CH2);\n\n\t/* flush buffer */\n\tinport_b(PS2_DATA);\n\n\t/* get controller configuration */\n\tconfig = 0;\n\tps2_write(PS2_COMMAND, PS2_CMD_RECV_CONFIG);\n\tconfig = ps2_read(PS2_DATA);\n\n\tif(!(kparms.flags & KPARMS_PS2_NORESET)) {\n\t\t/* set controller configuration (disabling IRQs) */\n\t\tps2_write(PS2_COMMAND, PS2_CMD_SEND_CONFIG);\n\t\tps2_write(PS2_DATA, config & ~(0x01 | 0x02));\n\n\t\t/* PS/2 controller self-test */\n\t\tps2_write(PS2_COMMAND, PS2_CMD_SELF_TEST);\n\t\tif((errno = ps2_read(PS2_DATA)) != 0x55) {\n\t\t\tprintk(\"WARNING: %s(): PS/2 controller not returned 0x55 after self-test (was 0x%x), try with the parameter 'ps2_noreset'.\\n\", __FUNCTION__, errno);\n\t\t\treturn;\n\t\t} else {\n\t\t\tsupp_ports = 1;\n\t\t}\n\n\t\t/*\n\t\t * This sets again the controller configuration since the previous\n\t\t * step may also reset the PS/2 controller to its power-on defaults.\n\t\t */\n\t\tps2_write(PS2_COMMAND, PS2_CMD_SEND_CONFIG);\n\t\tps2_write(PS2_DATA, config);\n\t}\n\n\t/* double-check if we have a second channel */\n\tif(config & 0x20) {\n\t\tps2_write(PS2_COMMAND, PS2_CMD_ENABLE_CH2);\n\t\tps2_write(PS2_COMMAND, PS2_CMD_RECV_CONFIG);\n\t\tif(!(ps2_read(PS2_DATA) & 0x20)) {\n\t\t\tsupp_ports = 1 + (config & 0x20 ? 1 : 0);\n\t\t}\n\t\tps2_write(PS2_COMMAND, PS2_CMD_DISABLE_CH2);\n\t}\n\n\t/* test interface first channel */\n\tps2_write(PS2_COMMAND, PS2_CMD_TEST_CH1);\n\tif((errno = ps2_read(PS2_DATA)) != 0) {\n\t\tprintk(\"WARNING: %s(): test in first PS/2 interface returned 0x%x.\\n\", __FUNCTION__, errno);\n\t}\n\n\tif(supp_ports > 1) {\n\t\t/* test interface second channel */\n\t\tps2_write(PS2_COMMAND, PS2_CMD_TEST_CH2);\n\t\tif((errno = ps2_read(PS2_DATA)) != 0) {\n\t\t\tprintk(\"WARNING: %s(): test in second PS/2 interface returned 0x%x.\\n\", __FUNCTION__, errno);\n\t\t}\n\t}\n\n\t/* check if it is a type 1 or type 2 controller */\n\tconfig2 = 0;\n\tps2_write(PS2_COMMAND, PS2_CMD_RECV_CONFIG);\n\tconfig = ps2_read(PS2_DATA);\t/* save state */\n\tps2_write(PS2_COMMAND, PS2_CMD_SEND_CONFIG);\n\tps2_write(PS2_DATA, config | 0x40);\t/* set translation */\n\tps2_write(PS2_COMMAND, PS2_CMD_RECV_CONFIG);\n\tconfig2 = ps2_read(PS2_DATA);\n\tps2_write(PS2_COMMAND, PS2_CMD_SEND_CONFIG);\n\tps2_write(PS2_DATA, config);\t/* restore state */\n\ttype = (config2 & 0x40) ? 1 : 0;\n\n\t/* enable interrupts if channels are present */\n\tconfig |= 0x01;\n\tif(supp_ports > 1) {\n\t\tconfig |= 0x02;\n\t}\n\tconfig |= 0x40;\t/* allow translation */\n\tps2_write(PS2_COMMAND, PS2_CMD_SEND_CONFIG);\n\tps2_write(PS2_DATA, config);\n\n\tprintk(\"ps/2      0x%04x,0x%04x     -\\tcontroller type=%d, channels=%d\\n\", PS2_DATA, PS2_COMMAND, type, supp_ports);\n\n\t/* enable device(s) */\n\tps2_write(PS2_COMMAND, PS2_CMD_ENABLE_CH1);\n\tkeyboard_init();\n#ifdef CONFIG_PSAUX\n\tif(supp_ports > 1) {\n\t\tps2_write(PS2_COMMAND, PS2_CMD_ENABLE_CH2);\n\t\tpsaux_init();\n\t}\n#endif /* CONFIG_PSAUX */\n}\n"
  },
  {
    "path": "drivers/char/psaux.c",
    "content": "/*\n * fiwix/drivers/char/psaux.c\n *\n * Copyright 2024, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/devices.h>\n#include <fiwix/fs.h>\n#include <fiwix/errno.h>\n#include <fiwix/ps2.h>\n#include <fiwix/psaux.h>\n#include <fiwix/pic.h>\n#include <fiwix/irq.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/sched.h>\n#include <fiwix/sleep.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#ifdef CONFIG_PSAUX\nstatic struct fs_operations psaux_driver_fsop = {\n\t0,\n\t0,\n\n\tpsaux_open,\n\tpsaux_close,\n\tpsaux_read,\n\tpsaux_write,\n\tNULL,\t\t\t/* ioctl */\n\tNULL,\t\t\t/* llseek */\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tpsaux_select,\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lockup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nstatic struct device psaux_device = {\n\t\"psaux\",\n\tPSAUX_MAJOR,\n\t{ 0, 0, 0, 0, 0, 0, 0, 0 },\n\tNULL,\n\tNULL,\n\t&psaux_driver_fsop,\n\tNULL,\n\tNULL,\n\tNULL\n};\n\nstruct psaux psaux_table;\n\nstatic struct interrupt irq_config_psaux = { 0, \"psaux\", &irq_psaux, NULL };\n\nextern volatile unsigned char ack;\nstatic unsigned char status[3] = { 0, 0, 0};\nstatic unsigned char is_ps2 = 0;\nstatic char id = -1;\n\nstatic int psaux_command_write(const unsigned char byte)\n{\n\tps2_write(PS2_COMMAND, PS2_CMD_CH2_PREFIX);\n\tps2_write(PS2_DATA, byte);\n\tif(ps2_wait_ack()) {\n\t\tprintk(\"WARNING: %s(): ACK not received on %x command!\\n\", __FUNCTION__, byte);\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n\nstatic void psaux_identify(void)\n{\n\t/* disable */\n\tpsaux_command_write(PS2_AUX_DISABLE);\n\n\t/* status information */\n\tpsaux_command_write(PS2_DEV_GETINFO);\n\tstatus[0] = ps2_read(PS2_DATA);\t/* status */\n\tstatus[2] = ps2_read(PS2_DATA);\t/* resolution */\n\tstatus[2] = ps2_read(PS2_DATA);\t/* sample rate */\n\n\t/* identify */\n\tpsaux_command_write(PS2_DEV_RATE);\n\tpsaux_command_write(200);\n\tpsaux_command_write(PS2_DEV_RATE);\n\tpsaux_command_write(100);\n\tpsaux_command_write(PS2_DEV_RATE);\n\tpsaux_command_write(80);\n\tpsaux_command_write(PS2_DEV_IDENTIFY);\n\tid = ps2_read(PS2_DATA);\n\tps2_clear_buffer();\n\n\t/* enable */\n\tpsaux_command_write(PS2_DEV_ENABLE);\n}\n\nvoid irq_psaux(int num, struct sigcontext *sc)\n{\n\tunsigned char ch;\n\n\tch = inport_b(PS2_DATA);\n\n\t/* aux controller said 'acknowledge!' */\n\tif(ch == DEV_ACK) {\n\t\tack = 1;\n\t}\n\tif(!psaux_table.count) {\n\t\treturn;\n\t}\n\tcharq_putchar(&psaux_table.read_q, ch);\n\twakeup(&psaux_read);\n\twakeup(&do_select);\n}\n\nint psaux_open(struct inode *i, struct fd *f)\n{\n\tint minor;\n\n\tminor = MINOR(i->rdev);\n\tif(!TEST_MINOR(psaux_device.minors, minor)) {\n\t\treturn -ENXIO;\n\t}\n\tif(psaux_table.count++) {\n\t\treturn 0;\n\t}\n\tmemset_b(&psaux_table.read_q, 0, sizeof(struct clist));\n\tmemset_b(&psaux_table.write_q, 0, sizeof(struct clist));\n\treturn 0;\n}\n\nint psaux_close(struct inode *i, struct fd *f)\n{\n\tint minor;\n\n\tminor = MINOR(i->rdev);\n\tif(!TEST_MINOR(psaux_device.minors, minor)) {\n\t\treturn -ENXIO;\n\t}\n\tpsaux_table.count--;\n\treturn 0;\n}\n\nint psaux_read(struct inode *i, struct fd *f, char *buffer, __size_t count)\n{\n\tint minor, bytes_read;\n\tunsigned char ch;\n\n\tminor = MINOR(i->rdev);\n\tif(!TEST_MINOR(psaux_device.minors, minor)) {\n\t\treturn -ENXIO;\n\t}\n\n\twhile(!psaux_table.read_q.count) {\n\t\tif(f->flags & O_NONBLOCK) {\n\t\t\treturn -EAGAIN;\n\t\t}\n\t\tif(sleep(&psaux_read, PROC_INTERRUPTIBLE)) {\n\t\t\treturn -EINTR;\n\t\t}\n\t}\n\tbytes_read = 0;\n\twhile(bytes_read < count) {\n\t\tif(psaux_table.read_q.count) {\n\t\t\tch = charq_getchar(&psaux_table.read_q);\n\t\t\tbuffer[bytes_read++] = ch;\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\tif(bytes_read) {\n\t\ti->i_atime = CURRENT_TIME;\n\t}\n\treturn bytes_read;\n}\n\nint psaux_write(struct inode *i, struct fd *f, const char *buffer, __size_t count)\n{\n\tint minor, bytes_written;\n\tunsigned char ch;\n\n\tminor = MINOR(i->rdev);\n\tif(!TEST_MINOR(psaux_device.minors, minor)) {\n\t\treturn -ENXIO;\n\t}\n\n\tbytes_written = 0;\n\twhile(bytes_written < count) {\n\t\tch = buffer[bytes_written++];\n\t\tpsaux_command_write(ch);\n\t}\n\tif(bytes_written) {\n\t\ti->i_mtime = CURRENT_TIME;\n\t}\n\treturn bytes_written;\n}\n\nint psaux_select(struct inode *i, struct fd *f, int flag)\n{\n\tint minor;\n\n\tminor = MINOR(i->rdev);\n\tif(!TEST_MINOR(psaux_device.minors, minor)) {\n\t\treturn -ENXIO;\n\t}\n\n\tswitch(flag) {\n\t\tcase SEL_R:\n\t\t\tif(psaux_table.read_q.count) {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tbreak;\n\t}\n\treturn 0;\n}\n\nvoid psaux_init(void)\n{\n\tint errno;\n\n\t/* reset device */\n\tpsaux_command_write(PS2_DEV_RESET);\n\tif((errno = ps2_read(PS2_DATA)) != DEV_RESET_OK) {\n\t\tprintk(\"psaux     0x%04x-0x%04x       \\tdevice not detected\\n\", 0x60, 0x64);\n\t\treturn;\n\t}\n\tif(ps2_read(PS2_DATA) == 0) {\n\t\tis_ps2 = 1;\n\t}\n\n\tif(!register_irq(PSAUX_IRQ, &irq_config_psaux)) {\n\t\tenable_irq(PSAUX_IRQ);\n\t}\n\n\tps2_clear_buffer();\n\tpsaux_identify();\n\tprintk(\"psaux     0x%04x-0x%04x    %d\", 0x60, 0x64, PSAUX_IRQ);\n\tprintk(\"\\ttype=%s\", is_ps2 ? \"PS/2\" : \"unknown\");\n\tswitch(id) {\n\t\tcase -1:\n\t\t\tprintk(\", unknown ID %x\", id & 0xFF);\n\t\t\tbreak;\n\t\tcase 0:\n\t\t\tprintk(\", standard mouse\");\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tprintk(\", track ball\");\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\tprintk(\", 3-button wheel mouse\");\n\t\t\tbreak;\n\t\tcase 4:\n\t\t\tprintk(\", 5-button wheel mouse\");\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tprintk(\", unknown mouse\");\n\t\t\tbreak;\n\t}\n\tprintk(\"\\n\");\n\tmemset_b(&psaux_table, 0, sizeof(struct psaux));\n\tSET_MINOR(psaux_device.minors, PSAUX_MINOR);\n\tif(register_device(CHR_DEV, &psaux_device)) {\n\t\tprintk(\"WARNING: %s(): unable to register psaux device.\\n\", __FUNCTION__);\n\t}\n}\n#endif /* CONFIG_PSAUX */\n"
  },
  {
    "path": "drivers/char/pty.c",
    "content": "/*\n * fiwix/drivers/char/pty.c\n *\n * Copyright 2025, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/devices.h>\n#include <fiwix/errno.h>\n#include <fiwix/tty.h>\n#include <fiwix/pty.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_devpts.h>\n#include <fiwix/stat.h>\n#include <fiwix/ioctl.h>\n#include <fiwix/sleep.h>\n#include <fiwix/sched.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#ifdef CONFIG_UNIX98_PTYS\nextern struct devpts_files *devpts_list;\n\nstatic struct fs_operations pty_master_driver_fsop = {\n\t0,\n\t0,\n\n\ttty_open,\n\ttty_close,\n\tpty_read,\n\tpty_write,\n\ttty_ioctl,\n\ttty_llseek,\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tpty_select,\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lockup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nstatic struct fs_operations pty_slave_driver_fsop = {\n\t0,\n\t0,\n\n\ttty_open,\n\ttty_close,\n\ttty_read,\n\ttty_write,\n\ttty_ioctl,\n\ttty_llseek,\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\ttty_select,\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lockup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nstatic struct device pty_master_device = {\n\t\"ptmx\",\n\tPTY_MASTER_MAJOR,\n\t{ 0, 0, 0, 0, 0, 0, 0, 0 },\n\tNULL,\n\tNULL,\n\t&pty_master_driver_fsop,\n\tNULL,\n\tNULL,\n\tNULL\n};\n\nstatic struct device pty_slave_device = {\n\t\"pts\",\n\tPTY_SLAVE_MAJOR,\n\t{ 0, 0, 0, 0, 0, 0, 0, 0 },\n\tNULL,\n\tNULL,\n\t&pty_slave_driver_fsop,\n\tNULL,\n\tNULL,\n\tNULL\n};\n\nvoid pty_wakeup_read(struct tty *tty)\n{\n\twakeup(&pty_read);\n\twakeup(&do_select);\n}\n\nint pty_open(struct tty *tty)\n{\n\tstruct filesystems *fs;\n\tstruct inode *i;\n\tint n, minor;\n\n\tif(tty->flags & TTY_PTY_LOCK) {\n\t\treturn -EIO;\n\t}\n\tif(MAJOR(tty->dev) == PTY_SLAVE_MAJOR) {\n\t\treturn 0;\n\t}\n\tminor = MINOR(tty->dev);\n\tif(!TEST_MINOR(pty_master_device.minors, minor)) {\n\t\treturn -ENXIO;\n\t}\n\n\tif(!(fs = get_filesystem(\"devpts\"))) {\n\t\tprintk(\"WARNING: %s(): devpts filesystem is not registered!\\n\", __FUNCTION__);\n\t\treturn -EINVAL;\n\t}\n\tif(!(i = ialloc(&fs->mp->sb, S_IFCHR))) {\n\t\treturn -EINVAL;\n\t}\n\tfor(n = 0; n < NR_PTYS; n++) {\n\t\tif(devpts_list[n].inode == i) {\n\t\t\tbreak;\n\t\t}\n\t}\n\ttty->driver_data = (void *)&devpts_list[n];\n\ti->i_uid = current->uid;\n\ti->i_gid = current->gid;\n\tminor = i->inode - (DEVPTS_ROOT_INO + 1);\n\ti->rdev = MKDEV(PTY_SLAVE_MAJOR, minor);\n\tSET_MINOR(pty_slave_device.minors, minor);\n\tregister_device(CHR_DEV, &pty_slave_device);\n\ttty->flags &= ~TTY_OTHER_CLOSED;\n\treturn 0;\n}\n\nint pty_close(struct tty *tty)\n{\n\tstruct devpts_files *dp;\n\tstruct inode *i;\n\tint minor;\n\n\tif(MAJOR(tty->dev) == PTY_SLAVE_MAJOR) {\n\t\tif(tty->count > 2) {\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\ttty->flags |= TTY_OTHER_CLOSED;\n\twakeup(&tty->read_q);\n\twakeup(&pty_read);\n\twakeup(&do_select);\n\tif(MAJOR(tty->dev) == PTY_SLAVE_MAJOR) {\n\t\tminor = MINOR(tty->dev);\n\t\tCLEAR_MINOR(pty_slave_device.minors, minor);\n\t\tunregister_device(CHR_DEV, &pty_slave_device);\n\t\tdp = (struct devpts_files *)tty->driver_data;\n\t\ti = (struct inode *)dp->inode;\n\t\tif(tty->count < 2) {\n\t\t\tif(tty->link) {\n\t\t\t\ttty->link->count--;\t/* /dev/ptmx */\n\t\t\t}\n\t\t\tunregister_tty(tty);\n\t\t\ti->i_nlink--;\n\t\t\tiput(i);\n\t\t}\n\t}\n\treturn 0;\n}\n\nint pty_read(struct inode *i, struct fd *f, char *buffer, __size_t count)\n{\n\tstruct tty *tty;\n\tunsigned char ch;\n\tint n;\n\n\ttty = f->private_data;\n\n\tn = 0;\n\twhile(n < count) {\n\t\tif(tty->write_q.count > 0) {\n\t\t\tch = charq_getchar(&tty->write_q);\n\t\t\tbuffer[n++] = ch;\n\t\t\tcontinue;\n\t\t}\n\t\tif(n) {\n\t\t\tbreak;\n\t\t}\n\t\tif(tty->flags & TTY_OTHER_CLOSED) {\n\t\t\tn = -EIO;\n\t\t\tbreak;\n\t\t}\n\t\tif(sleep(&pty_read, PROC_INTERRUPTIBLE)) {\n\t\t\tn = -EINTR;\n\t\t\tbreak;\n\t\t}\n\t}\n\twakeup(&tty->write_q);\n\twakeup(&do_select);\n\treturn n;\n}\n\nint pty_write(struct inode *i, struct fd *f, const char *buffer, __size_t count)\n{\n\tstruct tty *tty;\n\tunsigned char ch;\n\tint n;\n\n\ttty = f->private_data;\n\n\tn = 0;\n\twhile(n < count) {\n\t\tch = buffer[n++];\n\t\tif(charq_room(&tty->read_q) > 0) {\n\t\t\tcharq_putchar(&tty->read_q, ch);\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t}\n\ttty->input(tty);\n\twakeup(&do_select);\n\treturn n;\n}\n\nint pty_ioctl(struct tty *tty, struct fd *f, int cmd, unsigned int arg)\n{\n\tswitch(cmd) {\n\t\tcase TIOCGPTN:\n\t\t{\n\t\t\tunsigned int *val = (unsigned int *)arg;\n\t\t\t*val = MINOR(tty->dev);\n\t\t\tbreak;\n\t\t}\n\t\tcase TIOCSPTLCK:\n\t\t{\n\t\t\tint val = *(unsigned int *)arg;\n\t\t\tif(val) {\n\t\t\t\ttty->flags |= TTY_PTY_LOCK;\n\t\t\t} else {\n\t\t\t\ttty->flags &= ~TTY_PTY_LOCK;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\treturn -EINVAL;\n\t}\n\treturn 0;\n}\n\nint pty_select(struct inode *i, struct fd *f, int flag)\n{\n\tstruct tty *tty;\n\n\ttty = f->private_data;\n\n\tswitch(flag) {\n\t\tcase SEL_R:\n\t\t\tif(tty->write_q.count) {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tif(tty->flags & TTY_OTHER_CLOSED) {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase SEL_W:\n\t\t\tif(!tty->read_q.count) {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tbreak;\n\t}\n\treturn 0;\n}\n\nvoid pty_init(void)\n{\n\tstruct tty *tty;\n\n\tSET_MINOR(pty_master_device.minors, PTY_MASTER_MINOR);\n\tif((tty = register_tty(MKDEV(PTY_MASTER_MAJOR, PTY_MASTER_MINOR)))) {\n\t\ttty->open = pty_open;\n\t\ttty->close = pty_close;\n\t\tif(register_device(CHR_DEV, &pty_master_device)) {\n\t\t\tprintk(\"WARNING: %s(): unable to register '%s' device.\\n\", __FUNCTION__, pty_master_device.name);\n\t\t\tunregister_tty(tty);\n\t\t\treturn;\n\t\t}\n\t\tprintk(\"ptmx      -\\t\\t    -\\ttype=UNIX98, ptys=%d\\n\", NR_PTYS);\n\t} else {\n\t\tprintk(\"WARNING: %s(): unable to register %s.\\n\", __FUNCTION__, pty_master_device.name);\n\t}\n}\n#endif /* CONFIG_UNIX98_PTYS */\n"
  },
  {
    "path": "drivers/char/serial.c",
    "content": "/*\n * fiwix/drivers/char/serial.c\n *\n * Copyright 2020-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/devices.h>\n#include <fiwix/fs.h>\n#include <fiwix/errno.h>\n#include <fiwix/pic.h>\n#include <fiwix/irq.h>\n#include <fiwix/sleep.h>\n#include <fiwix/serial.h>\n#include <fiwix/pci.h>\n#include <fiwix/tty.h>\n#include <fiwix/ctype.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n#include <fiwix/sysconsole.h>\n\nstatic struct fs_operations serial_driver_fsop = {\n\t0,\n\t0,\n\n\ttty_open,\n\ttty_close,\n\ttty_read,\n\ttty_write,\n\ttty_ioctl,\n\ttty_llseek,\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\ttty_select,\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lockup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\n/* FIXME: this should be allocated dynamically */\nstruct serial serial_table[NR_SERIAL];\n\nstatic struct device serial_device = {\n\t\"ttyS\",\n\tSERIAL_MAJOR,\n\t{ 0, 0, 0, 0, 0, 0, 0, 0 },\n\tNULL,\n\tNULL,\n\t&serial_driver_fsop,\n\tNULL,\n\tNULL,\n\tNULL\n};\n\nstatic int isa_ioports[] = {\n\t0x3F8,\n\t0x2F8,\n\t0x3E8,\n\t0x2E8,\n\t0\n};\n\nchar *serial_chip[] = {\n\tNULL,\n\t\"8250\",\n\t\"16450\",\n\t\"16550\",\n\t\"16550A\",\n};\n\nstatic int baud_table[] = {\n\t0,\n\t50,\n\t75,\n\t110,\n\t134,\n\t150,\n\t200,\n\t300,\n\t600,\n\t1200,\n\t1800,\n\t2400,\n\t4800,\n\t9600,\n\t19200,\n\t38400,\n\t57200,\n\t115200,\n\t0\n};\n\nstatic struct serial *serial_active = NULL;\nstatic struct bh serial_bh = { 0, &irq_serial_bh, NULL };\n\n/* FIXME: this should be allocated dynamically */\nstatic struct interrupt irq_config_serial0 = { 0, \"serial\", &irq_serial, NULL };\t/* ISA irq4 */\nstatic struct interrupt irq_config_serial1 = { 0, \"serial\", &irq_serial, NULL };\t/* ISA irq3 */\nstatic struct interrupt irq_config_serial2 = { 0, \"serial\", &irq_serial, NULL };\t/* first PCI device */\n\nstatic int is_serial(__dev_t dev)\n{\n\tif(MAJOR(dev) == SERIAL_MAJOR && ((MINOR(dev) >= (1 << SERIAL_MSF) && MINOR(dev) < (1 << SERIAL_MSF) + SERIAL_MINORS))) {\n\t\treturn 1;\n\t}\n\n\treturn 0;\n}\n\n/* FIXME: this should be removed once these structures are allocated dynamically */\nstatic struct serial *get_serial_slot(void)\n{\n\tint n;\n\n\tfor(n = 0; n < NR_SERIAL; n++) {\n\t\tif(!(serial_table[n].flags & UART_ACTIVE)) {\n\t\t\treturn &serial_table[n];\n\t\t}\n\t}\n\n\tprintk(\"WARNING: %s(): no more serial slots free!\\n\", __FUNCTION__);\n\treturn NULL;\n}\n\nstatic int serial_identify(struct serial *s)\n{\n\tint value;\n\n\t/* set all features in FCR register to test the status of FIFO */\n\toutport_b(s->ioaddr + UART_FCR, (UART_FCR_FIFO |\n\t\t\t\t\tUART_FCR_DMA |\n\t\t\t\t\tUART_FCR_FIFO64 |\n\t\t\t\t\tUART_FCR_FIFO14));\n\n\tvalue = inport_b(s->ioaddr + UART_IIR);\n\tif(value & UART_IIR_FIFOKO) {\n\t\tif(value & UART_IIR_FIFO) {\n\t\t\tif(value & UART_IIR_FIFO64) {\n\t\t\t\t/* 16750 chip is not supported */\n\t\t\t} else {\n\t\t\t\ts->flags |= UART_IS_16550A | UART_HAS_FIFO;\n\t\t\t\treturn 4;\n\t\t\t}\n\t\t} else {\n\t\t\ts->flags |= UART_IS_16550;\n\t\t\treturn 3;\n\t\t}\n\t} else {\n\t\t/*\n\t\t * At this point we know this device don't has FIFO,\n\t\t * the Scratch Register will help us to know the final chip.\n\t\t */\n\t\tvalue = inport_b(s->ioaddr + UART_SR);\t/* save its value */\n\t\toutport_b(s->ioaddr + UART_SR, 0xAA);\t/* put a random value */\n\t\tif(inport_b(s->ioaddr + UART_SR) != 0xAA) {\n\t\t\ts->flags |= UART_IS_8250;\n\t\t\treturn 1;\n\t\t} else {\n\t\t\toutport_b(s->ioaddr + UART_SR, value);\t/* restore it */\n\t\t\ts->flags |= UART_IS_16450;\n\t\t\treturn 2;\n\t\t}\n\t}\n\treturn 0;\n}\n\nstatic void serial_default(struct serial *s)\n{\n\ts->name = \"ttyS.\";\n\n\t/* 9600,N,8,1 by default */\n\ts->baud = 9600;\n\ts->lctrl = UART_LCR_NP | UART_LCR_WL8 | UART_LCR_1STB;\n}\n\nstatic void serial_setup(struct serial *s)\n{\n\tint divisor;\n\n\toutport_b(s->ioaddr + UART_IER, 0);\t/* disable all interrupts */\n\n\tdivisor = 115200 / s->baud;\n\toutport_b(s->ioaddr + UART_LCR, UART_LCR_DLAB);\t/* enable DLAB */\n\toutport_b(s->ioaddr + UART_DLL, divisor & 0xFF);\t/* LSB of divisor */\n\toutport_b(s->ioaddr + UART_DLH, divisor >> 8);\t/* MSB of divisor */\n\toutport_b(s->ioaddr + UART_LCR, s->lctrl);\t/* line control */\n}\n\n/* disable transmitter interrupts */\nstatic void serial_stop(struct tty *tty)\n{\n\tstruct serial *s;\n\tunsigned int flags;\n\n\tSAVE_FLAGS(flags); CLI();\n\ts = (struct serial *)tty->driver_data;\n\toutport_b(s->ioaddr + UART_IER, UART_IER_RDAI);\n\tRESTORE_FLAGS(flags);\n}\n\n/* enable transmitter interrupts */\nstatic void serial_start(struct tty *tty)\n{\n\tstruct serial *s;\n\tunsigned int flags;\n\n\tSAVE_FLAGS(flags); CLI();\n\ts = (struct serial *)tty->driver_data;\n\toutport_b(s->ioaddr + UART_IER, UART_IER_RDAI | UART_IER_THREI);\n\tRESTORE_FLAGS(flags);\n}\n\nstatic void serial_errors(struct serial *s, int status)\n{\n\tstruct tty *tty;\n\n\ttty = s->tty;\n\n\tif(!(tty->termios.c_iflag & IGNBRK) && tty->termios.c_iflag & BRKINT) {\n\t\tif(status & UART_LSR_BI) {\n\t\t\tprintk(\"WARNING: break interrupt in %s.\\n\", s->name);\n\t\t}\n\t}\n\n\t/* this includes also overrun errors */\n\tif(!(tty->termios.c_iflag & IGNPAR) && tty->termios.c_iflag & PARMRK) {\n\t\tif(status & UART_LSR_OE) {\n\t\t\tprintk(\"WARNING: overrun error in %s.\\n\", s->name);\n\n\t\t} else if(status & UART_LSR_PE) {\n\t\t\tprintk(\"WARNING: parity error in %s.\\n\", s->name);\n\n\t\t} else if(status & UART_LSR_FE) {\n\t\t\tprintk(\"WARNING: framing error in %s.\\n\", s->name);\n\t\n\t\t} else if(status & UART_LSR_EFIFO) {\n\t\t\tprintk(\"WARNING: FIFO error in %s.\\n\", s->name);\n\t\t}\n\t}\n}\n\nstatic void serial_send(struct tty *tty)\n{\n\tunsigned char ch;\n\tstruct serial *s;\n\tint count;\n\n\ts = (struct serial *)tty->driver_data;\n\n\tif(!tty->write_q.count) {\n\t\toutport_b(s->ioaddr + UART_IER, UART_IER_RDAI);\n\t\treturn;\n\t}\n\n\tcount = 0;\n\twhile(tty->write_q.count > 0 && count < UART_FIFO_SIZE) {\n\t\tch = charq_getchar(&tty->write_q);\n\t\toutport_b(s->ioaddr + UART_TD, ch);\n\t\tcount++;\n\t}\n\n\tif(!tty->write_q.count) {\n\t\toutport_b(s->ioaddr + UART_IER, UART_IER_RDAI);\n\t}\n\twakeup(&tty_write);\n}\n\nstatic int serial_receive(struct serial *s)\n{\n\tint status, errno;\n\tunsigned char ch;\n\tstruct tty *tty;\n\n\terrno = 0;\n\ttty = s->tty;\n\n\tdo {\n\t\tif(!charq_room(&tty->read_q)) {\n\t\t\terrno = -EAGAIN;\n\t\t\tbreak;\n\t\t}\n\t\tch = inport_b(s->ioaddr + UART_RD);\n\t\tcharq_putchar(&tty->read_q, ch);\n\t\tstatus = inport_b(s->ioaddr + UART_LSR);\n\t} while(status & UART_LSR_RDA);\n\n\tserial_bh.flags |= BH_ACTIVE;\n\treturn errno;\n}\n\nvoid irq_serial(int num, struct sigcontext *sc)\n{\n\tstruct serial *s;\n\tint status;\n\n\ts = serial_active;\n\n\twhile(s) {\n\t\tif(s->irq == num) {\n\t\t\twhile(!(inport_b(s->ioaddr + UART_IIR) & UART_IIR_NOINT)) {\n\t\t\t\tstatus = inport_b(s->ioaddr + UART_LSR);\n\t\t\t\tif(status & UART_LSR_RDA) {\n\t\t\t\t\tif(serial_receive(s)) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(status & UART_LSR_THRE) {\n\t\t\t\t\tserial_send(s->tty);\n\t\t\t\t}\n\t\t\t\tserial_errors(s, status);\n\t\t\t}\n\t\t}\n\t\ts = s->next;\n\t}\n}\n\nint serial_open(struct tty *tty)\n{\n\tstruct serial *s;\n\tint minor;\n\n\tminor = MINOR(tty->dev);\n\tif(!TEST_MINOR(serial_device.minors, minor)) {\n\t\treturn -ENXIO;\n\t}\n\n\ts = (struct serial *)tty->driver_data;\n\n\t/* enable FIFO */\n\tif(s->flags & UART_HAS_FIFO) {\n\t\toutport_b(s->ioaddr + UART_FCR, UART_FCR_FIFO | UART_FCR_FIFO14);\n\t}\n\toutport_b(s->ioaddr + UART_MCR, UART_MCR_OUT2 | UART_MCR_RTS | UART_MCR_DTR);\n\n\t/* enable interrupts */\n\toutport_b(s->ioaddr + UART_IER, UART_IER_RDAI);\n\n\t/* clear all input registers */\n\tinport_b(s->ioaddr + UART_RD);\n\tinport_b(s->ioaddr + UART_IIR);\n\tinport_b(s->ioaddr + UART_LSR);\n\tinport_b(s->ioaddr + UART_MSR);\n\n\treturn 0;\n}\n\nint serial_close(struct tty *tty)\n{\n\tstruct serial *s;\n\tint minor;\n\n\tminor = MINOR(tty->dev);\n\tif(!TEST_MINOR(serial_device.minors, minor)) {\n\t\treturn -ENXIO;\n\t}\n\n\ts = (struct serial *)tty->driver_data;\n\n\tif(tty->count > 1) {\n\t\treturn 0;\n\t}\n\n\t/* disable all interrupts */\n\toutport_b(s->ioaddr + UART_IER, 0);\n\n\t/* disable FIFO */\n\toutport_b(s->ioaddr + UART_FCR, UART_FCR_CRCVR | UART_FCR_CXMTR);\n\n\t/* clear all input register */\n\tinport_b(s->ioaddr + UART_RD);\n\n\treturn 0;\n}\n\nvoid serial_set_termios(struct tty *tty)\n{\n\tshort int divisor;\n\tint baud, size, stop;\n\tint lctrl;\n\tstruct serial *s;\n\n\ts = (struct serial *)tty->driver_data;\n\tlctrl = 0;\n\n\tif(!(baud = baud_table[tty->termios.c_cflag & CBAUD])) {\n\t\treturn;\n\t}\n\tdivisor = 115200 / baud;\n\n\toutport_b(s->ioaddr + UART_LCR, UART_LCR_DLAB);\t/* enable DLAB */\n\toutport_b(s->ioaddr + UART_DLL, divisor & 0xFF);\t/* LSB of divisor */\n\toutport_b(s->ioaddr + UART_DLH, divisor >> 8);\t/* MSB of divisor */\n\n\tsize = tty->termios.c_cflag & CSIZE;\n\tswitch(size) {\n\t\tcase CS5:\n\t\t\tlctrl = UART_LCR_WL5;\n\t\t\tbreak;\n\t\tcase CS6:\n\t\t\tlctrl = UART_LCR_WL6;\n\t\t\tbreak;\n\t\tcase CS7:\n\t\t\tlctrl = UART_LCR_WL7;\n\t\t\tbreak;\n\t\tcase CS8:\n\t\t\tlctrl = UART_LCR_WL8;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tlctrl = UART_LCR_WL5;\n\t\t\tbreak;\n\t}\n\n\tstop = tty->termios.c_cflag & CSTOPB;\n\tif(stop) {\n\t\tlctrl |= UART_LCR_2STB;\n\t} else {\n\t\tlctrl |= UART_LCR_1STB;\n\t}\n\n\tif(tty->termios.c_cflag & PARENB) {\n\t\tlctrl |= UART_LCR_EP;\n\t} else if(tty->termios.c_cflag & PARODD) {\n\t\tlctrl |= UART_LCR_OP;\n\t} else {\n\t\tlctrl |= UART_LCR_NP;\n\t}\n\n\t/* FIXME: flow control RTSCTS no supported */\n\n\toutport_b(s->ioaddr + UART_LCR, lctrl);\t/* line control */\n}\n\nvoid serial_write(struct tty *tty)\n{\n\tstruct serial *s;\n\tunsigned int flags;\n\n\tSAVE_FLAGS(flags); CLI();\n\ts = (struct serial *)tty->driver_data;\n\toutport_b(s->ioaddr + UART_IER, UART_IER_RDAI | UART_IER_THREI);\n\tRESTORE_FLAGS(flags);\n}\n\nvoid irq_serial_bh(struct sigcontext *sc)\n{\n\tstruct tty *tty;\n\tstruct serial *s;\n\n\ts = serial_active;\n\n\twhile(s) {\n\t\ttty = s->tty;\n\t\tif(tty->read_q.count) {\n\t\t\tif(can_lock_area(AREA_SERIAL_READ)) {\n\t\t\t\ttty->input(tty);\n\t\t\t\tunlock_area(AREA_SERIAL_READ);\n\t\t\t} else {\n\t\t\t\tserial_bh.flags |= BH_ACTIVE;\n\t\t\t}\n\t\t}\n\t\ts = s->next;\n\t}\n}\n\nstatic int register_serial(struct serial *s, int minor)\n{\n\tstruct serial **sp;\n\tstruct tty *tty;\n\tint n, type;\n\n\tserial_default(s);\n\tif((type = serial_identify(s))) {\n\t\ts->name[4] = '0' + minor;\n\t\tprintk(\"%s\t  0x%04x-0x%04x\t  %3d\\ttype=%s%s\\n\", s->name, s->ioaddr, s->ioaddr + s->iosize - 1, s->irq, serial_chip[type], s->flags & UART_HAS_FIFO ? \" FIFO=yes\" : \"\");\n\t\tSET_MINOR(serial_device.minors, (1 << SERIAL_MSF) + minor);\n\t\tserial_setup(s);\n\t\tsp = &serial_active;\n\t\tif(*sp) {\n\t\t\tdo {\n\t\t\t\tsp = &(*sp)->next;\n\t\t\t} while(*sp);\n\t\t}\n\t\tif((tty = register_tty(MKDEV(SERIAL_MAJOR, (1 << SERIAL_MSF) + minor)))) {\n\t\t\ttty->driver_data = (void *)s;\n\t\t\ttty->stop = serial_stop;\n\t\t\ttty->start = serial_start;\n\t\t\ttty->deltab = tty_deltab;\n\t\t\ttty->reset = tty_reset;\n\t\t\ttty->input = do_cook;\n\t\t\ttty->output = serial_write;\n\t\t\ttty->open = serial_open;\n\t\t\ttty->close = serial_close;\n\t\t\ttty->set_termios = serial_set_termios;\n\t\t\ttty_reset(tty);\n\t\t\tfor(n = 0; n < MAX_TAB_COLS; n++) {\n\t\t\t\tif(!(n % TAB_SIZE)) {\n\t\t\t\t\ttty->tab_stop[n] = 1;\n\t\t\t\t} else {\n\t\t\t\t\ttty->tab_stop[n] = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t\ttty->count = 0;\n\t\t\ts->tty = tty;\n\t\t\ts->flags |= UART_ACTIVE;\n\t\t\t*sp = s;\n\t\t\treturn 0;\n\t\t} else {\n\t\t\tprintk(\"WARNING: %s(): unable to register %s.\\n\", __FUNCTION__, s->name);\n\t\t}\n\t}\n\n\treturn 1;\n}\n\n#ifdef CONFIG_PCI\nstatic int setup_serial_device(int minor, struct pci_device *pci_dev)\n{\n\tstruct serial *s;\n\tunsigned short int cmd;\n\n\tif(pci_dev->flags[0] & PCI_F_ADDR_SPACE_MEM) {\n\t\tprintk(\"WARNING: %s(): MMIO is not supported.\\n\", __FUNCTION__);\n\t\treturn minor;\n\t}\n\tif(!(s = get_serial_slot())) {\n\t\treturn minor;\n\t}\n\n\t/* enable I/O space */\n\tcmd = (pci_dev->command | PCI_COMMAND_IO);\n\tpci_write_short(pci_dev, PCI_COMMAND, cmd);\n\n\ts->ioaddr = pci_dev->bar[0];\n\ts->iosize = pci_dev->size[0];\n\ts->irq = pci_dev->irq;\n\tif(!register_serial(s, minor)) {\n\t\tpci_show_desc(pci_dev);\n\t\tif(!register_irq(s->irq, &irq_config_serial2)) {\n\t\t\tenable_irq(s->irq);\n\t\t}\n\t\tminor++;\n\t}\n\treturn minor;\n}\n\nstatic int serial_pci(int minor)\n{\n\tstruct pci_device *pci_dev;\n\n\tpci_dev = pci_device_table;\n\twhile(pci_dev) {\n\t\tif(pci_dev->class == PCI_CLASS_COMMUNICATION_SERIAL) {\n\t\t\tminor = setup_serial_device(minor, pci_dev);\n\t\t}\n\t\tif(minor < NR_SERIAL) {\n\t\t\tpci_dev = pci_dev->next;\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\treturn minor;\n}\n#endif /* CONFIG_PCI */\n\nstatic int serial_isa(void)\n{\n\tstruct serial *s;\n\tint n, minor;\n\n\tfor(n = 0, minor = 0; isa_ioports[n] && minor < NR_SERIAL; n++) {\n\t\tif(!(s = get_serial_slot())) {\n\t\t\treturn minor;\n\t\t}\n\t\ts->ioaddr = isa_ioports[n];\n\t\ts->iosize = 7;\n\t\tif(!(minor & 1)) {\n\t\t\ts->irq = SERIAL4_IRQ;\n\t\t} else {\n\t\t\ts->irq = SERIAL3_IRQ;\n\t\t}\n\t\tif(!(register_serial(s, minor))) {\n\t\t\tif(!minor) {\n\t\t\t\tif(!register_irq(SERIAL4_IRQ, &irq_config_serial0)) {\n\t\t\t\t\tenable_irq(SERIAL4_IRQ);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(minor == 1) {\n\t\t\t\tif(!register_irq(SERIAL3_IRQ, &irq_config_serial1)) {\n\t\t\t\t\tenable_irq(SERIAL3_IRQ);\n\t\t\t\t}\n\t\t\t}\n\t\t\tminor++;\n\t\t}\n\t}\n\n\treturn minor;\n}\n\nvoid serial_init(void)\n{\n\tint minor, n, syscon;\n\tstruct tty *tty;\n\n\tmemset_b(serial_table, 0, sizeof(serial_table));\n\n\tminor = serial_isa();\n#ifdef CONFIG_PCI\n\tminor = serial_pci(minor);\n#endif /* CONFIG_PCI */\n\n\tif(minor) {\n\t\tadd_bh(&serial_bh);\n\t\tif(register_device(CHR_DEV, &serial_device)) {\n\t\t\tprintk(\"WARNING: %s(): unable to register serial device.\\n\", __FUNCTION__);\n\t\t}\n\n\t\t/* check if a serial tty will act as a system console */\n\t\tfor(n = 0, syscon = 0; n < NR_SYSCONSOLES; n++) {\n\t\t\tif(is_serial(sysconsole_table[n].dev)) {\n\t\t\t\tif((tty = get_tty(sysconsole_table[n].dev))) {\n\t\t\t\t\tif(!syscon) {\n\t\t\t\t\t\tsyscon = sysconsole_table[n].dev;\n\t\t\t\t\t}\n\t\t\t\t\tregister_console(tty);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif(syscon) {\n\t\t\t/* flush early log into the first console */\n\t\t\ttty = get_tty(syscon);\n\t\t\tflush_log_buf(tty);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "drivers/char/sysrq.c",
    "content": "/*\n * fiwix/drivers/char/sysrq.c\n *\n * Copyright 2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/sysrq.h>\n#include <fiwix/traps.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n#include <fiwix/sleep.h>\n#include <fiwix/sched.h>\n#include <fiwix/mm.h>\n\nstatic const char *pstate[] = {\n\t\"?\",\n\t\"R\",\n\t\"S\",\n\t\"Z\",\n\t\"T\",\n\t\"D\"\n};\n\nstatic void memory(void)\n{\n\tchar *buf;\n\n\tbuf = (char *)kmalloc(PAGE_SIZE);\n\tdata_proc_meminfo(buf, 0);\n\tprintk(\"%s\", buf);\n\tprintk(\"\\n\");\n\tdata_proc_buddyinfo(buf, 0);\n\tprintk(\"%s\", buf);\n\tprintk(\"\\n\");\n\tkfree((unsigned int)buf);\n}\n\nstatic void proc_list(void)\n{\n\tstruct proc *p;\n\n\tprintk(\"USER   PID   PPID    RSS S SLEEP_ADDR CMD\\n\");\n\tFOR_EACH_PROCESS(p) {\n\t\tprintk(\"%d    %5d  %5d  %5d %s \",\n\t\t\tp->uid,\n\t\t\tp->pid,\n\t\t\tp->ppid ? p->ppid->pid : 0,\n\t\t\tp->rss << 2,\n\t\t\tpstate[p->state]);\n\t\tif(p->state == PROC_SLEEPING) {\n\t\t\tprintk(\"0x%08x \", p->sleep_address);\n\t\t} else {\n\t\t\tprintk(\"           \");\n\t\t}\n\t\tprintk(\"%s\\n\", p->argv0);\n\t\tp = p->next;\n\t}\n\n\tprintk(\"List of PIDs in running queue: \");\n\tFOR_EACH_PROCESS_RUNNING(p) {\n\t\tprintk(\"%d \", p->pid);\n\t\tp = p->next_run;\n\t}\n\tprintk(\"\\n\");\n}\n\nvoid sysrq(int op)\n{\n\tswitch(op) {\n\t\tcase SYSRQ_STACK:\n\t\t\tprintk(\"sysrq: Stack backtrace.\\n\");\n\t\t\tstack_backtrace();\n\t\t\tbreak;\n\t\tcase SYSRQ_MEMORY:\n\t\t\tprintk(\"sysrq: Memory information.\\n\");\n\t\t\tmemory();\n\t\t\tbreak;\n\t\tcase SYSRQ_TASKS:\n\t\t\tprintk(\"sysrq: Task list.\\n\");\n\t\t\tproc_list();\n\t\t\tbreak;\n\t\tcase SYSRQ_UNDEF:\n\t\t\tprintk(\"sysrq: Undefined operation.\\n\");\n\t\t\tbreak;\n\t}\n}\n"
  },
  {
    "path": "drivers/char/tty.c",
    "content": "/*\n * fiwix/drivers/char/tty.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/kparms.h>\n#include <fiwix/asm.h>\n#include <fiwix/ioctl.h>\n#include <fiwix/tty.h>\n#include <fiwix/ctype.h>\n#include <fiwix/console.h>\n#include <fiwix/devices.h>\n#include <fiwix/fs.h>\n#include <fiwix/errno.h>\n#include <fiwix/sched.h>\n#include <fiwix/timer.h>\n#include <fiwix/sleep.h>\n#include <fiwix/process.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/kd.h>\n#include <fiwix/pty.h>\n#include <fiwix/fs_devpts.h>\n#include <fiwix/mm.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#define SYSCON_DEV\tMKDEV(SYSCON_MAJOR, 1)\n#define VCONSOLE_DEV\tMKDEV(VCONSOLES_MAJOR, 0)\n#define TTY_DEV\t\tMKDEV(SYSCON_MAJOR, 0)\n\nstruct tty *tty_table;\nextern short int current_cons;\n\nstatic void wait_vtime_off(unsigned int arg)\n{\n\tunsigned int *fn = (unsigned int *)arg;\n\n\twakeup(fn);\n}\n\nstatic void termios2termio(struct termios *termios, struct termio *termio)\n{\n\tint n;\n\n\ttermio->c_iflag = termios->c_iflag;\n\ttermio->c_oflag = termios->c_oflag;\n\ttermio->c_cflag = termios->c_cflag;\n\ttermio->c_lflag = termios->c_lflag;\n\ttermio->c_line = termios->c_line;\n\tfor(n = 0; n < NCC; n++) {\n\t\ttermio->c_cc[n] = termios->c_cc[n];\n\t}\n}\n\nstatic void termio2termios(struct termio *termio, struct termios *termios)\n{\n\tint n;\n\n\ttermios->c_iflag = termio->c_iflag;\n\ttermios->c_oflag = termio->c_oflag;\n\ttermios->c_cflag = termio->c_cflag;\n\ttermios->c_lflag = termio->c_lflag;\n\ttermios->c_line = termio->c_line;\n\tfor(n = 0; n < NCC; n++) {\n\t\ttermios->c_cc[n] = termio->c_cc[n];\n\t}\n}\n\nstatic int opost(struct tty *tty, unsigned char ch)\n{\n\tint status;\n\n\tstatus = 0;\n\n\tif(tty->termios.c_oflag & OPOST) {\n\t\tswitch(ch) {\n\t\t\tcase '\\n':\n\t\t\t\tif(tty->termios.c_oflag & ONLCR) {\n\t\t\t\t\tif(charq_room(&tty->write_q) >= 2) {\n\t\t\t\t\t\tcharq_putchar(&tty->write_q, '\\r');\n\t\t\t\t\t\ttty->column = 0;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn -1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase '\\t':\n\t\t\t\twhile(tty->column < (tty->winsize.ws_col - 1)) {\n\t\t\t\t\tif(tty->tab_stop[++tty->column]) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase '\\b':\n\t\t\t\tif(tty->column > 0) {\n\t\t\t\t\ttty->column--;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tif(tty->termios.c_oflag & OLCUC) {\n\t\t\t\t\tch = TOUPPER(ch);\n\t\t\t\t}\n\t\t\t\tif(!ISCNTRL(ch)) {\n\t\t\t\t\ttty->column++;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n\tif(charq_putchar(&tty->write_q, ch) < 0) {\n\t\tstatus = -1;\n\t}\n\treturn status;\n}\n\nstatic void out_char(struct tty *tty, unsigned char ch)\n{\n\tif(ISCNTRL(ch) && !ISSPACE(ch) && (tty->termios.c_lflag & ECHOCTL)) {\n\t\tif(tty->flags & TTY_HAS_LNEXT || (!(tty->flags & TTY_HAS_LNEXT) && ch != tty->termios.c_cc[VEOF])) {\n\t\t\tcharq_putchar(&tty->write_q, '^');\n\t\t\tcharq_putchar(&tty->write_q, ch + 64);\n\t\t\ttty->column += 2;\n\t\t}\n\t} else {\n\t\topost(tty, ch);\n\t}\n}\n\nstatic void erase_char(struct tty *tty, unsigned char erasechar)\n{\n\tunsigned char ch;\n\n\tif(erasechar == tty->termios.c_cc[VERASE]) {\n\t\tif((ch = charq_unputchar(&tty->cooked_q))) {\n\t\t\tif(tty->termios.c_lflag & ECHO) {\n\t\t\t\tcharq_putchar(&tty->write_q, '\\b');\n\t\t\t\tcharq_putchar(&tty->write_q, ' ');\n\t\t\t\tcharq_putchar(&tty->write_q, '\\b');\n\t\t\t\tif(ch == '\\t') {\n\t\t\t\t\ttty->deltab(tty);\n\t\t\t\t}\n\t\t\t\tif(ISCNTRL(ch) && !ISSPACE(ch) && tty->termios.c_lflag & ECHOCTL) {\n\t\t\t\t\tcharq_putchar(&tty->write_q, '\\b');\n\t\t\t\t\tcharq_putchar(&tty->write_q, ' ');\n\t\t\t\t\tcharq_putchar(&tty->write_q, '\\b');\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif(erasechar == tty->termios.c_cc[VWERASE]) {\n\t\tunsigned char word_seen = 0;\n\n\t\twhile(tty->cooked_q.count > 0) {\n\t\t\tch = LAST_CHAR(&tty->cooked_q);\n\t\t\tif((ch == ' ' || ch == '\\t') && word_seen) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif(ch != ' ' && ch != '\\t') {\n\t\t\t\tword_seen = 1;\n\t\t\t}\n\t\t\terase_char(tty, tty->termios.c_cc[VERASE]);\n\t\t}\n\t}\n\tif(erasechar == tty->termios.c_cc[VKILL]) {\n\t\twhile(tty->cooked_q.count > 0) {\n\t\t\terase_char(tty, tty->termios.c_cc[VERASE]);\n\t\t}\n\t\tif(tty->termios.c_lflag & ECHOK && !(tty->termios.c_lflag & ECHOE)) {\n\t\t\tcharq_putchar(&tty->write_q, '\\n');\n\t\t}\n\t}\n}\n\nstatic void set_termios(struct tty *tty, struct termios *new_termios)\n{\n\tmemcpy_b(&tty->termios, new_termios, sizeof(struct termios));\n\tif(tty->set_termios) {\n\t\ttty->set_termios(tty);\n\t}\n}\n\nstatic void set_termio(struct tty *tty, struct termio *new_termio)\n{\n\tstruct termios new_termios;\n\n\ttermio2termios(new_termio, &new_termios);\n\tmemcpy_b(&tty->termios, &new_termios, sizeof(struct termios));\n}\n\nvoid tty_reset(struct tty *tty)\n{\n\ttermios_reset(tty);\n\ttty->winsize.ws_row = 25;\n\ttty->winsize.ws_col = 80;\n\ttty->winsize.ws_xpixel = 0;\n\ttty->winsize.ws_ypixel = 0;\n\ttty->flags = 0;\n}\n\nstruct tty *register_tty(__dev_t dev)\n{\n\tunsigned int flags;\n\tstruct tty *tty, *t;\n\tint n;\n\n\tif(!(tty = (struct tty *)kmalloc(sizeof(struct tty)))) {\n\t\treturn NULL;\n\t}\n\n\tSAVE_FLAGS(flags); CLI();\n\tif((t = tty_table)) {\n\t\tfor(;;) {\n\t\t\tif(t->dev == dev) {\n\t\t\t\tprintk(\"ERROR: %s(): tty device %d,%d already registered!\\n\", __FUNCTION__, MAJOR(dev), MINOR(dev));\n\t\t\t\tRESTORE_FLAGS(flags);\n\t\t\t\tkfree((unsigned int)tty);\n\t\t\t\treturn NULL;\n\t\t\t}\n\t\t\tif(t->next) {\n\t\t\t\tt = t->next;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tt->next = tty;\n\t} else {\n\t\ttty_table = tty;\n\t}\n\tRESTORE_FLAGS(flags);\n\n\tmemset_b(tty, 0, sizeof(struct tty));\n\ttty_reset(tty);\n\ttty->dev = dev;\n\tfor(n = 0; n < MAX_TAB_COLS; n++) {\n\t\tif(!(n % TAB_SIZE)) {\n\t\t\ttty->tab_stop[n] = 1;\n\t\t} else {\n\t\t\ttty->tab_stop[n] = 0;\n\t\t}\n\t}\n\treturn tty;\n}\n\nvoid unregister_tty(struct tty *tty)\n{\n\tunsigned int flags;\n\tstruct tty *t;\n\n\tSAVE_FLAGS(flags); CLI();\n\tif(tty == tty_table) {\n\t\ttty_table = tty->next;\n\t} else {\n\t\tt = tty_table;\n\t\twhile(t->next != tty) {\n\t\t\tt = t->next;\n\t\t}\n\t\tt->next = tty->next;\n\t}\n\tkfree((unsigned int)tty);\n\tRESTORE_FLAGS(flags);\n}\n\nstruct tty *get_tty(__dev_t dev)\n{\n\tstruct tty *tty;\n\n\tif(!dev) {\n\t\treturn NULL;\n\t}\n\n\t/* /dev/console = system console */\n\tif(dev == SYSCON_DEV) {\n\t\tdev = (__dev_t)kparms.syscondev;\n\t}\n\n\t/* /dev/tty0 = current virtual console */\n\tif(dev == VCONSOLE_DEV) {\n\t\tdev = MKDEV(VCONSOLES_MAJOR, current_cons);\n\t}\n\n\t/* /dev/tty = controlling TTY device */\n\tif(dev == TTY_DEV) {\n\t\tif(!current->ctty) {\n\t\t\treturn NULL;\n\t\t}\n\t\tdev = current->ctty->dev;\n\t}\n\n\tfor(tty = tty_table; tty; tty = tty->next) {\n\t\tif(tty->dev == dev) {\n\t\t\treturn tty;\n\t\t}\n\t}\n\treturn NULL;\n}\n\nvoid disassociate_ctty(struct tty *tty)\n{\n\tstruct proc *p;\n\n\tif(!tty) {\n\t\treturn;\n\t}\n\n\t/* this tty is no longer the controlling tty of any session */\n\ttty->pgid = tty->sid = 0;\n\n\t/* clear the controlling tty for all processes in the same SID */\n\tFOR_EACH_PROCESS(p) {\n\t\tif(p->sid == current->sid) {\n\t\t\tp->ctty = NULL;\n\t\t}\n\t\tp = p->next;\n\t}\n\tkill_pgrp(current->pgid, SIGHUP, KERNEL);\n\tkill_pgrp(current->pgid, SIGCONT, KERNEL);\n}\n\nvoid termios_reset(struct tty *tty)\n{\n\ttty->kbd.mode = K_XLATE;\n\ttty->termios.c_iflag = ICRNL | IXON | IXOFF;\n\ttty->termios.c_oflag = OPOST | ONLCR;\n\ttty->termios.c_cflag = B9600 | CS8 | HUPCL | CREAD | CLOCAL;\n\ttty->termios.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN;\n\ttty->termios.c_line = 0;\n\ttty->termios.c_cc[VINTR]    = 3;\t/* ^C */\n\ttty->termios.c_cc[VQUIT]    = 28;\t/* ^\\ */\n\ttty->termios.c_cc[VERASE]   = BS;\t/* ^? (127) not '\\b' (^H) */\n\ttty->termios.c_cc[VKILL]    = 21;\t/* ^U */\n\ttty->termios.c_cc[VEOF]     = 4;\t/* ^D */\n\ttty->termios.c_cc[VTIME]    = 0;\n\ttty->termios.c_cc[VMIN]     = 1;\n\ttty->termios.c_cc[VSWTC]    = 0;\n\ttty->termios.c_cc[VSTART]   = 17;\t/* ^Q */\n\ttty->termios.c_cc[VSTOP]    = 19;\t/* ^S */\n\ttty->termios.c_cc[VSUSP]    = 26;\t/* ^Z */\n\ttty->termios.c_cc[VEOL]     = '\\n';\t/* ^J */\n\ttty->termios.c_cc[VREPRINT] = 18;\t/* ^R */\n\ttty->termios.c_cc[VDISCARD] = 15;\t/* ^O */\n\ttty->termios.c_cc[VWERASE]  = 23;\t/* ^W */\n\ttty->termios.c_cc[VLNEXT]   = 22;\t/* ^V */\n\ttty->termios.c_cc[VEOL2]    = 0;\t\n}\n\nvoid tty_deltab(struct tty *tty)\n{\n\tunsigned short int col, n, count;\n\tstruct cblock *cb;\n\tunsigned char ch;\n\n\tcb = tty->cooked_q.head;\n\tcol = count = 0;\n\n\twhile(cb) {\n\t\tfor(n = 0; n < cb->end_off; n++) {\n\t\t\tif(n >= cb->start_off) {\n\t\t\t\tch = cb->data[n];\n\t\t\t\tif(ch == '\\t') {\n\t\t\t\t\twhile(!tty->tab_stop[++col]);\n\t\t\t\t} else {\n\t\t\t\t\tcol++;\n\t\t\t\t\tif(ISCNTRL(ch) && !ISSPACE(ch) && tty->termios.c_lflag & ECHOCTL) {\n\t\t\t\t\t\tcol++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcol %= tty->winsize.ws_col;\n\t\t\t}\n\t\t}\n\t\tcb = cb->next;\n\t}\n\tcount = tty->column - col;\n\n\twhile(count--) {\n\t\tcharq_putchar(&tty->write_q, '\\b');\n\t\ttty->column--;\n\t}\n}\n\nvoid do_cook(struct tty *tty)\n{\n\tint n;\n\tunsigned char ch;\n\tstruct cblock *cb;\n\n\twhile(tty->read_q.count > 0) {\n\t\tch = charq_getchar(&tty->read_q);\n\n\t\tif((tty->termios.c_lflag & ISIG) && !(tty->flags & TTY_HAS_LNEXT)) {\n\t\t\tif(ch == tty->termios.c_cc[VINTR]) {\n\t\t\t\tif(!(tty->termios.c_lflag & NOFLSH)) {\n\t\t\t\t\tcharq_flush(&tty->read_q);\n\t\t\t\t\tcharq_flush(&tty->cooked_q);\n\t\t\t\t}\n\t\t\t\tif(tty->pgid > 0) {\n\t\t\t\t\tkill_pgrp(tty->pgid, SIGINT, KERNEL);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif(ch == tty->termios.c_cc[VQUIT]) {\n\t\t\t\tif(tty->pgid > 0) {\n\t\t\t\t\tkill_pgrp(tty->pgid, SIGQUIT, KERNEL);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif(ch == tty->termios.c_cc[VSUSP]) {\n\t\t\t\tif(tty->pgid > 0) {\n\t\t\t\t\tkill_pgrp(tty->pgid, SIGTSTP, KERNEL);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif(tty->termios.c_iflag & ISTRIP) {\n\t\t\tch = TOASCII(ch);\n\t\t}\n\t\tif(tty->termios.c_iflag & IUCLC) {\n\t\t\tif(ISUPPER(ch)) {\n\t\t\t\tch = TOLOWER(ch);\n\t\t\t}\n\t\t}\n\n\t\tif(!(tty->flags & TTY_HAS_LNEXT)) {\n\t\t\tif(ch == '\\r') {\n\t\t\t\tif(tty->termios.c_iflag & IGNCR) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif(tty->termios.c_iflag & ICRNL) {\n\t\t\t\t\tch = '\\n';\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif(ch == '\\n') {\n\t\t\t\t\tif(tty->termios.c_iflag & INLCR) {\n\t\t\t\t\t\tch = '\\r';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif(tty->termios.c_lflag & ICANON && !(tty->flags & TTY_HAS_LNEXT)) {\n\t\t\tif(ch == tty->termios.c_cc[VERASE] || ch == tty->termios.c_cc[VWERASE] || ch == tty->termios.c_cc[VKILL]) {\n\t\t\t\terase_char(tty, ch);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif(ch == tty->termios.c_cc[VREPRINT]) {\n\t\t\t\tout_char(tty, ch);\n\t\t\t\tcharq_putchar(&tty->write_q, '\\n');\n\t\t\t\tcb = tty->cooked_q.head;\n\t\t\t\twhile(cb) {\n\t\t\t\t\tfor(n = 0; n < cb->end_off; n++) {\n\t\t\t\t\t\tif(n >= cb->start_off) {\n\t\t\t\t\t\t\tout_char(tty, cb->data[n]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcb = cb->next;\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif(ch == tty->termios.c_cc[VLNEXT] && tty->termios.c_lflag & IEXTEN) {\n\t\t\t\ttty->flags |= TTY_HAS_LNEXT;\n\t\t\t\tif(tty->termios.c_lflag & ECHOCTL) {\n\t\t\t\t\tcharq_putchar(&tty->write_q, '^');\n\t\t\t\t\tcharq_putchar(&tty->write_q, '\\b');\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif(tty->termios.c_iflag & IXON) {\n\t\t\t\tif(ch == tty->termios.c_cc[VSTART]) {\n\t\t\t\t\tif(tty->start) {\n\t\t\t\t\t\ttty->start(tty);\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif(ch == tty->termios.c_cc[VSTOP]) {\n\t\t\t\t\tif(tty->stop) {\n\t\t\t\t\t\ttty->stop(tty);\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif(tty->termios.c_iflag & IXANY) {\n\t\t\t\t\tif(tty->start) {\n\t\t\t\t\t\ttty->start(tty);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/* FIXME: using ISSPACE here makes LNEXT working incorrectly */\n\t\tif(tty->termios.c_lflag & ICANON) {\n\t\t\tif(ISCNTRL(ch) && !ISSPACE(ch) && (tty->termios.c_lflag & ECHOCTL)) {\n\t\t\t\tout_char(tty, ch);\n\t\t\t\tcharq_putchar(&tty->cooked_q, ch);\n\t\t\t\ttty->flags &= ~TTY_HAS_LNEXT;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif(ch == '\\n') {\n\t\t\t\ttty->canon_data = 1;\n\t\t\t}\n\t\t}\n\n\t\tif(tty->termios.c_lflag & ECHO) {\n\t\t\tout_char(tty, ch);\n\t\t} else {\n\t\t\tif((tty->termios.c_lflag & ECHONL) && (ch == '\\n')) {\n\t\t\t\tout_char(tty, ch);\n\t\t\t}\n\t\t}\n\t\tcharq_putchar(&tty->cooked_q, ch);\n\t\ttty->flags &= ~TTY_HAS_LNEXT;\n\t}\n\tif(tty->output) {\n\t\ttty->output(tty);\n\t}\n\tif(!(tty->termios.c_lflag & ICANON) || ((tty->termios.c_lflag & ICANON) && tty->canon_data)) {\n\t\twakeup(&do_select);\n\t}\n\twakeup(&tty->read_q);\n}\n\nint tty_open(struct inode *i, struct fd *f)\n{\n\tint noctty_flag;\n\tstruct tty *tty, *otty;\n\tstruct inode *oi;\n\tstruct devpts_files *dp;\n\tint errno;\n\t \n\tnoctty_flag = f->flags & O_NOCTTY;\n\n\tif(i->rdev == TTY_DEV) {\n\t\tif(!current->ctty) {\n\t\t\treturn -ENXIO;\n\t\t}\n\t}\n\n\tif(i->rdev == VCONSOLE_DEV) {\n\t\tnoctty_flag = 1;\n\t}\n\n\tif(!(tty = get_tty(i->rdev))) {\n\t\tprintk(\"%s(): oops! (%x)\\n\", __FUNCTION__, i->rdev);\n\t\tprintk(\"_syscondev = %x\\n\", kparms.syscondev);\n\t\treturn -ENXIO;\n\t}\n\n\terrno = 0;\n\tif(tty->open) {\n\t\tif((errno = tty->open(tty)) < 0) {\n\t\t\treturn errno;\n\t\t}\n\t}\n\ttty->count++;\n\ttty->column = 0;\n\n\tf->private_data = tty;\n\n#ifdef CONFIG_UNIX98_PTYS\n\tif(i->rdev == PTMX_DEV) {\n\t\tdp = (struct devpts_files *)tty->driver_data;\n\t\toi = (struct inode *)dp->inode;\n\t\tif((otty = register_tty(oi->rdev))) {\n\t\t\totty->count++;\n\t\t\totty->driver_data = tty->driver_data;\n\t\t\totty->flags |= TTY_PTY_LOCK;\n\t\t\totty->link = tty;\n\t\t\t/* FIXME\n\t\t\totty->stop =\n\t\t\totty->start =\n\t\t\t*/\n\t\t\totty->deltab = tty_deltab;\n\t\t\totty->input = do_cook;\n\t\t\totty->output = pty_wakeup_read;\n\t\t\totty->open = pty_open;\n\t\t\totty->close = pty_close;\n\t\t\totty->ioctl = pty_ioctl;\n\t\t\tf->private_data = otty;\n\t\t} else {\n\t\t\tprintk(\"WARNING: %s(): unable to register pty slave (%d,%d).\\n\", __FUNCTION__, MAJOR(oi->rdev), MINOR(oi->rdev));\n\t\t\treturn -ENOMEM;\n\t\t}\n\t}\n#endif /* CONFIG_UNIX98_PTYS */\n\n\tif(SESS_LEADER(current) && !current->ctty && !noctty_flag && !tty->sid) {\n\t\tcurrent->ctty = tty;\n\t\ttty->sid = current->sid;\n\t\ttty->pgid = current->pgid;\n\t}\n\treturn 0;\n}\n\nint tty_close(struct inode *i, struct fd *f)\n{\n\tstruct proc *p;\n\tstruct tty *tty;\n\tint errno;\n\n\ttty = f->private_data;\n\tif(tty->close) {\n\t\tif((errno = tty->close(tty)) < 0) {\n\t\t\treturn errno;\n\t\t}\n\t}\n\ttty->count--;\n\tif(!tty->count) {\n\t\ttermios_reset(tty);\n\t\ttty->pgid = tty->sid = 0;\n\n\t\t/* this tty is no longer the controlling tty of any process */\n\t\tFOR_EACH_PROCESS(p) {\n\t\t\tif(p->ctty == tty) {\n\t\t\t\tp->ctty = NULL;\n\t\t\t}\n\t\t\tp = p->next;\n\t\t}\n\t}\n\treturn 0;\n}\n\nint tty_read(struct inode *i, struct fd *f, char *buffer, __size_t count)\n{\n\tunsigned int min;\n\tunsigned char ch;\n\tstruct tty *tty;\n\tstruct callout_req creq;\n\tint n;\n\n\ttty = f->private_data;\n\n\t/* only the foreground process group is allowed to read from the tty */\n\tif(current->ctty == tty && current->pgid != tty->pgid) {\n\t\tif(current->sigaction[SIGTTIN - 1].sa_handler == SIG_IGN || current->sigblocked & (1 << (SIGTTIN - 1)) || is_orphaned_pgrp(current->pgid)) {\n\t\t\treturn -EIO;\n\t\t}\n\t\tkill_pgrp(current->pgid, SIGTTIN, KERNEL);\n\t\treturn -ERESTART;\n\t}\n\n\tn = min = 0;\n\twhile(count > 0) {\n\t\tif(tty->kbd.mode == K_RAW || tty->kbd.mode == K_MEDIUMRAW) {\n\t\t\tn = 0;\n\t\t\twhile(n < count) {\n\t\t\t\tif((ch = charq_getchar(&tty->read_q))) {\n\t\t\t\t\tbuffer[n++] = ch;\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(n) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif(tty->flags & TTY_OTHER_CLOSED) {\n\t\t\tn = -EIO;\n\t\t\tbreak;\n\t\t}\n\n\t\tif(tty->termios.c_lflag & ICANON) {\n\t\t\tif((ch = LAST_CHAR(&tty->cooked_q))) {\n\t\t\t\tif(ch == '\\n' || ch == tty->termios.c_cc[VEOL] || ch == tty->termios.c_cc[VEOF] || (tty->termios.c_lflag & IEXTEN && ch == tty->termios.c_cc[VEOL2] && tty->termios.c_cc[VEOL2] != 0)) {\n\n\t\t\t\t\ttty->canon_data = 0;\n\t\t\t\t\t/* EOF is not passed to the reading process */\n\t\t\t\t\tif(ch == tty->termios.c_cc[VEOF]) {\n\t\t\t\t\t\tcharq_unputchar(&tty->cooked_q);\n\t\t\t\t\t}\n\n\t\t\t\t\twhile(n < count) {\n\t\t\t\t\t\tif((ch = charq_getchar(&tty->cooked_q))) {\n\t\t\t\t\t\t\tbuffer[n++] = ch;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tif(tty->termios.c_cc[VTIME] > 0) {\n\t\t\t\tunsigned int ini_ticks = CURRENT_TICKS;\n\t\t\t\tunsigned int timeout;\n\n\t\t\t\tif(!tty->termios.c_cc[VMIN]) {\n\t\t\t\t\t/* VTIME is measured in tenths of second */\n\t\t\t\t\ttimeout = tty->termios.c_cc[VTIME] * (HZ / 10);\n\n\t\t\t\t\twhile(CURRENT_TICKS - ini_ticks < timeout && !tty->cooked_q.count) {\n\t\t\t\t\t\tcreq.fn = wait_vtime_off;\n\t\t\t\t\t\tcreq.arg = (unsigned int)&tty->cooked_q;\n\t\t\t\t\t\tadd_callout(&creq, timeout);\n\t\t\t\t\t\tif(f->flags & O_NONBLOCK) {\n\t\t\t\t\t\t\treturn -EAGAIN;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(sleep(&tty->read_q, PROC_INTERRUPTIBLE)) {\n\t\t\t\t\t\t\treturn -EINTR;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\twhile(n < count) {\n\t\t\t\t\t\tif((ch = charq_getchar(&tty->cooked_q))) {\n\t\t\t\t\t\t\tbuffer[n++] = ch;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t} else {\n\t\t\t\t\tif(tty->cooked_q.count > 0) {\n\t\t\t\t\t\tif(n < MIN(tty->termios.c_cc[VMIN], count)) {\n\t\t\t\t\t\t\tch = charq_getchar(&tty->cooked_q);\n\t\t\t\t\t\t\tbuffer[n++] = ch;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(n >= MIN(tty->termios.c_cc[VMIN], count)) {\n\t\t\t\t\t\t\tdel_callout(&creq);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttimeout = tty->termios.c_cc[VTIME] * (HZ / 10);\n\t\t\t\t\t\tcreq.fn = wait_vtime_off;\n\t\t\t\t\t\tcreq.arg = (unsigned int)&tty->cooked_q;\n\t\t\t\t\t\tadd_callout(&creq, timeout);\n\t\t\t\t\t\tif(f->flags & O_NONBLOCK) {\n\t\t\t\t\t\t\tn = -EAGAIN;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(sleep(&tty->read_q, PROC_INTERRUPTIBLE)) {\n\t\t\t\t\t\t\tn = -EINTR;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(!tty->cooked_q.count) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile(tty->cooked_q.count > 0) {\n\t\t\t\t\tif(n < count) {\n\t\t\t\t\t\tch = charq_getchar(&tty->cooked_q);\n\t\t\t\t\t\tbuffer[n++] = ch;\n\t\t\t\t\t\tif(--tty->canon_data < 0) {\n\t\t\t\t\t\t\ttty->canon_data = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tmin++;\n\t\t\t\t}\n\t\t\t\tif(min >= tty->termios.c_cc[VMIN]) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif(f->flags & O_NONBLOCK) {\n\t\t\tn = -EAGAIN;\n\t\t\tbreak;\n\t\t}\n\t\tif(sleep(&tty->read_q, PROC_INTERRUPTIBLE)) {\n\t\t\tn = -EINTR;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif(n) {\n\t\ti->i_atime = CURRENT_TIME;\n\t}\n\treturn n;\n}\n\nint tty_write(struct inode *i, struct fd *f, const char *buffer, __size_t count)\n{\n\tunsigned char ch;\n\tstruct tty *tty;\n\tint n;\n\n\ttty = f->private_data;\n\n\t/* only the foreground process group is allowed to write to the tty */\n\tif(current->ctty == tty && current->pgid != tty->pgid) {\n\t\tif(tty->termios.c_lflag & TOSTOP) {\n\t\t\tif(current->sigaction[SIGTTIN - 1].sa_handler != SIG_IGN && !(current->sigblocked & (1 << (SIGTTIN - 1)))) {\n\t\t\t\tif(is_orphaned_pgrp(current->pgid)) {\n\t\t\t\t\treturn -EIO;\n\t\t\t\t}\n\t\t\t\tkill_pgrp(current->pgid, SIGTTOU, KERNEL);\n\t\t\t\treturn -ERESTART;\n\t\t\t}\n\t\t}\n\t}\n\n\tn = 0;\n\tfor(;;) {\n\t\tif(current->sigpending & ~current->sigblocked) {\n\t\t\treturn -ERESTART;\n\t\t}\n\t\twhile(count && n < count) {\n\t\t\tch = *(buffer + n);\n\t\t\t/* FIXME: check if *(buffer + n) address is valid */\n\t\t\tif(opost(tty, ch) < 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tn++;\n\t\t}\n\t\tif(tty->output) {\n\t\t\ttty->output(tty);\n\t\t}\n\t\tif(n == count) {\n\t\t\tbreak;\n\t\t}\n\t\tif(f->flags & O_NONBLOCK) {\n\t\t\tn = -EAGAIN;\n\t\t\tbreak;\n\t\t}\n\t\tif(tty->write_q.count > 0) {\n\t\t\tif(sleep(&tty->write_q, PROC_INTERRUPTIBLE)) {\n\t\t\t\tn = -EINTR;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif(need_resched) {\n\t\t\tdo_sched();\n\t\t}\n\t}\n\n\tif(n) {\n\t\ti->i_mtime = CURRENT_TIME;\n\t}\n\treturn n;\n}\n\n/* FIXME: http://www.lafn.org/~dave/linux/termios.txt (doc/termios.txt) */\nint tty_ioctl(struct inode *i, struct fd *f, int cmd, unsigned int arg)\n{\n\tstruct proc *p;\n\tstruct tty *tty;\n\tint errno;\n\n\ttty = f->private_data;\n\terrno = 0;\n\n\tswitch(cmd) {\n\t\t/*\n\t\t * Fetch and store the current terminal parameters to a termios\n\t\t * structure pointed to by the argument.\n\t\t */\n\t\tcase TCGETS:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(struct termios)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tmemcpy_b((struct termios *)arg, &tty->termios, sizeof(struct termios));\n\t\t\tbreak;\n\n\t\t/*\n\t\t * Set the current terminal parameters according to the\n\t\t * values in the termios structure pointed to by the argument.\n\t\t */\n\t\tcase TCSETS:\n\t\t\tif((errno = check_user_area(VERIFY_READ, (void *)arg, sizeof(struct termios)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tset_termios(tty, (struct termios *)arg);\n\t\t\tbreak;\n\n\t\t/*\n\t\t * Same as TCSETS except it doesn't take effect until all\n\t\t * the characters queued for output have been transmitted.\n\t\t */\n\t\tcase TCSETSW:\n\t\t\tif((errno = check_user_area(VERIFY_READ, (void *)arg, sizeof(struct termios)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\t/* not tested */\n\t\t\twhile(tty->write_q.count) {\n\t\t\t\tif(sleep(&tty->write_q, PROC_INTERRUPTIBLE)) {\n\t\t\t\t\treturn -EINTR;\n\t\t\t\t}\n\t\t\t\tdo_sched();\n\t\t\t}\n\t\t\tset_termios(tty, (struct termios *)arg);\n\t\t\tbreak;\n\n\t\t/*\n\t\t * Same as TCSETSW except that all characters queued for\n\t\t * input are discarded.\n\t\t */\n\t\tcase TCSETSF:\n\t\t\tif((errno = check_user_area(VERIFY_READ, (void *)arg, sizeof(struct termios)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\t/* not tested */\n\t\t\twhile(tty->write_q.count) {\n\t\t\t\tif(sleep(&tty->write_q, PROC_INTERRUPTIBLE)) {\n\t\t\t\t\treturn -EINTR;\n\t\t\t\t}\n\t\t\t\tdo_sched();\n\t\t\t}\n\t\t\tset_termios(tty, (struct termios *)arg);\n\t\t\tcharq_flush(&tty->read_q);\n\t\t\tbreak;\n\n\t\t/*\n\t\t * Fetch and store the current terminal parameters to a termio\n\t\t * structure pointed to by the argument.\n\t\t */\n\t\tcase TCGETA:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(struct termio)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\ttermios2termio(&tty->termios, (struct termio *)arg);\n\t\t\tbreak;\n\n\t\t/*\n\t\t * Set the current terminal parameters according to the\n\t\t * values in the termio structure pointed to by the argument.\n\t\t */\n\t\tcase TCSETA:\n\t\t\tif((errno = check_user_area(VERIFY_READ, (void *)arg, sizeof(struct termio)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tset_termio(tty, (struct termio *)arg);\n\t\t\tbreak;\n\n\t\t/*\n\t\t * Same as TCSET except it doesn't take effect until all\n\t\t * the characters queued for output have been transmitted.\n\t\t */\n\t\tcase TCSETAW:\n\t\t\tif((errno = check_user_area(VERIFY_READ, (void *)arg, sizeof(struct termio)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\t/* not tested */\n\t\t\twhile(tty->write_q.count) {\n\t\t\t\tif(sleep(&tty->write_q, PROC_INTERRUPTIBLE)) {\n\t\t\t\t\treturn -EINTR;\n\t\t\t\t}\n\t\t\t\tdo_sched();\n\t\t\t}\n\t\t\tset_termio(tty, (struct termio *)arg);\n\t\t\tbreak;\n\n\t\t/*\n\t\t * Same as TCSETAW except that all characters queued for\n\t\t * input are discarded.\n\t\t */\n\t\tcase TCSETAF:\n\t\t\tif((errno = check_user_area(VERIFY_READ, (void *)arg, sizeof(struct termio)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\t/* not tested */\n\t\t\twhile(tty->write_q.count) {\n\t\t\t\tif(sleep(&tty->write_q, PROC_INTERRUPTIBLE)) {\n\t\t\t\t\treturn -EINTR;\n\t\t\t\t}\n\t\t\t\tdo_sched();\n\t\t\t}\n\t\t\tset_termio(tty, (struct termio *)arg);\n\t\t\tcharq_flush(&tty->read_q);\n\t\t\tbreak;\n\n\t\t/* Perform start/stop control */\n\t\tcase TCXONC:\n\t\t\tswitch(arg) {\n\t\t\t\tcase TCOOFF:\n\t\t\t\t\tif(tty->stop) {\n\t\t\t\t\t\ttty->stop(tty);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase TCOON:\n\t\t\t\t\tif(tty->start) {\n\t\t\t\t\t\ttty->start(tty);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase TCFLSH:\n\t\t\tswitch(arg) {\n\t\t\t\tcase TCIFLUSH:\n\t\t\t\t\tcharq_flush(&tty->read_q);\n\t\t\t\t\tcharq_flush(&tty->cooked_q);\n\t\t\t\t\tbreak;\n\t\t\t\tcase TCOFLUSH:\n\t\t\t\t\tcharq_flush(&tty->write_q);\n\t\t\t\t\tbreak;\n\t\t\t\tcase TCIOFLUSH:\n\t\t\t\t\tcharq_flush(&tty->read_q);\n\t\t\t\t\tcharq_flush(&tty->cooked_q);\n\t\t\t\t\tcharq_flush(&tty->write_q);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase TIOCSCTTY:\n\t\t\tif(SESS_LEADER(current) && (current->sid == tty->sid)) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif(!SESS_LEADER(current) || current->ctty) {\n\t\t\t\treturn -EPERM;\n\t\t\t}\n\t\t\tif(tty->sid) {\n\t\t\t\tif((arg == 1) && IS_SUPERUSER) {\n\t\t\t\t\tFOR_EACH_PROCESS(p) {\n\t\t\t\t\t\tif(p->ctty == tty) {\n\t\t\t\t\t\t\tp->ctty = NULL;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tp = p->next;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\treturn -EPERM;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcurrent->ctty = tty;\n\t\t\ttty->sid = current->sid;\n\t\t\ttty->pgid = current->pgid;\n\t\t\tbreak;\n\n\t\t/*\n\t\t * Get the process group ID of the '__pid_t' pointed to by\n\t\t * the arg to the foreground processes group ID.\n\t\t */\n\t\tcase TIOCGPGRP:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(__pid_t)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tmemcpy_b((void *)arg, &tty->pgid, sizeof(__pid_t));\n\t\t\tbreak;\n\n\t\t/*\n\t\t * Associate the process pointed to by '__pid_t' in the arg to\n\t\t * the value of the terminal.\n\t\t */\n\t\tcase TIOCSPGRP:\n\t\t\tif(arg < 1) {\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\tif((errno = check_user_area(VERIFY_READ, (void *)arg, sizeof(__pid_t)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tmemcpy_b(&tty->pgid, (void *)arg, sizeof(__pid_t));\n\t\t\tbreak;\n\n\t\t/*\n\t\t * The session ID of the terminal is fetched and stored in\n\t\t * the '__pid_t' pointed to by the arg.\n\t\tcase TIOCSID:\tFIXME\n\t\t */\n\n\t\t/*\n\t\t * The terminal drivers notion of terminal size is stored in\n\t\t * the 'winsize' structure pointed to by the arg.\n\t\t */\n\t\tcase TIOCGWINSZ:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(struct winsize)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tmemcpy_b((void *)arg, &tty->winsize, sizeof(struct winsize));\n\t\t\tbreak;\n\n\t\t/*\n\t\t * The terminal drivers notion of the terminal size is set\n\t\t * to value in the 'winsize' structure pointed to by the arg.\n\t\t */\n\t\tcase TIOCSWINSZ:\n\t\t{\n\t\t\tstruct winsize *ws = (struct winsize *)arg;\n\t\t\tshort int changed;\n\n\t\t\tif((errno = check_user_area(VERIFY_READ, (void *)arg, sizeof(struct winsize)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tchanged = 0;\n\t\t\tif(tty->winsize.ws_row != ws->ws_row ||\n\t\t\t   tty->winsize.ws_col != ws->ws_col ||\n\t\t\t   tty->winsize.ws_xpixel != ws->ws_xpixel ||\n\t\t\t   tty->winsize.ws_ypixel != ws->ws_ypixel) {\n\t\t\t\tchanged = 1;\n\t\t\t}\n\t\t\ttty->winsize.ws_row = ws->ws_row;\n\t\t\ttty->winsize.ws_col = ws->ws_col;\n\t\t\ttty->winsize.ws_xpixel = ws->ws_xpixel;\n\t\t\ttty->winsize.ws_ypixel = ws->ws_ypixel;\n\t\t\tif(changed) {\n\t\t\t\tkill_pgrp(tty->pgid, SIGWINCH, KERNEL);\n\t\t\t}\n\t\t}\n\t\t\tbreak;\n\t\tcase TIOCNOTTY:\n\t\t\tif(current->ctty != tty) {\n\t\t\t\treturn -ENOTTY;\n\t\t\t}\n\t\t\tif(SESS_LEADER(current)) {\n\t\t\t\tdisassociate_ctty(tty);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase TIOCLINUX:\n\t\t{\n\t\t\tint val = *(unsigned char *)arg;\n\t\t\tif((errno = check_user_area(VERIFY_READ, (void *)arg, sizeof(unsigned char)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tswitch(val) {\n\t\t\t\tcase 12:\t/* get current console */\n\t\t\t\t\treturn current_cons;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\treturn -EINVAL;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase TIOCINQ:\n\t\t{\n\t\t\tint *val = (int *)arg;\n\t\t\tif(tty->termios.c_lflag & ICANON) {\n\t\t\t\t*val = tty->cooked_q.count;\n\t\t\t} else {\n\t\t\t\t*val = tty->read_q.count;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tdefault:\n\t\t\terrno = vt_ioctl(tty, cmd, arg);\n\t\t\tif(tty->ioctl) {\n\t\t\t\terrno = tty->ioctl(tty, f, cmd, arg);\n\t\t\t}\n\t}\n\treturn errno;\n}\n\n__loff_t tty_llseek(struct inode *i, __loff_t offset)\n{\n\treturn -ESPIPE;\n}\n\nint tty_select(struct inode *i, struct fd *f, int flag)\n{\n\tstruct tty *tty;\n\n\ttty = f->private_data;\n\n\tswitch(flag) {\n\t\tcase SEL_R:\n\t\t\tif(tty->cooked_q.count > 0) {\n\t\t\t\tif(!(tty->termios.c_lflag & ICANON) || ((tty->termios.c_lflag & ICANON) && tty->canon_data)) {\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(tty->read_q.count > 0) {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase SEL_W:\n\t\t\tif(!tty->write_q.count) {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tbreak;\n\t}\n\treturn 0;\n}\n\nvoid tty_init(void)\n{\n\tcharq_init();\n\ttty_table = NULL;\n}\n"
  },
  {
    "path": "drivers/char/vt.c",
    "content": "/*\n * fiwix/drivers/char/vt.c\n *\n * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/console.h>\n#include <fiwix/keyboard.h>\n#include <fiwix/tty.h>\n#include <fiwix/vt.h>\n#include <fiwix/kd.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nint kbdmode = 0;\n\nint vt_ioctl(struct tty *tty, int cmd, unsigned int arg)\n{\n\tstruct vconsole *vc;\n\tint n, errno;\n\n\t/* only virtual consoles support the following ioctl commands */\n\tif(MAJOR(tty->dev) != VCONSOLES_MAJOR) {\n\t\treturn -ENXIO;\n\t}\n\n\tvc = (struct vconsole *)tty->driver_data;\n\n\tswitch(cmd) {\n\t\tcase KDGETLED:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned char)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tmemset_b((void *)arg, vc->led_status, sizeof(char));\n\t\t\tbreak;\n\n\t\tcase KDSETLED:\n\t\t\tif(arg > 7) {\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\tvc->led_status = arg;\n\t\t\tset_leds(vc->led_status);\n\t\t\tbreak;\n\n\t\t/* FIXME: implement KDGKBLED and KDSKBLED\n\t\t * it will need to convert 'scrlock, numlock, capslock' into led_flags.\n\t\t */\n\n\t\tcase KDGKBTYPE:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned char)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tmemset_b((void *)arg, KB_101, sizeof(char));\n\t\t\tbreak;\n\n\t\tcase KDSETMODE:\n\t\t\tif(arg != KD_TEXT && arg != KD_GRAPHICS) {\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\tif(vc->vc_mode != arg) {\n\t\t\t\tvc->vc_mode = arg;\n\t\t\t\tif(arg == KD_GRAPHICS) {\n\t\t\t\t\tvideo.blank_screen(vc);\n\t\t\t\t} else {\n\t\t\t\t\tunblank_screen(vc);\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase KDGETMODE:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned char)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tmemset_b((void *)arg, vc->vc_mode, sizeof(char));\n\t\t\tbreak;\n\n\t\tcase KDGKBMODE:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned char)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tmemset_b((void *)arg, tty->kbd.mode, sizeof(unsigned char));\n\t\t\tbreak;\n\n\t\tcase KDSKBMODE:\n\t\t\tif(arg != K_RAW && arg != K_XLATE && arg != K_MEDIUMRAW) {\n\t\t\t\targ = K_XLATE;\n\t\t\t}\n\t\t\ttty->kbd.mode = arg;\n\t\t\tcharq_flush(&tty->read_q);\n\t\t\tbreak;\n\n\t\tcase KDSKBENT:\n\t\t{\n\t\t\tstruct kbentry *k = (struct kbentry *)arg;\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, (void *)k, sizeof(struct kbentry)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tif(k->kb_table < NR_MODIFIERS) {\n\t\t\t\tif(k->kb_index < NR_SCODES) {\n\t\t\t\t\tkeymap[(k->kb_index * NR_MODIFIERS) + k->kb_table] = k->kb_value;\n\t\t\t\t} else {\n\t\t\t\t\treturn -EINVAL;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tprintk(\"%s(): kb_table value '%d' not supported.\\n\", __FUNCTION__, k->kb_table);\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t}\n\t\t\tbreak;\n\n\t\tcase VT_OPENQRY:\n\t\t{\n\t\t\tint *val = (int *)arg;\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned int)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tfor(n = 1; n < NR_VCONSOLES + 1; n++) {\n\t\t\t\ttty = get_tty(MKDEV(VCONSOLES_MAJOR, n));\n\t\t\t\tif(!tty->count) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t*val = (n < NR_VCONSOLES + 1 ? n : -1);\n\t\t}\n\t\t\tbreak;\n\n\t\tcase VT_GETMODE:\n\t\t{\n\t\t\tstruct vt_mode *vt_mode = (struct vt_mode *)arg;\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, (void *)vt_mode, sizeof(struct vt_mode)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tmemcpy_b(vt_mode, &vc->vt_mode, sizeof(struct vt_mode));\n\t\t}\n\t\t\tbreak;\n\n\t\tcase VT_SETMODE:\n\t\t{\n\t\t\tstruct vt_mode *vt_mode = (struct vt_mode *)arg;\n\t\t\tif((errno = check_user_area(VERIFY_READ, (void *)vt_mode, sizeof(struct vt_mode)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tif(vt_mode->mode != VT_AUTO && vt_mode->mode != VT_PROCESS) {\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\tmemcpy_b(&vc->vt_mode, vt_mode, sizeof(struct vt_mode));\n\t\t\tvc->vt_mode.frsig = 0;\t/* ignored */\n\t\t\ttty->pid = current->pid;\n\t\t\tvc->switchto_tty = 0;\n\t\t}\n\t\t\tbreak;\n\n\t\tcase VT_GETSTATE:\n\t\t{\n\t\t\tstruct vt_stat *vt_stat = (struct vt_stat *)arg;\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, (void *)vt_stat, sizeof(struct vt_stat)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tvt_stat->v_active = current_cons;\n\t\t\tvt_stat->v_state = 1;\t/* /dev/tty0 is always opened */\n\t\t\tfor(n = 1; n < NR_VCONSOLES + 1; n++) {\n\t\t\t\ttty = get_tty(MKDEV(VCONSOLES_MAJOR, n));\n\t\t\t\tif(tty->count) {\n\t\t\t\t\tvt_stat->v_state |= (1 << n);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t\tbreak;\n\n\t\tcase VT_RELDISP:\n\t\t\tif(vc->vt_mode.mode != VT_PROCESS) {\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\tif(vc->switchto_tty < 0) {\n\t\t\t\tif(arg != VT_ACKACQ) {\n\t\t\t\t\treturn -EINVAL;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif(arg) {\n\t\t\t\t\tint switchto_tty;\n\t\t\t\t\tswitchto_tty = vc->switchto_tty;\n\t\t\t\t\tvc->switchto_tty = -1;\n\t\t\t\t\tvconsole_select_final(switchto_tty);\n\t\t\t\t} else {\n\t\t\t\t\tvc->switchto_tty = -1;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase VT_ACTIVATE:\n\t\t\tif(current_cons == MINOR(tty->dev) || IS_SUPERUSER) {\n\t\t\t\tif(!arg || arg > NR_VCONSOLES) {\n\t\t\t\t\treturn -ENXIO;\n\t\t\t\t}\n\t\t\t\tvconsole_select(--arg);\n\t\t\t} else {\n\t\t\t\treturn -EPERM;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase VT_WAITACTIVE:\n\t\t\tif(current_cons == MINOR(tty->dev) || IS_SUPERUSER) {\n\t\t\t\tif(current_cons == MINOR(tty->dev)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif(!arg || arg > NR_VCONSOLES) {\n\t\t\t\t\treturn -ENXIO;\n\t\t\t\t}\n\t\t\t\tprintk(\"ACTIVATING another tty!! (cmd = 0x%x)\\n\", cmd);\n\t\t\t} else {\n\t\t\t\treturn -EPERM;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\treturn -EINVAL;\n\t}\n\treturn 0;\n}\n"
  },
  {
    "path": "drivers/pci/Makefile",
    "content": "# fiwix/drivers/pci/Makefile\n#\n# Copyright 2022, Jordi Sanfeliu. All rights reserved.\n# Distributed under the terms of the Fiwix License.\n#\n\n.c.o:\n\t$(CC) $(CFLAGS) -c -o $@ $<\n\nOBJS = pci.o\n\nall:\t$(OBJS)\n\nclean:\n\trm -f *.o\n\n"
  },
  {
    "path": "drivers/pci/pci.c",
    "content": "/*\n * fiwix/drivers/pci/pci.c\n *\n * Copyright 2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/config.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n#include <fiwix/pci.h>\n#include <fiwix/mm.h>\n\n#ifdef CONFIG_PCI\nstruct pci_device *pci_device_table;\n\n/* supported device classes only */\nstatic const char *get_strclass(unsigned short int class)\n{\n\tswitch(class) {\n\t\tcase PCI_CLASS_STORAGE_IDE:\t\treturn \"IDE interface\";\n\t\tcase PCI_CLASS_DISPLAY_VGA:\t\treturn \"VGA Display controller\";\n\t\tcase PCI_CLASS_COMMUNICATION_SERIAL:\treturn \"Serial controller\";\n\t}\n\treturn NULL;\n}\n\nstatic const char *get_strvendor_id(unsigned short int vendor_id)\n{\n#ifdef CONFIG_PCI_NAMES\n\tswitch(vendor_id) {\n\t\tcase PCI_VENDOR_ID_BOCHS:\t\treturn \"QEMU\";\n\t}\n#endif /* CONFIG_PCI_NAMES */\n\treturn NULL;\n}\n\nstatic const char *get_strdevice_id(unsigned short int device_id)\n{\n#ifdef CONFIG_PCI_NAMES\n\tswitch(device_id) {\n\t\tcase PCI_DEVICE_ID_BGA:\t\t\treturn \"Bochs Graphics Adapter\";\n\t}\n#endif /* CONFIG_PCI_NAMES */\n\treturn NULL;\n}\n\nstatic unsigned int get_addr(int bus, int dev, int func, int offset)\n{\n\tunsigned int addr;\n\n\taddr = (unsigned int)(0x80000000 |\n\t\t(bus << 16) |\n\t\t(dev << 11) |\n\t\t(func << 8) |\n\t\t(offset & 0xFC));\n\n\treturn addr;\n}\n\nstatic int is_mechanism_1_supported(void)\n{\n\tunsigned int orig, value;\n\n\torig = inport_l(PCI_ADDRESS);\n\n\toutport_l(PCI_ADDRESS, 0x80000000);\n\tvalue = inport_l(PCI_ADDRESS);\n\tif(value == 0x80000000) {\n\t\treturn 1;\n\t}\n\n\toutport_l(PCI_ADDRESS, orig);\n\treturn 0;\n}\n\nstatic void add_pci_device(struct pci_device *pci_dev)\n{\n\tstruct pci_device *pdt;\n\n\tif(!(pdt = (struct pci_device *)kmalloc(sizeof(struct pci_device)))) {\n\t\treturn;\n\t}\n\n\t*pdt = *pci_dev;\n\tif(!pci_device_table) {\n\t\tpci_device_table = pdt;\n\t} else {\n\t\tpdt->prev = pci_device_table->prev;\n\t\tpci_device_table->prev->next = pdt;\n\t}\n\tpci_device_table->prev = pdt;\n}\n\nstatic void scan_bus(void)\n{\n\tint n, b, d, f;\n\tunsigned int vendor_id, device_id, class;\n\tunsigned char hdr_type, irq, prog_if;\n\tstruct pci_device pci_dev, *pd;\n\tunsigned int reg, addr, val;\n\tunsigned short int cmd;\n\n\tfor(b = 0; b < PCI_MAX_BUS; b++) {\n\t\tfor(d = 0; d < PCI_MAX_DEV; d++) {\n\t\t\tfor(f = 0; f < PCI_MAX_FUNC; f++) {\n\t\t\t\tmemset_b(&pci_dev, 0, sizeof(struct pci_device));\n\t\t\t\tpci_dev.bus = b;\n\t\t\t\tpci_dev.dev = d;\n\t\t\t\tpci_dev.func = f;\n\n\t\t\t\tvendor_id = pci_read_short(&pci_dev, PCI_VENDOR_ID);\n\t\t\t\tif(!vendor_id || vendor_id == 0xFFFF) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tdevice_id = pci_read_short(&pci_dev, PCI_DEVICE_ID);\n\t\t\t\tprog_if = pci_read_char(&pci_dev, PCI_PROG_IF);\n\t\t\t\tclass = pci_read_short(&pci_dev, PCI_CLASS_DEVICE);\n\t\t\t\thdr_type = pci_read_char(&pci_dev, PCI_HEADER_TYPE);\n\t\t\t\tirq = pci_read_char(&pci_dev, PCI_INTERRUPT_LINE);\n\n\t\t\t\tprintk(\"\\t  b:%02x d:%02x f:%d\", b, d, f);\n\t\t\t\tif(irq) {\n\t\t\t\t\tprintk(\"   %3d\", irq);\n\t\t\t\t} else {\n\t\t\t\t\tprintk(\"     -\");\n\t\t\t\t}\n\t\t\t\tprintk(\"\\t%04x:%04x %04x%02x\", vendor_id, device_id, class, (int)prog_if);\n\t\t\t\tpci_dev.name = get_strclass(class);\n\t\t\t\tprintk(\" - %s\\n\", pci_dev.name ? pci_dev.name : \"Unknown\");\n\t\t\t\tpci_dev.vendor_id = vendor_id;\n\t\t\t\tpci_dev.device_id = device_id;\n\t\t\t\tpci_dev.class = class;\n\t\t\t\tpci_dev.hdr_type = hdr_type;\n\t\t\t\tpci_dev.irq = irq;\n\t\t\t\tpci_dev.command = pci_read_short(&pci_dev, PCI_COMMAND);\n\t\t\t\tpci_dev.status = pci_read_short(&pci_dev, PCI_STATUS);\n\t\t\t\tpci_dev.rev = pci_read_char(&pci_dev, PCI_REVISION_ID);\n\t\t\t\tpci_dev.prog_if = prog_if;\n\t\t\t\tpci_dev.cline_size = pci_read_char(&pci_dev, PCI_CACHE_LINE_SIZE);\n\t\t\t\tpci_dev.latency = pci_read_char(&pci_dev, PCI_LATENCY_TIMER);\n\t\t\t\tpci_dev.bist = pci_read_char(&pci_dev, PCI_BIST);\n\t\t\t\tpci_dev.pin = pci_read_char(&pci_dev, PCI_INTERRUPT_PIN);\n\t\t\t\tpci_dev.min_gnt = pci_read_char(&pci_dev, PCI_MIN_GRANT);\n\t\t\t\tpci_dev.max_lat = pci_read_char(&pci_dev, PCI_MAX_LATENCY);\n\n\t\t\t\tadd_pci_device(&pci_dev);\n\t\t\t\tif(!f && !(hdr_type & 0x80)) {\n\t\t\t\t\tbreak;\t/* no more functions in this device */\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/* get BARs */\n\tpd = pci_device_table;\n\twhile(pd) {\n\t\t/* only normal PCI devices (bridges are not supported) */\n\t\tif(pd->hdr_type != PCI_HEADER_TYPE_NORMAL) {\n\t\t\tpd = pd->next;\n\t\t\tcontinue;\n\t\t}\n\n\t\t/* disable I/O space and address space */\n\t\tcmd = pci_read_short(pd, PCI_COMMAND);\n\t\tpci_write_short(pd, PCI_COMMAND, cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER));\n\n\t\t/* read up to 6 BARs */\n\t\tfor(n = 0; n < 6; n++) {\n\t\t\treg = PCI_BASE_ADDR_0 + (n * 4);\n\n\t\t\t/* save the original value */\n\t\t\taddr = pci_read_long(pd, reg);\n\n\t\t\tpci_write_long(pd, reg, ~0);\n\t\t\tval = pci_read_long(pd, reg);\n\n\t\t\t/* restore the original value */\n\t\t\tpci_write_long(pd, reg, addr);\n\n\t\t\tif(!val || val == 0xFFFFFFFF) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tpd->obar[n] = addr;\n\t\t\tif(addr & PCI_BASE_ADDR_SPACE_IO) {\n\t\t\t\taddr &= PCI_BASE_ADDR_IO_MASK;\n\t\t\t\tpd->flags[n] |= PCI_F_ADDR_SPACE_IO;\n\t\t\t\tval = (~(val & ~0x1)) + 1;\n\t\t\t} else {\n\t\t\t\t/* memory mapped */\n\t\t\t\tif(addr & PCI_BASE_ADDR_MEM_PREF) {\n\t\t\t\t\tpd->flags[n] |= PCI_F_ADDR_SPACE_PREFET;\n\t\t\t\t}\n\t\t\t\tif((addr & PCI_BASE_ADDR_TYPE_MASK) == PCI_BASE_ADDR_TYPE_32) {\n\t\t\t\t\tpd->flags[n] |= PCI_F_ADDR_MEM_32;\n\t\t\t\t} \n\t\t\t\tif((addr & PCI_BASE_ADDR_TYPE_MASK) == PCI_BASE_ADDR_TYPE_64) {\n\t\t\t\t\tpd->flags[n] |= PCI_F_ADDR_MEM_64;\n\t\t\t\t} \n\t\t\t\taddr &= PCI_BASE_ADDR_MEM_MASK;\n\t\t\t\tpd->flags[n] |= PCI_F_ADDR_SPACE_MEM;\n\t\t\t\tval = (~(val & ~0xF)) + 1;\n\t\t\t}\n\t\t\tpd->bar[n] = addr;\n\t\t\tpd->size[n] = val;\n\t\t}\n\n\t\t/* restore I/O space and address space */\n\t\tpci_write_short(pd, PCI_COMMAND, cmd);\n\n\t\tpd = pd->next;\n\t}\n}\n\nunsigned char pci_read_char(struct pci_device *pci_dev, int offset)\n{\n\tunsigned char retval;\n\n\toutport_l(PCI_ADDRESS, get_addr(pci_dev->bus, pci_dev->dev, pci_dev->func, offset));\n\tretval = inport_l(PCI_DATA) >> ((offset & 3) * 8) & 0xFF;\n\treturn retval;\n}\n\nunsigned short int pci_read_short(struct pci_device *pci_dev, int offset)\n{\n\tunsigned short int retval;\n\n\toutport_l(PCI_ADDRESS, get_addr(pci_dev->bus, pci_dev->dev, pci_dev->func, offset));\n\tretval = inport_l(PCI_DATA) >> ((offset & 2) * 8) & 0xFFFF;\n\treturn retval;\n}\n\nunsigned int pci_read_long(struct pci_device *pci_dev, int offset)\n{\n\tunsigned int retval;\n\n\toutport_l(PCI_ADDRESS, get_addr(pci_dev->bus, pci_dev->dev, pci_dev->func, offset));\n\tretval = inport_l(PCI_DATA) >> ((offset & 2) * 8);\n\treturn retval;\n}\n\nvoid pci_write_char(struct pci_device *pci_dev, int offset, unsigned char buf)\n{\n\toutport_l(PCI_ADDRESS, get_addr(pci_dev->bus, pci_dev->dev, pci_dev->func, offset));\n\toutport_b(PCI_DATA, buf);\n}\n\nvoid pci_write_short(struct pci_device *pci_dev, int offset, unsigned short int buf)\n{\n\toutport_l(PCI_ADDRESS, get_addr(pci_dev->bus, pci_dev->dev, pci_dev->func, offset));\n\toutport_w(PCI_DATA, buf);\n}\n\nvoid pci_write_long(struct pci_device *pci_dev, int offset, unsigned int buf)\n{\n\toutport_l(PCI_ADDRESS, get_addr(pci_dev->bus, pci_dev->dev, pci_dev->func, offset));\n\toutport_l(PCI_DATA, buf);\n}\n\nvoid pci_show_desc(struct pci_device *pci_dev)\n{\n\tconst char *name;\n\n\tprintk(\"\\t\\t\\t\\tpci=b:%02x d:%02x f:%d, rev=0x%02x\\n\", pci_dev->bus, pci_dev->dev, pci_dev->func, pci_dev->rev);\n\tif((name = get_strdevice_id(pci_dev->device_id))) {\n\t\tprintk(\"\\t\\t\\t\\t\");\n\t\tprintk(\"desc=%s \", name);\n\t\tif((name = get_strvendor_id(pci_dev->vendor_id))) {\n\t\t\tprintk(\"(%s)\", name);\n\t\t}\n\t\tprintk(\"\\n\");\n\t}\n}\n\nvoid pci_init(void)\n{\n\tif(!is_mechanism_1_supported()) {\n\t\treturn;\n\t}\n\n\tpci_device_table = NULL;\n\tprintk(\"pci       0x%04x-0x%04x\", PCI_ADDRESS, PCI_DATA + sizeof(unsigned int) - 1);\n\tprintk(\"     -\\tbus range=0-%d, configuration type=1\\n\", PCI_MAX_BUS - 1);\n\tscan_bus();\n}\n#endif /* CONFIG_PCI */\n"
  },
  {
    "path": "drivers/video/Makefile",
    "content": "# fiwix/drivers/video/Makefile\n#\n# Copyright 2021-2022, Jordi Sanfeliu. All rights reserved.\n# Distributed under the terms of the Fiwix License.\n#\n\n.c.o:\n\t$(CC) $(CFLAGS) -c -o $@ $<\n\nOBJS = video.o vgacon.o fbcon.o bga.o fonts.o\n\nall:\t$(OBJS)\n\nclean:\n\trm -f *.o\n\n"
  },
  {
    "path": "drivers/video/bga.c",
    "content": "/*\n * fiwix/drivers/video/bga.c\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/kparms.h>\n#include <fiwix/config.h>\n#include <fiwix/bga.h>\n#include <fiwix/pci.h>\n#include <fiwix/console.h>\n#include <fiwix/mm.h>\n#include <fiwix/string.h>\n#include <fiwix/stdio.h>\n\n#ifdef CONFIG_PCI\n#ifdef CONFIG_BGA\nstatic void bga_write_register(int index, int data)\n{\n\toutport_w(VBE_DISPI_IOPORT_INDEX, index);\n\toutport_w(VBE_DISPI_IOPORT_DATA, data);\n}\n\nstatic unsigned short int bga_read_register(unsigned short int cmd)\n{\n\toutport_w(VBE_DISPI_IOPORT_INDEX, cmd);\n\treturn inport_w(VBE_DISPI_IOPORT_DATA);\n}\n\nstatic int setup_bga_device(struct pci_device *pci_dev)\n{\n\tunsigned short int cmd;\n\tint xres, yres, bpp;\n\n\tif(!(*kparms.bgaresolution)) {\n\t\treturn 0;\n\t}\n\n\t/* prepare to switch to the resolution requested */\n\tbga_write_register(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);\n\tbga_write_register(VBE_DISPI_INDEX_XRES, video.fb_width);\n\tbga_write_register(VBE_DISPI_INDEX_YRES, video.fb_height);\n\tbga_write_register(VBE_DISPI_INDEX_BPP, video.fb_bpp);\n\n\t/* check if the values were accepted */\n\txres = bga_read_register(VBE_DISPI_INDEX_XRES);\n\tyres = bga_read_register(VBE_DISPI_INDEX_YRES);\n\tbpp = bga_read_register(VBE_DISPI_INDEX_BPP);\n\n\tif(xres != video.fb_width || yres != video.fb_height || bpp != video.fb_bpp) {\n\t\tprintk(\"WARNING: %s(): resolution %dx%dx%d is not valid.\\n\", __FUNCTION__, video.fb_width, video.fb_height, video.fb_bpp);\n\t\treturn 0;\n\t}\n\n\t/* enable I/O space and memory space */\n\tcmd = (pci_dev->command | PCI_COMMAND_IO | PCI_COMMAND_MEMORY);\n\tpci_write_short(pci_dev, PCI_COMMAND, cmd);\n\n\tvideo.pci_dev = pci_dev;\n\tvideo.address = (unsigned int *)pci_dev->bar[0];\n\tvideo.port = 0;\n\n\tstrcpy((char *)video.signature, \"BGA\");\n\tvideo.fb_version = bga_read_register(VBE_DISPI_INDEX_ID);\n\n\tif(video.fb_version < VBE_DISPI_ID4) {\n\t\tvideo.memsize = 4 * 1024 * 1024;\t/* 4MB */\n\t} else if(video.fb_version == VBE_DISPI_ID4) {\n\t\tvideo.memsize = 8 * 1024 * 1024;\t/* 8MB */\n\t} else {\n\t\tvideo.memsize = bga_read_register(VBE_DISPI_INDEX_VIDEO_MEMORY_64K);\n\t\tvideo.memsize *= 64 * 1024;\n\t}\n\n\tvideo.fb_pixelwidth = video.fb_bpp / 8;\n\tvideo.fb_pitch = video.fb_width * video.fb_pixelwidth;\n\tvideo.fb_linesize = video.fb_pitch * video.fb_char_height;\n\tvideo.fb_size = video.fb_width * video.fb_height * video.fb_pixelwidth;\n\tvideo.fb_vsize = video.lines * video.fb_pitch * video.fb_char_height;\n\n\tmap_kaddr(kpage_dir, (unsigned int)video.address, (unsigned int)video.address + video.memsize, 0, PAGE_PRESENT | PAGE_RW);\n\n\tbga_write_register(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);\n\treturn 1;\n}\n\nvoid bga_init(void)\n{\n\tstruct pci_device *pci_dev;\n\n\tpci_dev = pci_device_table;\n\n\twhile(pci_dev) {\n\t\tif(pci_dev->class == PCI_CLASS_DISPLAY_VGA) {\n\t\t\tif(setup_bga_device(pci_dev)) {\n\t\t\t\t/* only one device is supported */\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tpci_dev = pci_dev->next;\n\t}\n}\n#endif /* CONFIG_BGA */\n#endif /* CONFIG_PCI */\n"
  },
  {
    "path": "drivers/video/fbcon.c",
    "content": "/*\n * fiwix/drivers/video/fbcon.c\n *\n * Copyright 2021-2022, Jordi Sanfeliu. All rights reserved.\n * Portions Copyright 2024, Greg Haerr.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/fb.h>\n#include <fiwix/fbcon.h>\n#include <fiwix/font.h>\n#include <fiwix/console.h>\n#include <fiwix/mm.h>\n#include <fiwix/tty.h>\n#include <fiwix/timer.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#define SPACE_CHAR\t32\n\nunsigned char *font_data;\nunsigned char *cursor_shape;\nstatic unsigned char screen_is_off = 0;\n\n/* RGB colors */\nstatic int color_table[] = {\n\t0x000000,\t/* black */\n\t0x0000AA,\t/* blue */\n\t0x00AA00,\t/* green */\n\t0x00AAAA,\t/* cyan */\n\t0xAA0000,\t/* red */\n\t0xAA00AA,\t/* magenta */\n\t0xAA5000,\t/* brown */\n\t0xAAAAAA,\t/* gray */\n\n\t0x555555,\t/* dark gray */\n\t0x5555FF,\t/* light blue */\n\t0x55FF55,\t/* light green */\n\t0x55FFFF,\t/* light cyan */\n\t0xFF5555,\t/* light red */\n\t0xFF55FF,\t/* light magenta */\n\t0xFFFF55,\t/* yellow */\n\t0xFFFFFF,\t/* white */\n};\n\nstatic int get_fg_color(unsigned char color)\n{\n\tint fg, bright;\n\n\tfg = color & 7;\n\tbright = (color & 0xF) & 8;\n\treturn color_table[bright + fg];\n}\n\nstatic int get_bg_color(unsigned char color)\n{\n\tint bg;\n\n\tbg = (color >> 4) & 7;\n\treturn color_table[bg];\n}\n\nstatic void set_color(void *addr, int color)\n{\n\tunsigned int *addr32;\n\tunsigned short int *addr16;\n\tunsigned char *addr8;\n\tshort int r, g, b;\n\n\tswitch(video.fb_bpp) {\n\t\tcase 32:\n\t\t\taddr32 = (unsigned int *)addr;\n\t\t\t*addr32 = color;\n\t\t\tbreak;\n\t\tcase 24:\n\t\t\taddr8 = (unsigned char *)addr;\n\t\t\t*(addr8++) = color & 0xFF;\n\t\t\t*(addr8++) = (color >> 8) & 0xFF;\n\t\t\t*(addr8++) = (color >> 16) & 0xFF;\n\t\t\tbreak;\n\t\tcase 16:\n\t\t\t/* 0:5:6:5 */\n\t\t\tr = ((color >> 16) & 0xFF) << 8;\n\t\t\tg = ((color >> 8) & 0xFF) << 8;\n\t\t\tb = (color & 0xFF) << 8;\n\t\t\taddr16 = (unsigned short int *)addr;\n\t\t\t*addr16 = (r & 0xf800) | ((g & 0xfc00) >> 5) | ((b & 0xf800) >> 11);\n\t\t\tbreak;\n\t\tcase 15:\n\t\t\t/* 1:5:5:5 */\n\t\t\tr = ((color >> 16) & 0xFF) << 8;\n\t\t\tg = ((color >> 8) & 0xFF) << 8;\n\t\t\tb = (color & 0xFF) << 8;\n\t\t\taddr16 = (unsigned short int *)addr;\n\t\t\t*addr16 = ((r & 0xf800) >> 1) | ((g & 0xf800) >> 6) | ((b & 0xf800) >> 11);\n\t\t\tbreak;\n\t}\n}\n\nstatic void draw_glyph(unsigned char *addr, int x, int y, unsigned char *ch, int color)\n{\n\tint n, b, offset;\n\n\tif(screen_is_off) {\n\t\treturn;\n\t}\n\n\toffset = (y * video.fb_linesize) + (x * video.fb_bpp);\n\taddr += offset;\n\n\tfor(n = 0; n < video.fb_char_height; n++) {\n\t\tif(*(ch + n) == 0) {\n\t\t\tif(ch == cursor_shape) {\n\t\t\t\taddr += video.fb_pitch;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tb = video.fb_char_width - 1;\n\t\t\tdo {\n\t\t\t\tset_color(addr, get_bg_color(color));\n\t\t\t\taddr += video.fb_pixelwidth;\n\t\t\t\tb--;\n\t\t\t} while(b >= 0);\n\t\t} else {\n\t\t\tb = video.fb_char_width - 1;\n\t\t\tdo {\n\t\t\t\tif(*(ch + n) & (1 << b)) {\n\t\t\t\t\tset_color(addr, get_fg_color(color));\n\t\t\t\t} else {\n\t\t\t\t\tset_color(addr, get_bg_color(color));\n\t\t\t\t}\n\t\t\t\taddr += video.fb_pixelwidth;\n\t\t\t\tb--;\n\t\t\t} while(b >= 0);\n\t\t}\n\t\taddr += (video.fb_width - video.fb_char_width) * video.fb_pixelwidth;\n\t}\n}\n\nstatic void remove_cursor(struct vconsole *vc)\n{\n\tint soffset;\n\tunsigned char *vidmem, *ch;\n\tshort int *screen, sch;\n\n\tvidmem = vc->vidmem;\n\tscreen = vc->screen;\n\tsoffset = (vc->cursor_y * vc->columns) + vc->cursor_x;\n\n\tsch = screen[soffset];\n\tif(sch & 0xFF) {\n\t\tch = &font_data[(sch & 0xFF) * video.fb_char_height];\n\t} else {\n\t\tch = &font_data[SPACE_CHAR * video.fb_char_height];\n\t}\n\tdraw_glyph(vidmem, vc->cursor_x, vc->cursor_y, ch, sch >> 8);\n}\n\nstatic void draw_cursor(struct vconsole *vc)\n{\n\tunsigned char *vidmem;\n\n\tvidmem = vc->vidmem;\n\tdraw_glyph(vidmem, vc->x, vc->y, cursor_shape, DEF_MODE >> 8);\n}\n\nvoid fbcon_put_char(struct vconsole *vc, unsigned char ch)\n{\n\tshort int *screen;\n\tunsigned char *vidmem;\n\n\tscreen = vc->screen;\n\n\tif(!(vc->flags & CONSOLE_HAS_FOCUS)) {\n\t\tscreen[(vc->y * vc->columns) + vc->x] = vc->color_attr | ch;\n\t\treturn;\n\t}\n\n\tvidmem = vc->vidmem;\n\tdraw_glyph(vidmem, vc->x, vc->y, &font_data[ch * video.fb_char_height], vc->color_attr >> 8);\n\tscreen[(vc->y * vc->columns) + vc->x] = vc->color_attr | ch;\n\tvcbuf[(video.buf_y * vc->columns) + vc->x] = vc->color_attr | ch;\n}\n\nvoid fbcon_insert_char(struct vconsole *vc)\n{\n\tint n, soffset;\n\tshort int tmp, slast_ch;\n\tunsigned char *vidmem, *last_ch;\n\tshort int *screen;\n\n\tvidmem = vc->vidmem;\n\tscreen = vc->screen;\n\tsoffset = (vc->y * vc->columns) + vc->x;\n\tn = vc->x;\n\tlast_ch = &font_data[SPACE_CHAR * video.fb_char_height];\n\tslast_ch = BLANK_MEM;\n\n\twhile(n < vc->columns) {\n\t\ttmp = screen[soffset];\n\t\tif(vc->flags & CONSOLE_HAS_FOCUS) {\n\t\t\tdraw_glyph(vidmem, n, vc->y, last_ch, vc->color_attr >> 8);\n\t\t\tif(tmp & 0xFF) {\n\t\t\t\tlast_ch = &font_data[(tmp & 0xFF) * video.fb_char_height];\n\t\t\t} else {\n\t\t\t\tlast_ch = &font_data[SPACE_CHAR * video.fb_char_height];\n\t\t\t}\n\t\t}\n\t\tmemset_w(screen + soffset, slast_ch, 1);\n\t\tslast_ch = tmp;\n\t\tsoffset++;\n\t\tn++;\n\t}\n}\n\nvoid fbcon_delete_char(struct vconsole *vc)\n{\n\tint n, soffset;\n\tshort int sch;\n\tunsigned char *vidmem, *ch;\n\tshort int *screen;\n\n\tvidmem = vc->vidmem;\n\tscreen = vc->screen;\n\tsoffset = (vc->y * vc->columns) + vc->x;\n\tn = vc->x;\n\n\twhile(n < vc->columns) {\n\t\tsch = screen[soffset + 1];\n\t\tif(vc->flags & CONSOLE_HAS_FOCUS) {\n\t\t\tif(sch & 0xFF) {\n\t\t\t\tch = &font_data[(sch & 0xFF) * video.fb_char_height];\n\t\t\t} else {\n\t\t\t\tch = &font_data[SPACE_CHAR * video.fb_char_height];\n\t\t\t}\n\t\t\tdraw_glyph(vidmem, n, vc->y, ch, vc->color_attr >> 8);\n\t\t}\n\t\tmemset_w(screen + soffset, sch, 1);\n\t\tsoffset++;\n\t\tn++;\n\t}\n\tmemset_w(screen + soffset, BLANK_MEM, 1);\n}\n\nvoid fbcon_update_curpos(struct vconsole *vc)\n{\n\tif(!(vc->flags & CONSOLE_HAS_FOCUS)) {\n\t\treturn;\n\t}\n\n\t/* remove old cursor */\n\tif(vc->x != vc->cursor_x || vc->y != vc->cursor_y) {\n\t\tremove_cursor(vc);\n\t}\n\n\tif(video.flags & VPF_CURSOR_ON) {\n\t\tdraw_cursor(vc);\n\t}\n\tvc->cursor_x = vc->x;\n\tvc->cursor_y = vc->y;\n}\n\nvoid fbcon_show_cursor(struct vconsole *vc, int mode)\n{\n\tswitch(mode) {\n\t\tcase COND:\n\t\t\tif(!(video.flags & VPF_CURSOR_ON)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t/* fall through */\n\t\tcase ON:\n\t\t\tvideo.flags |= VPF_CURSOR_ON;\n\t\t\tfbcon_update_curpos(vc);\n\t\t\tbreak;\n\t\tcase OFF:\n\t\t\tvideo.flags &= ~VPF_CURSOR_ON;\n\t\t\tfbcon_update_curpos(vc);\n\t\t\tbreak;\n\t}\n}\n\nvoid fbcon_get_curpos(struct vconsole *vc)\n{\n\t/* not used */\n}\n\nvoid fbcon_write_screen(struct vconsole *vc, int from, int count, short int color)\n{\n\tint n, n2, lines, columns, x, y;\n\tunsigned char *vidmem, *ch;\n\tshort int *screen;\n\n\tscreen = vc->screen;\n\tif(!(vc->flags & CONSOLE_HAS_FOCUS)) {\n\t\tmemset_w(screen + from, color, count);\n\t\treturn;\n\t}\n\n\tvidmem = vc->vidmem;\n\tch = &font_data[SPACE_CHAR * video.fb_char_height];\n\tx = from % vc->columns;\n\ty = from / vc->columns;\n\tlines = count / vc->columns;\n\tcolumns = x + count;\n\tif(!lines) {\n\t\tlines = 1;\n\t}\n\tif(!columns) {\n\t\tcolumns = vc->columns;\n\t}\n\tfor(n = 0; n < lines; n++) {\n\t\tfor(n2 = x; n2 < columns; n2++) {\n\t\t\tdraw_glyph(vidmem, n2, y + n, ch, color >> 8);\n\t\t}\n\t\tx = 0;\n\t\tcolumns = vc->columns;\n\t}\n\tmemset_w(screen + from, color, count);\n}\n\nvoid fbcon_blank_screen(struct vconsole *vc)\n{\n\tunsigned char *vidmem;\n\n\tif(vc->flags & CONSOLE_BLANKED) {\n\t\treturn;\n\t}\n\n\tvidmem = vc->vidmem;\n\tif(!(int)vidmem) {\n\t\treturn;\n\t}\n\n\tmemset_b(vidmem, 0, video.fb_size);\n\tvc->flags |= CONSOLE_BLANKED;\n\tfbcon_show_cursor(vc, OFF);\n}\n\nvoid fbcon_scroll_screen(struct vconsole *vc, int top, int mode)\n{\n\tint soffset, poffset, count;\n\tint x, y;\n\tshort int *screen, sch, pch;\n\tunsigned char *vidmem, *ch;\n\n\tvidmem = vc->vidmem;\n\tscreen = vc->screen;\n\n\tif(!top) {\n\t\ttop = vc->top;\n\t}\n\tswitch(mode) {\n\t\tcase SCROLL_UP:\n\t\t\tif(vc->flags & CONSOLE_HAS_FOCUS) {\n\t\t\t\tfor(y = top + 1; y < vc->lines; y++) {\n\t\t\t\t\tfor(x = 0; x < vc->columns; x++) {\n\t\t\t\t\t\tsoffset = (y * vc->columns) + x;\n\t\t\t\t\t\tpoffset = ((y - 1) * vc->columns) + x;\n\t\t\t\t\t\tsch = screen[soffset];\n\t\t\t\t\t\tpch = screen[poffset];\n\t\t\t\t\t\tif(sch == pch) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(sch & 0xFF) {\n\t\t\t\t\t\t\tch = &font_data[(sch & 0xFF) * video.fb_char_height];\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tch = &font_data[SPACE_CHAR * video.fb_char_height];\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdraw_glyph(vidmem, x, y - 1, ch, sch >> 8);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(!screen_is_off) {\n\t\t\t\t\tcount = video.fb_pitch * video.fb_char_height;\n\t\t\t\t\tmemset_l(vidmem + (vc->lines - 1) * count, 0, count / sizeof(unsigned int));\n\t\t\t\t}\n\t\t\t}\n\t\t\tcount = vc->columns * (vc->lines - top - 1);\n\t\t\tsoffset = top * vc->columns;\n\t\t\ttop = (top + 1) * vc->columns;\n\t\t\tif(vc->cursor_y) {\n\t\t\t\tvc->cursor_y--;\n\t\t\t}\n\t\t\tmemcpy_w(screen + soffset, screen + top, count);\n\t\t\tmemset_w(screen + soffset + count, BLANK_MEM, top);\n\t\t\tbreak;\n\t\tcase SCROLL_DOWN:\n\t\t\tfor(y = vc->lines - 2; y >= top; y--) {\n\t\t\t\tfor(x = 0; x < vc->columns; x++) {\n\t\t\t\t\tif(vc->flags & CONSOLE_HAS_FOCUS) {\n\t\t\t\t\t\tsoffset = (y * vc->columns) + x;\n\t\t\t\t\t\tpoffset = ((y + 1) * vc->columns) + x;\n\t\t\t\t\t\tsch = screen[soffset];\n\t\t\t\t\t\tpch = screen[poffset];\n\t\t\t\t\t\tif(sch == pch) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(sch & 0xFF) {\n\t\t\t\t\t\t\tch = &font_data[(sch & 0xFF) * video.fb_char_height];\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tch = &font_data[SPACE_CHAR * video.fb_char_height];\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdraw_glyph(vidmem, x, y + 1, ch, sch >> 8);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tmemcpy_w(screen + (vc->columns * (y + 1)), screen + (vc->columns * y), vc->columns);\n\t\t\t}\n\t\t\tif((vc->flags & CONSOLE_HAS_FOCUS) && !screen_is_off) {\n\t\t\t\tcount = video.fb_pitch * video.fb_char_height;\n\t\t\t\tmemset_l(vidmem + (top * count), 0, count / sizeof(unsigned int));\n\t\t\t}\n\t\t\tmemset_w(screen + (top * vc->columns), BLANK_MEM, vc->columns);\n\t\t\tbreak;\n\t}\n\treturn;\n}\n\nvoid fbcon_restore_screen(struct vconsole *vc)\n{\n\tint x, y;\n\tshort int *screen, sch;\n\tunsigned char *vidmem, *ch, c;\n\n\tvidmem = vc->vidmem;\n\tscreen = vc->screen;\n\n\tif(!screen_is_off && !video.buf_top) {\n\t\tmemset_b(vidmem, 0, video.fb_size);\n\t}\n\tfor(y = 0; y < video.lines; y++) {\n\t\tfor(x = 0; x < vc->columns; x++) {\n\t\t\tsch = screen[(y * vc->columns) + x];\n\t\t\tc = sch & 0xFF;\n\t\t\tif(!c || (c == SPACE_CHAR && !(sch >> 8))) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tch = &font_data[c * video.fb_char_height];\n\t\t\tdraw_glyph(vidmem, x, y, ch, sch >> 8);\n\t\t}\n\t}\n\tvc->flags &= ~CONSOLE_BLANKED;\n}\n\nvoid fbcon_screen_on(struct vconsole *vc)\n{\n\tunsigned int flags;\n\tstruct callout_req creq;\n\n\tif(screen_is_off) {\n\t\tscreen_is_off = 0;\n\t\tSAVE_FLAGS(flags); CLI();\n\t\tfbcon_restore_screen(vc);\n\t\tfbcon_update_curpos(vc);\n\t\tRESTORE_FLAGS(flags);\n\t\tvc->flags &= ~CONSOLE_BLANKED;\n\t}\n\n\tif(BLANK_INTERVAL) {\n\t\tcreq.fn = fbcon_screen_off;\n\t\tcreq.arg = (unsigned int)vc;\n\t\tadd_callout(&creq, BLANK_INTERVAL);\n\t}\n}\n\nvoid fbcon_screen_off(unsigned int arg)\n{\n\tstruct vconsole *vc;\n\tunsigned int flags;\n\n\tvc = (struct vconsole *)arg;\n\tscreen_is_off = 1;\n\tSAVE_FLAGS(flags); CLI();\n\tfbcon_blank_screen(vc);\n\tRESTORE_FLAGS(flags);\n}\n\nvoid fbcon_buf_scroll(struct vconsole *vc, int mode)\n{\n\tshort int sch;\n\tint y, x, offset;\n\tunsigned char *vidmem, *ch;\n\n\tif(video.buf_y <= SCREEN_LINES) {\n\t\treturn;\n\t}\n\n\tvidmem = vc->vidmem;\n\n\tif(mode == SCROLL_UP) {\n\t\tif(video.buf_top < 0) {\n\t\t\treturn;\n\t\t}\n\t\tif(!video.buf_top) {\n\t\t\tvideo.buf_top = (video.buf_y - SCREEN_LINES + 1) * SCREEN_COLS;\n\t\t}\n\t\tvideo.buf_top -= (SCREEN_LINES / 2) * SCREEN_COLS;\n\t\tif(video.buf_top < 0) {\n\t\t\tvideo.buf_top = 0;\n\t\t}\n\t\tfor(offset = 0, y = 0; y < video.lines; y++) {\n\t\t\tfor(x = 0; x < vc->columns; x++, offset++) {\n\t\t\t\tsch = vcbuf[video.buf_top + offset];\n\t\t\t\tif(sch & 0xFF) {\n\t\t\t\t\tch = &font_data[(sch & 0xFF) * video.fb_char_height];\n\t\t\t\t} else {\n\t\t\t\t\tch = &font_data[SPACE_CHAR * video.fb_char_height];\n\t\t\t\t}\n\t\t\t\tdraw_glyph(vidmem, x, y, ch, sch >> 8);\n\t\t\t}\n\t\t}\n\t\tif(!video.buf_top) {\n\t\t\tvideo.buf_top = -1;\n\t\t}\n\t\tfbcon_show_cursor(vc, OFF);\n\t\treturn;\n\t}\n\tif(mode == SCROLL_DOWN) {\n\t\tif(!video.buf_top) {\n\t\t\treturn;\n\t\t}\n\t\tif(video.buf_top == video.buf_y * SCREEN_COLS) {\n\t\t\treturn;\n\t\t}\n\t\tif(video.buf_top < 0) {\n\t\t\tvideo.buf_top = 0;\n\t\t}\n\t\tvideo.buf_top += (SCREEN_LINES / 2) * SCREEN_COLS;\n\t\tif(video.buf_top >= (video.buf_y - SCREEN_LINES + 1) * SCREEN_COLS) {\n\t\t\tvideo.buf_top = (video.buf_y - SCREEN_LINES + 1) * SCREEN_COLS;\n\t\t}\n\t\tfor(offset = 0, y = 0; y < video.lines; y++) {\n\t\t\tfor(x = 0; x < vc->columns; x++, offset++) {\n\t\t\t\tsch = vcbuf[video.buf_top + offset];\n\t\t\t\tif(sch & 0xFF) {\n\t\t\t\t\tch = &font_data[(sch & 0xFF) * video.fb_char_height];\n\t\t\t\t} else {\n\t\t\t\t\tch = &font_data[SPACE_CHAR * video.fb_char_height];\n\t\t\t\t}\n\t\t\t\tdraw_glyph(vidmem, x, y, ch, sch >> 8);\n\t\t\t}\n\t\t}\n\t\tif(video.buf_top >= (video.buf_y - SCREEN_LINES + 1) * SCREEN_COLS) {\n\t\t\tfbcon_show_cursor(vc, ON);\n\t\t\tfbcon_update_curpos(vc);\n\t\t}\n\t\treturn;\n\t}\n}\n\nvoid fbcon_cursor_blink(unsigned int arg)\n{\n\tstruct vconsole *vc;\n\tstruct callout_req creq;\n\tstatic int blink_on = 0;\n\n\tvc = (struct vconsole *)arg;\n\tif(!(vc->flags & CONSOLE_HAS_FOCUS)) {\n\t\treturn;\n\t}\n\n\tif(video.flags & VPF_CURSOR_ON && !screen_is_off) {\n\t\tif(blink_on) {\n\t\t\tdraw_cursor(vc);\n\t\t} else {\n\t\t\tremove_cursor(vc);\n\t\t}\n\t}\n\tblink_on = !blink_on;\n\tcreq.fn = fbcon_cursor_blink;\n\tcreq.arg = arg;\n\tadd_callout(&creq, 25);\t\t/* 250ms */\n}\n\nvoid fbcon_init(void)\n{\n\tstruct fbcon_font_desc *font_desc;\n\n\tmap_kaddr(kpage_dir, (unsigned int)video.address, (unsigned int)video.address + video.memsize, 0, PAGE_PRESENT | PAGE_RW);\n\n\t/* some parameters already set in multiboot.c */\n\n\tvideo.put_char = fbcon_put_char;\n\tvideo.insert_char = fbcon_insert_char;\n\tvideo.delete_char = fbcon_delete_char;\n\tvideo.update_curpos = fbcon_update_curpos;\n\tvideo.show_cursor = fbcon_show_cursor;\n\tvideo.get_curpos = fbcon_get_curpos;\n\tvideo.write_screen = fbcon_write_screen;\n\tvideo.blank_screen = fbcon_blank_screen;\n\tvideo.scroll_screen = fbcon_scroll_screen;\n\tvideo.restore_screen = fbcon_restore_screen;\n\tvideo.screen_on = fbcon_screen_on;\n\tvideo.buf_scroll = fbcon_buf_scroll;\n\tvideo.cursor_blink = fbcon_cursor_blink;\n\n\tif(!(font_desc = fbcon_find_font(video.fb_char_height))) {\n\t\tfont_desc = fbcon_find_font(16);\n\t}\n\tfont_data = font_desc->data;\n\tcursor_shape = font_desc->cursorshape;\n}\n"
  },
  {
    "path": "drivers/video/font-lat9-8x14.c",
    "content": "#include <fiwix/font.h>\n\n/* refer to 'fiwix/docs/video/' for a visual representation of these glyphs */\nstatic unsigned char fontdata_8x14[] = {\n\t/* 0x00        */ 0x00, 0x7e, 0xc3, 0x99, 0x99, 0xf3, 0xe7, 0xe7, 0xff, 0xe7, 0xe7, 0x7e, 0x00, 0x00,\n\t/* 0x01        */ 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x02        */ 0x00, 0x6e, 0xd8, 0xd8, 0xd8, 0xd8, 0xde, 0xd8, 0xd8, 0xd8, 0x6e, 0x00, 0x00, 0x00,\n\t/* 0x03        */ 0x00, 0x00, 0x00, 0x00, 0x6e, 0xdb, 0xdb, 0xdf, 0xd8, 0xdb, 0x6e, 0x00, 0x00, 0x00,\n\t/* 0x04        */ 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x05        */ 0x00, 0x88, 0x88, 0xf8, 0x88, 0x88, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,\n\t/* 0x06        */ 0x00, 0xf8, 0x80, 0xe0, 0x80, 0x80, 0x00, 0x3e, 0x20, 0x38, 0x20, 0x20, 0x00, 0x00,\n\t/* 0x07        */ 0x00, 0x78, 0x80, 0x80, 0x80, 0x78, 0x00, 0x3c, 0x22, 0x3e, 0x24, 0x22, 0x00, 0x00,\n\t/* 0x08        */ 0x00, 0x80, 0x80, 0x80, 0x80, 0xf8, 0x00, 0x3e, 0x20, 0x38, 0x20, 0x20, 0x00, 0x00,\n\t/* 0x09        */ 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22,\n\t/* 0x0a        */ 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55,\n\t/* 0x0b        */ 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee,\n\t/* 0x0c        */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n\t/* 0x0d        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n\t/* 0x0e        */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x0f        */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,\n\t/* 0x10        */ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,\n\t/* 0x11        */ 0x00, 0x88, 0xc8, 0xa8, 0x98, 0x88, 0x00, 0x20, 0x20, 0x20, 0x20, 0x3e, 0x00, 0x00,\n\t/* 0x12        */ 0x00, 0x88, 0x88, 0x50, 0x50, 0x20, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,\n\t/* 0x13        */ 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x14        */ 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x15        */ 0x00, 0x00, 0x00, 0x06, 0x0c, 0xfe, 0x38, 0xfe, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x16        */ 0x00, 0x00, 0x02, 0x0e, 0x3e, 0x7e, 0xfe, 0x7e, 0x3e, 0x0e, 0x02, 0x00, 0x00, 0x00,\n\t/* 0x17        */ 0x00, 0x00, 0x80, 0xe0, 0xf0, 0xfc, 0xfe, 0xfc, 0xf0, 0xe0, 0x80, 0x00, 0x00, 0x00,\n\t/* 0x18        */ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,\n\t/* 0x19        */ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00,\n\t/* 0x1a        */ 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x1b        */ 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x1c        */ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00,\n\t/* 0x1d        */ 0x00, 0x00, 0x00, 0x00, 0x28, 0x6c, 0xfe, 0x6c, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x1e        */ 0x00, 0x00, 0x06, 0x06, 0x36, 0x66, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x1f        */ 0x00, 0x00, 0x00, 0x00, 0xc0, 0x7c, 0x6e, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00,\n\t/* 0x20  (' ') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x21  ('!') */ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,\n\t/* 0x22  ('\"') */ 0x00, 0x00, 0x36, 0x36, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x23  ('#') */ 0x00, 0x00, 0x6c, 0xfe, 0x6c, 0x6c, 0xfe, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x24  ('$') */ 0x00, 0x00, 0x10, 0x7c, 0xd6, 0x70, 0x38, 0x1c, 0xd6, 0x7c, 0x10, 0x00, 0x00, 0x00,\n\t/* 0x25  ('%') */ 0x00, 0x00, 0x00, 0x00, 0x62, 0x66, 0x0c, 0x18, 0x30, 0x66, 0xc6, 0x00, 0x00, 0x00,\n\t/* 0x26  ('&') */ 0x00, 0x00, 0x38, 0x6c, 0x38, 0x38, 0x76, 0xf6, 0xce, 0xcc, 0x76, 0x00, 0x00, 0x00,\n\t/* 0x27  (''') */ 0x00, 0x1c, 0x1c, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x28  ('(') */ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00,\n\t/* 0x29  (')') */ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00,\n\t/* 0x2a  ('*') */ 0x00, 0x00, 0x00, 0x00, 0x6c, 0x38, 0xfe, 0x38, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x2b  ('+') */ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x2c  (',') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x18, 0x00, 0x00,\n\t/* 0x2d  ('-') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x2e  ('.') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,\n\t/* 0x2f  ('/') */ 0x00, 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x30  ('0') */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xd6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0x31  ('1') */ 0x00, 0x00, 0x18, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00,\n\t/* 0x32  ('2') */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00,\n\t/* 0x33  ('3') */ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0x34  ('4') */ 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x00,\n\t/* 0x35  ('5') */ 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0x36  ('6') */ 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0x37  ('7') */ 0x00, 0x00, 0xfe, 0xc6, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00,\n\t/* 0x38  ('8') */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0x39  ('9') */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0x3a  (':') */ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x3b  (';') */ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x18, 0x00, 0x00,\n\t/* 0x3c  ('<') */ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00,\n\t/* 0x3d  ('=') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x3e  ('>') */ 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00,\n\t/* 0x3f  ('?') */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,\n\t/* 0x40  ('@') */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7e, 0x00, 0x00, 0x00,\n\t/* 0x41  ('A') */ 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,\n\t/* 0x42  ('B') */ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00,\n\t/* 0x43  ('C') */ 0x00, 0x00, 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00, 0x00, 0x00,\n\t/* 0x44  ('D') */ 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00,\n\t/* 0x45  ('E') */ 0x00, 0x00, 0xfe, 0x66, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00,\n\t/* 0x46  ('F') */ 0x00, 0x00, 0xfe, 0x66, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,\n\t/* 0x47  ('G') */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc0, 0xc0, 0xce, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0x48  ('H') */ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00,\n\t/* 0x49  ('I') */ 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,\n\t/* 0x4a  ('J') */ 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00,\n\t/* 0x4b  ('K') */ 0x00, 0x00, 0xc6, 0xcc, 0xd8, 0xf0, 0xf0, 0xd8, 0xcc, 0xc6, 0xc6, 0x00, 0x00, 0x00,\n\t/* 0x4c  ('L') */ 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00,\n\t/* 0x4d  ('M') */ 0x00, 0x00, 0xc6, 0xc6, 0xee, 0xfe, 0xd6, 0xd6, 0xd6, 0xc6, 0xc6, 0x00, 0x00, 0x00,\n\t/* 0x4e  ('N') */ 0x00, 0x00, 0xc6, 0xc6, 0xe6, 0xe6, 0xf6, 0xde, 0xce, 0xce, 0xc6, 0x00, 0x00, 0x00,\n\t/* 0x4f  ('O') */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0x50  ('P') */ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,\n\t/* 0x51  ('Q') */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0x7c, 0x06, 0x00, 0x00,\n\t/* 0x52  ('R') */ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00,\n\t/* 0x53  ('S') */ 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0x54  ('T') */ 0x00, 0x00, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,\n\t/* 0x55  ('U') */ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0x56  ('V') */ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00,\n\t/* 0x57  ('W') */ 0x00, 0x00, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xfe, 0xee, 0xc6, 0xc6, 0x00, 0x00, 0x00,\n\t/* 0x58  ('X') */ 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0xc6, 0x00, 0x00, 0x00,\n\t/* 0x59  ('Y') */ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,\n\t/* 0x5a  ('Z') */ 0x00, 0x00, 0xfe, 0xc6, 0x8c, 0x18, 0x30, 0x60, 0xc2, 0xc6, 0xfe, 0x00, 0x00, 0x00,\n\t/* 0x5b  ('[') */ 0x00, 0x00, 0x7c, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0x5c  ('\\') */ 0x00, 0x00, 0x00, 0x00, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x5d  (']') */ 0x00, 0x00, 0x7c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0x5e  ('^') */ 0x00, 0x00, 0x18, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x5f  ('_') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,\n\t/* 0x60  ('`') */ 0x00, 0x1c, 0x1c, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x61  ('a') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xdc, 0x76, 0x00, 0x00, 0x00,\n\t/* 0x62  ('b') */ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00,\n\t/* 0x63  ('c') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0x64  ('d') */ 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0xcc, 0x7e, 0x00, 0x00, 0x00,\n\t/* 0x65  ('e') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0x66  ('f') */ 0x00, 0x00, 0x1c, 0x36, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00,\n\t/* 0x67  ('g') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xce, 0xc6, 0xc6, 0x7e, 0x06, 0xc6, 0x7c, 0x00,\n\t/* 0x68  ('h') */ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00,\n\t/* 0x69  ('i') */ 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,\n\t/* 0x6a  ('j') */ 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x1c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,\n\t/* 0x6b  ('k') */ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00,\n\t/* 0x6c  ('l') */ 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,\n\t/* 0x6d  ('m') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xd6, 0xd6, 0xc6, 0xc6, 0x00, 0x00, 0x00,\n\t/* 0x6e  ('n') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00,\n\t/* 0x6f  ('o') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0x70  ('p') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,\n\t/* 0x71  ('q') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,\n\t/* 0x72  ('r') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,\n\t/* 0x73  ('s') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x70, 0x1c, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0x74  ('t') */ 0x00, 0x00, 0x30, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00,\n\t/* 0x75  ('u') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,\n\t/* 0x76  ('v') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00,\n\t/* 0x77  ('w') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 0x00, 0x00,\n\t/* 0x78  ('x') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00,\n\t/* 0x79  ('y') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xce, 0x76, 0x06, 0xc6, 0x7c, 0x00,\n\t/* 0x7a  ('z') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x8c, 0x18, 0x30, 0x62, 0xfe, 0x00, 0x00, 0x00,\n\t/* 0x7b  ('{') */ 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00,\n\t/* 0x7c  ('|') */ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00,\n\t/* 0x7d  ('}') */ 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00,\n\t/* 0x7e  ('~') */ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x7f        */ 0x00, 0x66, 0x66, 0x00, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,\n\t/* 0x80        */ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x81        */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x82        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x83        */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x84        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,\n\t/* 0x85        */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,\n\t/* 0x86        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,\n\t/* 0x87        */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,\n\t/* 0x88        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x89        */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x8a        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x8b        */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x8c        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,\n\t/* 0x8d        */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,\n\t/* 0x8e        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,\n\t/* 0x8f        */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,\n\t/* 0x90        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x91        */ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x92        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x93        */ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6f, 0x60, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x94        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,\n\t/* 0x95        */ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,\n\t/* 0x96        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x60, 0x6f, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,\n\t/* 0x97        */ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6f, 0x60, 0x6f, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,\n\t/* 0x98        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0c, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x99        */ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xec, 0x0c, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x9a        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x9b        */ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xef, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x9c        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0c, 0xec, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,\n\t/* 0x9d        */ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xec, 0x0c, 0xec, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,\n\t/* 0x9e        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xef, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,\n\t/* 0x9f        */ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xef, 0x00, 0xef, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,\n\t/* 0xa0        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0xfe, 0x00, 0x00,\n\t/* 0xa1        */ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00,\n\t/* 0xa2        */ 0x00, 0x00, 0x00, 0x10, 0x7c, 0xd6, 0xd0, 0xd0, 0xd6, 0x7c, 0x10, 0x00, 0x00, 0x00,\n\t/* 0xa3        */ 0x00, 0x00, 0x38, 0x6c, 0x60, 0x60, 0xf0, 0x60, 0x66, 0xf6, 0x6c, 0x00, 0x00, 0x00,\n\t/* 0xa4        */ 0x00, 0x00, 0x3c, 0x62, 0x60, 0xf8, 0x60, 0xf8, 0x60, 0x62, 0x3c, 0x00, 0x00, 0x00,\n\t/* 0xa5        */ 0x00, 0x00, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x3c, 0x18, 0x18, 0x00, 0x00, 0x00,\n\t/* 0xa6        */ 0x6c, 0x38, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x1c, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0xa7        */ 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x7c, 0xc6, 0xc6, 0x7c, 0x0c, 0xc6, 0xc6, 0x7c, 0x00,\n\t/* 0xa8        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xa9        */ 0x00, 0x7e, 0x81, 0x99, 0xa5, 0xa1, 0xa5, 0x99, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xaa        */ 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xab        */ 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xac        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xad        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xae        */ 0x00, 0x7e, 0x81, 0xb9, 0xa5, 0xb9, 0xa5, 0xa5, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xaf        */ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xb0        */ 0x00, 0x38, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xb1        */ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x00, 0x00,\n\t/* 0xb2        */ 0x00, 0x38, 0x6c, 0x18, 0x30, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xb3        */ 0x00, 0x38, 0x6c, 0x18, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xb4        */ 0x6c, 0x38, 0x00, 0xfe, 0xc6, 0x8c, 0x18, 0x30, 0x62, 0xc6, 0xfe, 0x00, 0x00, 0x00,\n\t/* 0xb5        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xf6, 0xc0, 0xc0, 0xc0,\n\t/* 0xb6        */ 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00,\n\t/* 0xb7        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xb8        */ 0x00, 0x00, 0x6c, 0x38, 0x00, 0xfe, 0x8c, 0x18, 0x30, 0x62, 0xfe, 0x00, 0x00, 0x00,\n\t/* 0xb9        */ 0x00, 0x30, 0x70, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xba        */ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xbb        */ 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xbc        */ 0x00, 0x00, 0x77, 0xdf, 0xd8, 0xde, 0xde, 0xd8, 0xd8, 0xdf, 0x77, 0x00, 0x00, 0x00,\n\t/* 0xbd        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0xdb, 0xdf, 0xd8, 0xdb, 0x6e, 0x00, 0x00, 0x00,\n\t/* 0xbe        */ 0x00, 0x66, 0x66, 0x00, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,\n\t/* 0xbf        */ 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc6, 0xc6, 0x7c, 0x00,\n\t/* 0xc0        */ 0x60, 0x30, 0x18, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x00, 0x00,\n\t/* 0xc1        */ 0x0c, 0x18, 0x30, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x00, 0x00,\n\t/* 0xc2        */ 0x10, 0x38, 0x6c, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x00, 0x00,\n\t/* 0xc3        */ 0x00, 0x76, 0xdc, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x00, 0x00,\n\t/* 0xc4        */ 0x00, 0x6c, 0x6c, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x00, 0x00,\n\t/* 0xc5        */ 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x00, 0x00,\n\t/* 0xc6        */ 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xfe, 0xd8, 0xd8, 0xd8, 0xde, 0x00, 0x00, 0x00,\n\t/* 0xc7        */ 0x00, 0x00, 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x18, 0x6c, 0x38,\n\t/* 0xc8        */ 0x30, 0x18, 0x0c, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00,\n\t/* 0xc9        */ 0x0c, 0x18, 0x30, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00,\n\t/* 0xca        */ 0x10, 0x38, 0x6c, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00,\n\t/* 0xcb        */ 0x00, 0x6c, 0x6c, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00,\n\t/* 0xcc        */ 0x30, 0x18, 0x0c, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,\n\t/* 0xcd        */ 0x0c, 0x18, 0x30, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,\n\t/* 0xce        */ 0x18, 0x3c, 0x66, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,\n\t/* 0xcf        */ 0x00, 0x66, 0x66, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,\n\t/* 0xd0        */ 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0xf6, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00,\n\t/* 0xd1        */ 0x00, 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00, 0x00, 0x00,\n\t/* 0xd2        */ 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0xd3        */ 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0xd4        */ 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0xd5        */ 0x00, 0x76, 0xdc, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0xd6        */ 0x00, 0x6c, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0xd7        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x38, 0x38, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xd8        */ 0x00, 0x00, 0x7e, 0xc6, 0xce, 0xde, 0xd6, 0xf6, 0xe6, 0xc6, 0xfc, 0x00, 0x00, 0x00,\n\t/* 0xd9        */ 0x60, 0x30, 0x18, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0xda        */ 0x0c, 0x18, 0x30, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0xdb        */ 0x10, 0x38, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0xdc        */ 0x00, 0x6c, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0xdd        */ 0x06, 0x0c, 0x18, 0x00, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,\n\t/* 0xde        */ 0x00, 0x00, 0xf0, 0x60, 0x7c, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xf0, 0x00, 0x00, 0x00,\n\t/* 0xdf        */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xcc, 0xc6, 0xc6, 0xd6, 0xdc, 0x80, 0x00, 0x00,\n\t/* 0xe0        */ 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xdc, 0x76, 0x00, 0x00, 0x00,\n\t/* 0xe1        */ 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xdc, 0x76, 0x00, 0x00, 0x00,\n\t/* 0xe2        */ 0x00, 0x30, 0x78, 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xdc, 0x76, 0x00, 0x00, 0x00,\n\t/* 0xe3        */ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xdc, 0x76, 0x00, 0x00, 0x00,\n\t/* 0xe4        */ 0x00, 0x00, 0x6c, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xdc, 0x76, 0x00, 0x00, 0x00,\n\t/* 0xe5        */ 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xdc, 0x76, 0x00, 0x00, 0x00,\n\t/* 0xe6        */ 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0x1b, 0x7f, 0xd8, 0xdb, 0x7e, 0x00, 0x00, 0x00,\n\t/* 0xe7        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x18, 0x6c, 0x38,\n\t/* 0xe8        */ 0x00, 0x30, 0x18, 0x0c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0xe9        */ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0xea        */ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0xeb        */ 0x00, 0x00, 0x6c, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0xec        */ 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,\n\t/* 0xed        */ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,\n\t/* 0xee        */ 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,\n\t/* 0xef        */ 0x00, 0x00, 0x6c, 0x6c, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00,\n\t/* 0xf0        */ 0x00, 0x78, 0x30, 0x78, 0x0c, 0x7e, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0xf1        */ 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00,\n\t/* 0xf2        */ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0xf3        */ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0xf4        */ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0xf5        */ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0xf6        */ 0x00, 0x00, 0x6c, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0xf7        */ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xf8        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xce, 0xde, 0xf6, 0xe6, 0xfc, 0x00, 0x00, 0x00,\n\t/* 0xf9        */ 0x00, 0xc0, 0x60, 0x30, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,\n\t/* 0xfa        */ 0x00, 0x0c, 0x18, 0x30, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,\n\t/* 0xfb        */ 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,\n\t/* 0xfc        */ 0x00, 0x00, 0xcc, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00,\n\t/* 0xfd        */ 0x00, 0x0c, 0x18, 0x30, 0x00, 0xc6, 0xc6, 0xc6, 0xce, 0x76, 0x06, 0xc6, 0x7c, 0x00,\n\t/* 0xfe        */ 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x78, 0x6c, 0x6c, 0x6c, 0x78, 0x60, 0x60, 0xf0,\n\t/* 0xff        */ 0x00, 0x00, 0xc6, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xce, 0x76, 0x06, 0xc6, 0x7c, 0x00\n};\n\nstatic unsigned char cursorshape_8x14[] = {\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF\n};\n\nstruct fbcon_font_desc font_lat9_8x14 = {\n\t\"VGA8x14\",\n\t8,\n\t14,\n\tfontdata_8x14,\n\tcursorshape_8x14\n};\n"
  },
  {
    "path": "drivers/video/font-lat9-8x16.c",
    "content": "#include <fiwix/font.h>\n\n/* refer to 'fiwix/docs/video/' for a visual representation of these glyphs */\nstatic unsigned char fontdata_8x16[] = {\n\t/* 0x00        */ 0x00, 0x00, 0x7e, 0xc3, 0x99, 0x99, 0xf3, 0xe7, 0xe7, 0xff, 0xe7, 0xe7, 0x7e, 0x00, 0x00, 0x00,\n\t/* 0x01        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x02        */ 0x00, 0x00, 0x6e, 0xf8, 0xd8, 0xd8, 0xdc, 0xd8, 0xd8, 0xd8, 0xf8, 0x6e, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x03        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0xdb, 0xdb, 0xdf, 0xd8, 0xdb, 0x6e, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x04        */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x05        */ 0x00, 0x88, 0x88, 0xf8, 0x88, 0x88, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x06        */ 0x00, 0xf8, 0x80, 0xe0, 0x80, 0x80, 0x00, 0x3e, 0x20, 0x38, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x07        */ 0x00, 0x70, 0x88, 0x80, 0x88, 0x70, 0x00, 0x3c, 0x22, 0x3c, 0x24, 0x22, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x08        */ 0x00, 0x80, 0x80, 0x80, 0x80, 0xf8, 0x00, 0x3e, 0x20, 0x38, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x09        */ 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,\n\t/* 0x0a        */ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,\n\t/* 0x0b        */ 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,\n\t/* 0x0c        */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n\t/* 0x0d        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n\t/* 0x0e        */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x0f        */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,\n\t/* 0x10        */ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,\n\t/* 0x11        */ 0x00, 0x88, 0xc8, 0xa8, 0x98, 0x88, 0x00, 0x20, 0x20, 0x20, 0x20, 0x3e, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x12        */ 0x00, 0x88, 0x88, 0x50, 0x50, 0x20, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x13        */ 0x00, 0x00, 0x00, 0x00, 0x0e, 0x38, 0xe0, 0x38, 0x0e, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x14        */ 0x00, 0x00, 0x00, 0x00, 0xe0, 0x38, 0x0e, 0x38, 0xe0, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x15        */ 0x00, 0x00, 0x00, 0x06, 0x0c, 0xfe, 0x18, 0x30, 0xfe, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x16        */ 0x00, 0x00, 0x00, 0x00, 0x06, 0x1e, 0x7e, 0xfe, 0x7e, 0x1e, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x17        */ 0x00, 0x00, 0x00, 0x00, 0xc0, 0xf0, 0xfc, 0xfe, 0xfc, 0xf0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x18        */ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x19        */ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x1a        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x1b        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x1c        */ 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x1d        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x6c, 0xfe, 0x6c, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x1e        */ 0x00, 0x00, 0x00, 0x00, 0x06, 0x36, 0x66, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x1f        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x20  (' ') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x21  ('!') */ 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x22  ('\"') */ 0x00, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x23  ('#') */ 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x24  ('$') */ 0x00, 0x10, 0x10, 0x7c, 0xd6, 0xd0, 0xd0, 0x7c, 0x16, 0x16, 0xd6, 0x7c, 0x10, 0x10, 0x00, 0x00,\n\t/* 0x25  ('%') */ 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x26  ('&') */ 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x27  (''') */ 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x28  ('(') */ 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x29  (')') */ 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x2a  ('*') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x2b  ('+') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x2c  (',') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,\n\t/* 0x2d  ('-') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x2e  ('.') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x2f  ('/') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x30  ('0') */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x31  ('1') */ 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x32  ('2') */ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x33  ('3') */ 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x34  ('4') */ 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x35  ('5') */ 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x36  ('6') */ 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x37  ('7') */ 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x38  ('8') */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x39  ('9') */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x3a  (':') */ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x3b  (';') */ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x3c  ('<') */ 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x3d  ('=') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x3e  ('>') */ 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x3f  ('?') */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x40  ('@') */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x41  ('A') */ 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x42  ('B') */ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x43  ('C') */ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x44  ('D') */ 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x45  ('E') */ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x46  ('F') */ 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x47  ('G') */ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x48  ('H') */ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x49  ('I') */ 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x4a  ('J') */ 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x4b  ('K') */ 0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x4c  ('L') */ 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x4d  ('M') */ 0x00, 0x00, 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x4e  ('N') */ 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x4f  ('O') */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x50  ('P') */ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x51  ('Q') */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00,\n\t/* 0x52  ('R') */ 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x53  ('S') */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x64, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x54  ('T') */ 0x00, 0x00, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x55  ('U') */ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x56  ('V') */ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x57  ('W') */ 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xfe, 0xee, 0x6c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x58  ('X') */ 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x7c, 0x38, 0x38, 0x7c, 0x6c, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x59  ('Y') */ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x5a  ('Z') */ 0x00, 0x00, 0xfe, 0xc6, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc2, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x5b  ('[') */ 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x5c  ('\\') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x5d  (']') */ 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x5e  ('^') */ 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x5f  ('_') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,\n\t/* 0x60  ('`') */ 0x00, 0x30, 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x61  ('a') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x62  ('b') */ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x63  ('c') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x64  ('d') */ 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x65  ('e') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x66  ('f') */ 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x67  ('g') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00,\n\t/* 0x68  ('h') */ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x69  ('i') */ 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x6a  ('j') */ 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00,\n\t/* 0x6b  ('k') */ 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x6c  ('l') */ 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x6d  ('m') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xfe, 0xd6, 0xd6, 0xd6, 0xd6, 0xc6, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x6e  ('n') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x6f  ('o') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x70  ('p') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,\n\t/* 0x71  ('q') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,\n\t/* 0x72  ('r') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x73  ('s') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x74  ('t') */ 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x75  ('u') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x76  ('v') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x77  ('w') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x78  ('x') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x79  ('y') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,\n\t/* 0x7a  ('z') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x7b  ('{') */ 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x7c  ('|') */ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x7d  ('}') */ 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x7e  ('~') */ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x7f        */ 0x00, 0x66, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x80        */ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x81        */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x82        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x83        */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x84        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,\n\t/* 0x85        */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,\n\t/* 0x86        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,\n\t/* 0x87        */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,\n\t/* 0x88        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x89        */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x8a        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x8b        */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x8c        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,\n\t/* 0x8d        */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,\n\t/* 0x8e        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,\n\t/* 0x8f        */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,\n\t/* 0x90        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x91        */ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x92        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x60, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x93        */ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6f, 0x60, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x94        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,\n\t/* 0x95        */ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,\n\t/* 0x96        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x60, 0x6f, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,\n\t/* 0x97        */ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6f, 0x60, 0x6f, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,\n\t/* 0x98        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0c, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x99        */ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xec, 0x0c, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x9a        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x9b        */ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xef, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x9c        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0c, 0xec, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,\n\t/* 0x9d        */ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xec, 0x0c, 0xec, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,\n\t/* 0x9e        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xef, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,\n\t/* 0x9f        */ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xef, 0x00, 0xef, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,\n\t/* 0xa0        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0xfe, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xa1        */ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00,\n\t/* 0xa2        */ 0x00, 0x00, 0x00, 0x00, 0x10, 0x7c, 0xd6, 0xd0, 0xd0, 0xd0, 0xd6, 0x7c, 0x10, 0x00, 0x00, 0x00,\n\t/* 0xa3        */ 0x00, 0x00, 0x38, 0x6c, 0x60, 0x60, 0xf0, 0x60, 0x60, 0x66, 0xf6, 0x6c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xa4        */ 0x00, 0x1c, 0x32, 0x60, 0x60, 0xfc, 0x60, 0xfc, 0x60, 0x60, 0x32, 0x1c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xa5        */ 0x00, 0x00, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xa6        */ 0x6c, 0x38, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xa7        */ 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0xa8        */ 0x00, 0x6c, 0x38, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xa9        */ 0x00, 0x00, 0x3c, 0x42, 0x99, 0xa5, 0xa1, 0xa5, 0x99, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xaa        */ 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xab        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xac        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xad        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xae        */ 0x00, 0x00, 0x3c, 0x42, 0xb9, 0xa5, 0xb9, 0xa5, 0xa5, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xaf        */ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xb0        */ 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xb1        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xb2        */ 0x38, 0x6c, 0x18, 0x30, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xb3        */ 0x38, 0x6c, 0x18, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xb4        */ 0x6c, 0x38, 0x00, 0xfe, 0xc6, 0x8c, 0x18, 0x30, 0x60, 0xc2, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xb5        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xf6, 0xc0, 0xc0, 0xc0, 0x00,\n\t/* 0xb6        */ 0x00, 0x00, 0x7f, 0xd6, 0xd6, 0x76, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xb7        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xb8        */ 0x00, 0x00, 0x6c, 0x38, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xb9        */ 0x30, 0x70, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xba        */ 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xbb        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xbc        */ 0x00, 0x00, 0x77, 0xcc, 0xcc, 0xcc, 0xcf, 0xcf, 0xcc, 0xcc, 0xcc, 0x77, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xbd        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0xdb, 0xdb, 0xdf, 0xd8, 0xdb, 0x6e, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xbe        */ 0x00, 0x66, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xbf        */ 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x30, 0x60, 0xc6, 0xc6, 0x7c, 0x00, 0x00,\n\t/* 0xc0        */ 0x60, 0x30, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xc1        */ 0x0c, 0x18, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xc2        */ 0x10, 0x38, 0x6c, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xc3        */ 0x76, 0xdc, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xc4        */ 0x00, 0x6c, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xc5        */ 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xc6        */ 0x00, 0x00, 0x3e, 0x78, 0xd8, 0xd8, 0xfc, 0xd8, 0xd8, 0xd8, 0xd8, 0xde, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xc7        */ 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x66, 0x3c, 0x00,\n\t/* 0xc8        */ 0x60, 0x30, 0x00, 0xfe, 0x66, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xc9        */ 0x0c, 0x18, 0x00, 0xfe, 0x66, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xca        */ 0x10, 0x38, 0x6c, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xcb        */ 0x00, 0x6c, 0x00, 0xfe, 0x66, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xcc        */ 0x60, 0x30, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xcd        */ 0x06, 0x0c, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xce        */ 0x18, 0x3c, 0x66, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xcf        */ 0x00, 0x66, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xd0        */ 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0xf6, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xd1        */ 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xd2        */ 0x60, 0x30, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xd3        */ 0x0c, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xd4        */ 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xd5        */ 0x76, 0xdc, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xd6        */ 0x00, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xd7        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xd8        */ 0x00, 0x00, 0x7e, 0xc6, 0xce, 0xce, 0xde, 0xf6, 0xe6, 0xe6, 0xc6, 0xfc, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xd9        */ 0x60, 0x30, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xda        */ 0x0c, 0x18, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xdb        */ 0x10, 0x38, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xdc        */ 0x00, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xdd        */ 0x06, 0x0c, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xde        */ 0x00, 0x00, 0xf0, 0x60, 0x7c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xdf        */ 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xcc, 0xc6, 0xc6, 0xc6, 0xd6, 0xdc, 0x80, 0x00, 0x00, 0x00,\n\t/* 0xe0        */ 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xe1        */ 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xe2        */ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xe3        */ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xe4        */ 0x00, 0x00, 0x00, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xe5        */ 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xe6        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0x1b, 0x7f, 0xd8, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xe7        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x18, 0x6c, 0x38, 0x00,\n\t/* 0xe8        */ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xe9        */ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xea        */ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xeb        */ 0x00, 0x00, 0x00, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xec        */ 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xed        */ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xee        */ 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xef        */ 0x00, 0x00, 0x00, 0x6c, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xf0        */ 0x00, 0x78, 0x30, 0x78, 0x0c, 0x7e, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xf1        */ 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xf2        */ 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xf3        */ 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xf4        */ 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xf5        */ 0x00, 0x00, 0x76, 0xdc, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xf6        */ 0x00, 0x00, 0x00, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xf7        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xf8        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xce, 0xde, 0xfe, 0xf6, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xf9        */ 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xfa        */ 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xfb        */ 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xfc        */ 0x00, 0x00, 0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xfd        */ 0x00, 0x0c, 0x18, 0x30, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00,\n\t/* 0xfe        */ 0x00, 0x00, 0xf0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00,\n\t/* 0xff        */ 0x00, 0x00, 0x00, 0x6c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00\n};\n\nstatic unsigned char cursorshape_8x16[] = {\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF\n};\n\nstruct fbcon_font_desc font_lat9_8x16 = {\n\t\"VGA8x16\",\n\t8,\n\t16,\n\tfontdata_8x16,\n\tcursorshape_8x16\n};\n"
  },
  {
    "path": "drivers/video/font-lat9-8x8.c",
    "content": "#include <fiwix/font.h>\n\n/* refer to 'fiwix/docs/video/' for a visual representation of these glyphs */\nstatic unsigned char fontdata_8x8[] = {\n\t/* 0x00        */ 0x7e, 0xc3, 0x99, 0xf3, 0xe7, 0xff, 0xe7, 0x7e,\n\t/* 0x01        */ 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00,\n\t/* 0x02        */ 0x76, 0xd8, 0xd8, 0xdc, 0xd8, 0xd8, 0x76, 0x00,\n\t/* 0x03        */ 0x00, 0x00, 0x6e, 0xd8, 0xde, 0xd8, 0x6e, 0x00,\n\t/* 0x04        */ 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00,\n\t/* 0x05        */ 0xa0, 0xa0, 0xe0, 0xae, 0xa4, 0x04, 0x04, 0x04,\n\t/* 0x06        */ 0xe0, 0x80, 0xc0, 0x8e, 0x88, 0x0c, 0x08, 0x08,\n\t/* 0x07        */ 0x60, 0x80, 0x80, 0x8c, 0x6a, 0x0c, 0x0a, 0x0a,\n\t/* 0x08        */ 0x80, 0x80, 0x80, 0x8e, 0xe8, 0x0c, 0x08, 0x08,\n\t/* 0x09        */ 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,\n\t/* 0x0a        */ 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,\n\t/* 0x0b        */ 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb,\n\t/* 0x0c        */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n\t/* 0x0d        */ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,\n\t/* 0x0e        */ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x0f        */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,\n\t/* 0x10        */ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,\n\t/* 0x11        */ 0x90, 0xd0, 0xf0, 0xb4, 0x94, 0x04, 0x04, 0x07,\n\t/* 0x12        */ 0xa0, 0xa0, 0xa0, 0xae, 0x44, 0x04, 0x04, 0x04,\n\t/* 0x13        */ 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xfc, 0x00,\n\t/* 0x14        */ 0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00,\n\t/* 0x15        */ 0x00, 0x0c, 0xfe, 0x18, 0x30, 0xfe, 0x60, 0x00,\n\t/* 0x16        */ 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,\n\t/* 0x17        */ 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00,\n\t/* 0x18        */ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00,\n\t/* 0x19        */ 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,\n\t/* 0x1a        */ 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00,\n\t/* 0x1b        */ 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,\n\t/* 0x1c        */ 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18,\n\t/* 0x1d        */ 0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00,\n\t/* 0x1e        */ 0x06, 0x06, 0x36, 0x66, 0xfe, 0x60, 0x30, 0x00,\n\t/* 0x1f        */ 0x00, 0xc0, 0x7c, 0x6e, 0x6c, 0x6c, 0x6c, 0x00,\n\t/* 0x20  (' ') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x21  ('!') */ 0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,\n\t/* 0x22  ('\"') */ 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x23  ('#') */ 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,\n\t/* 0x24  ('$') */ 0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00,\n\t/* 0x25  ('%') */ 0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00,\n\t/* 0x26  ('&') */ 0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00,\n\t/* 0x27  (''') */ 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x28  ('(') */ 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,\n\t/* 0x29  (')') */ 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,\n\t/* 0x2a  ('*') */ 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,\n\t/* 0x2b  ('+') */ 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,\n\t/* 0x2c  (',') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,\n\t/* 0x2d  ('-') */ 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x2e  ('.') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,\n\t/* 0x2f  ('/') */ 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x00,\n\t/* 0x30  ('0') */ 0x7c, 0xc6, 0xc6, 0xd6, 0xc6, 0xc6, 0x7c, 0x00,\n\t/* 0x31  ('1') */ 0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00,\n\t/* 0x32  ('2') */ 0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00,\n\t/* 0x33  ('3') */ 0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00,\n\t/* 0x34  ('4') */ 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00,\n\t/* 0x35  ('5') */ 0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00,\n\t/* 0x36  ('6') */ 0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00,\n\t/* 0x37  ('7') */ 0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,\n\t/* 0x38  ('8') */ 0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00,\n\t/* 0x39  ('9') */ 0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00,\n\t/* 0x3a  (':') */ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,\n\t/* 0x3b  (';') */ 0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,\n\t/* 0x3c  ('<') */ 0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00,\n\t/* 0x3d  ('=') */ 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00,\n\t/* 0x3e  ('>') */ 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00,\n\t/* 0x3f  ('?') */ 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,\n\t/* 0x40  ('@') */ 0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00,\n\t/* 0x41  ('A') */ 0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,\n\t/* 0x42  ('B') */ 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00,\n\t/* 0x43  ('C') */ 0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00,\n\t/* 0x44  ('D') */ 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00,\n\t/* 0x45  ('E') */ 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,\n\t/* 0x46  ('F') */ 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00,\n\t/* 0x47  ('G') */ 0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00,\n\t/* 0x48  ('H') */ 0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00,\n\t/* 0x49  ('I') */ 0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,\n\t/* 0x4a  ('J') */ 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00,\n\t/* 0x4b  ('K') */ 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,\n\t/* 0x4c  ('L') */ 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00,\n\t/* 0x4d  ('M') */ 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,\n\t/* 0x4e  ('N') */ 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00,\n\t/* 0x4f  ('O') */ 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00,\n\t/* 0x50  ('P') */ 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00,\n\t/* 0x51  ('Q') */ 0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00,\n\t/* 0x52  ('R') */ 0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00,\n\t/* 0x53  ('S') */ 0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00,\n\t/* 0x54  ('T') */ 0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,\n\t/* 0x55  ('U') */ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00,\n\t/* 0x56  ('V') */ 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,\n\t/* 0x57  ('W') */ 0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00,\n\t/* 0x58  ('X') */ 0xc6, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0xc6, 0x00,\n\t/* 0x59  ('Y') */ 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,\n\t/* 0x5a  ('Z') */ 0xfe, 0xc6, 0x0c, 0x18, 0x30, 0x66, 0xfe, 0x00,\n\t/* 0x5b  ('[') */ 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,\n\t/* 0x5c  ('\\') */ 0x00, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00,\n\t/* 0x5d  (']') */ 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,\n\t/* 0x5e  ('^') */ 0x18, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x5f  ('_') */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,\n\t/* 0x60  ('`') */ 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x61  ('a') */ 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,\n\t/* 0x62  ('b') */ 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00,\n\t/* 0x63  ('c') */ 0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00,\n\t/* 0x64  ('d') */ 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00,\n\t/* 0x65  ('e') */ 0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,\n\t/* 0x66  ('f') */ 0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00,\n\t/* 0x67  ('g') */ 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,\n\t/* 0x68  ('h') */ 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00,\n\t/* 0x69  ('i') */ 0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,\n\t/* 0x6a  ('j') */ 0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78,\n\t/* 0x6b  ('k') */ 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,\n\t/* 0x6c  ('l') */ 0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,\n\t/* 0x6d  ('m') */ 0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00,\n\t/* 0x6e  ('n') */ 0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,\n\t/* 0x6f  ('o') */ 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,\n\t/* 0x70  ('p') */ 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0,\n\t/* 0x71  ('q') */ 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,\n\t/* 0x72  ('r') */ 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00,\n\t/* 0x73  ('s') */ 0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,\n\t/* 0x74  ('t') */ 0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00,\n\t/* 0x75  ('u') */ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,\n\t/* 0x76  ('v') */ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00,\n\t/* 0x77  ('w') */ 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00,\n\t/* 0x78  ('x') */ 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00,\n\t/* 0x79  ('y') */ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,\n\t/* 0x7a  ('z') */ 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,\n\t/* 0x7b  ('{') */ 0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00,\n\t/* 0x7c  ('|') */ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00,\n\t/* 0x7d  ('}') */ 0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00,\n\t/* 0x7e  ('~') */ 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x7f        */ 0xcc, 0x00, 0xcc, 0xcc, 0x78, 0x30, 0x78, 0x00,\n\t/* 0x80        */ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x81        */ 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x82        */ 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x83        */ 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x84        */ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,\n\t/* 0x85        */ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,\n\t/* 0x86        */ 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18,\n\t/* 0x87        */ 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,\n\t/* 0x88        */ 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x89        */ 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x8a        */ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x8b        */ 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00,\n\t/* 0x8c        */ 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18,\n\t/* 0x8d        */ 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18,\n\t/* 0x8e        */ 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18,\n\t/* 0x8f        */ 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18,\n\t/* 0x90        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,\n\t/* 0x91        */ 0x6c, 0x6c, 0x6c, 0x6c, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0x92        */ 0x00, 0x00, 0x7f, 0x60, 0x7f, 0x00, 0x00, 0x00,\n\t/* 0x93        */ 0x6c, 0x6c, 0x6f, 0x60, 0x7f, 0x00, 0x00, 0x00,\n\t/* 0x94        */ 0x00, 0x00, 0x7c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,\n\t/* 0x95        */ 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,\n\t/* 0x96        */ 0x00, 0x00, 0x7f, 0x60, 0x6f, 0x6c, 0x6c, 0x6c,\n\t/* 0x97        */ 0x6c, 0x6c, 0x6f, 0x60, 0x6f, 0x6c, 0x6c, 0x6c,\n\t/* 0x98        */ 0x00, 0x00, 0xfc, 0x0c, 0xfc, 0x00, 0x00, 0x00,\n\t/* 0x99        */ 0x6c, 0x6c, 0xec, 0x0c, 0xfc, 0x00, 0x00, 0x00,\n\t/* 0x9a        */ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,\n\t/* 0x9b        */ 0x6c, 0x6c, 0xef, 0x00, 0xff, 0x00, 0x00, 0x00,\n\t/* 0x9c        */ 0x00, 0x00, 0xfc, 0x0c, 0xec, 0x6c, 0x6c, 0x6c,\n\t/* 0x9d        */ 0x6c, 0x6c, 0xec, 0x0c, 0xec, 0x6c, 0x6c, 0x6c,\n\t/* 0x9e        */ 0x00, 0x00, 0xff, 0x00, 0xef, 0x6c, 0x6c, 0x6c,\n\t/* 0x9f        */ 0x6c, 0x6c, 0xef, 0x00, 0xef, 0x6c, 0x6c, 0x6c,\n\t/* 0xa0        */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xfe,\n\t/* 0xa1        */ 0x00, 0x30, 0x00, 0x30, 0x30, 0x78, 0x78, 0x30,\n\t/* 0xa2        */ 0x30, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x30, 0x00,\n\t/* 0xa3        */ 0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00,\n\t/* 0xa4        */ 0x38, 0x64, 0xf0, 0x60, 0xf0, 0x64, 0x38, 0x00,\n\t/* 0xa5        */ 0xcc, 0xcc, 0x78, 0xfc, 0x30, 0xfc, 0x30, 0x30,\n\t/* 0xa6        */ 0x48, 0x78, 0x84, 0x60, 0x18, 0x84, 0x78, 0x00,\n\t/* 0xa7        */ 0x3e, 0x61, 0x3c, 0x66, 0x66, 0x3c, 0x86, 0x7c,\n\t/* 0xa8        */ 0x78, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00,\n\t/* 0xa9        */ 0x7c, 0x82, 0x9a, 0xa2, 0xa2, 0x9a, 0x82, 0x7c,\n\t/* 0xaa        */ 0x3c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00,\n\t/* 0xab        */ 0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00,\n\t/* 0xac        */ 0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00,\n\t/* 0xad        */ 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xae        */ 0x7c, 0x82, 0xb2, 0xaa, 0xb2, 0xaa, 0x82, 0x7c,\n\t/* 0xaf        */ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xb0        */ 0x70, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t/* 0xb1        */ 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00,\n\t/* 0xb2        */ 0x70, 0xd8, 0x30, 0x60, 0xf8, 0x00, 0x00, 0x00,\n\t/* 0xb3        */ 0x70, 0xd8, 0x30, 0xd8, 0x70, 0x00, 0x00, 0x00,\n\t/* 0xb4        */ 0x6c, 0xfe, 0xcc, 0x18, 0x30, 0x66, 0xfe, 0x00,\n\t/* 0xb5        */ 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xf6, 0xc0,\n\t/* 0xb6        */ 0x7f, 0xdb, 0x7b, 0x3b, 0x1b, 0x1b, 0x1b, 0x00,\n\t/* 0xb7        */ 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,\n\t/* 0xb8        */ 0x78, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00,\n\t/* 0xb9        */ 0x60, 0xe0, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00,\n\t/* 0xba        */ 0x38, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00,\n\t/* 0xbb        */ 0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00,\n\t/* 0xbc        */ 0x7e, 0xd8, 0xd8, 0xdc, 0xd8, 0xd8, 0x7e, 0x00,\n\t/* 0xbd        */ 0x00, 0x00, 0x7e, 0xdb, 0xde, 0xd8, 0x7e, 0x00,\n\t/* 0xbe        */ 0xcc, 0x00, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00,\n\t/* 0xbf        */ 0x00, 0x18, 0x00, 0x18, 0x30, 0x60, 0x66, 0x3c,\n\t/* 0xc0        */ 0x60, 0x30, 0x78, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,\n\t/* 0xc1        */ 0x18, 0x30, 0x78, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,\n\t/* 0xc2        */ 0x78, 0x84, 0x78, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,\n\t/* 0xc3        */ 0x76, 0xdc, 0x78, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,\n\t/* 0xc4        */ 0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,\n\t/* 0xc5        */ 0x30, 0x48, 0x78, 0xcc, 0xfc, 0xcc, 0xcc, 0x00,\n\t/* 0xc6        */ 0x3e, 0x78, 0xd8, 0xfc, 0xd8, 0xd8, 0xde, 0x00,\n\t/* 0xc7        */ 0x3c, 0x66, 0xc0, 0xc0, 0x66, 0x3c, 0x0c, 0x78,\n\t/* 0xc8        */ 0x60, 0x30, 0xfe, 0x62, 0x78, 0x62, 0xfe, 0x00,\n\t/* 0xc9        */ 0x0c, 0x18, 0xfe, 0x62, 0x78, 0x62, 0xfe, 0x00,\n\t/* 0xca        */ 0x38, 0x6c, 0xfe, 0x62, 0x78, 0x62, 0xfe, 0x00,\n\t/* 0xcb        */ 0x6c, 0x00, 0xfe, 0x62, 0x78, 0x62, 0xfe, 0x00,\n\t/* 0xcc        */ 0x60, 0x30, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00,\n\t/* 0xcd        */ 0x18, 0x30, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00,\n\t/* 0xce        */ 0x78, 0xcc, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00,\n\t/* 0xcf        */ 0xcc, 0x00, 0x78, 0x30, 0x30, 0x30, 0x78, 0x00,\n\t/* 0xd0        */ 0xf8, 0x6c, 0x66, 0xf6, 0x66, 0x6c, 0xf8, 0x00,\n\t/* 0xd1        */ 0x76, 0xdc, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0x00,\n\t/* 0xd2        */ 0x60, 0x30, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,\n\t/* 0xd3        */ 0x18, 0x30, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,\n\t/* 0xd4        */ 0x78, 0xcc, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,\n\t/* 0xd5        */ 0x76, 0xdc, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,\n\t/* 0xd6        */ 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00,\n\t/* 0xd7        */ 0x00, 0x6c, 0x38, 0x38, 0x6c, 0x00, 0x00, 0x00,\n\t/* 0xd8        */ 0x3e, 0x6c, 0xde, 0xd6, 0xf6, 0x6c, 0xf8, 0x00,\n\t/* 0xd9        */ 0x60, 0x30, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00,\n\t/* 0xda        */ 0x18, 0x30, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00,\n\t/* 0xdb        */ 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x00,\n\t/* 0xdc        */ 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00,\n\t/* 0xdd        */ 0x18, 0x30, 0xcc, 0xcc, 0x78, 0x30, 0x78, 0x00,\n\t/* 0xde        */ 0xf0, 0x60, 0x7c, 0x66, 0x7c, 0x60, 0xf0, 0x00,\n\t/* 0xdf        */ 0x7c, 0xc6, 0xc6, 0xcc, 0xc6, 0xd6, 0xdc, 0x80,\n\t/* 0xe0        */ 0x60, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,\n\t/* 0xe1        */ 0x18, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,\n\t/* 0xe2        */ 0x78, 0x84, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,\n\t/* 0xe3        */ 0x76, 0xdc, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,\n\t/* 0xe4        */ 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,\n\t/* 0xe5        */ 0x38, 0x6c, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,\n\t/* 0xe6        */ 0x00, 0x00, 0x7e, 0x1b, 0x7e, 0xd8, 0x7e, 0x00,\n\t/* 0xe7        */ 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x18, 0x70,\n\t/* 0xe8        */ 0x60, 0x30, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,\n\t/* 0xe9        */ 0x0c, 0x18, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,\n\t/* 0xea        */ 0x78, 0x84, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,\n\t/* 0xeb        */ 0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00,\n\t/* 0xec        */ 0x60, 0x30, 0x00, 0x70, 0x30, 0x30, 0x78, 0x00,\n\t/* 0xed        */ 0x18, 0x30, 0x00, 0x70, 0x30, 0x30, 0x78, 0x00,\n\t/* 0xee        */ 0x70, 0xd8, 0x00, 0x70, 0x30, 0x30, 0x78, 0x00,\n\t/* 0xef        */ 0x00, 0xd8, 0x00, 0x70, 0x30, 0x30, 0x78, 0x00,\n\t/* 0xf0        */ 0x78, 0x70, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00,\n\t/* 0xf1        */ 0x76, 0xdc, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00,\n\t/* 0xf2        */ 0x60, 0x30, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,\n\t/* 0xf3        */ 0x18, 0x30, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,\n\t/* 0xf4        */ 0x78, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,\n\t/* 0xf5        */ 0x76, 0xdc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,\n\t/* 0xf6        */ 0x00, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00,\n\t/* 0xf7        */ 0x00, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x00, 0x00,\n\t/* 0xf8        */ 0x00, 0x00, 0x7c, 0xdc, 0xfc, 0xec, 0xf8, 0x00,\n\t/* 0xf9        */ 0x60, 0x30, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,\n\t/* 0xfa        */ 0x18, 0x30, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,\n\t/* 0xfb        */ 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x76, 0x00,\n\t/* 0xfc        */ 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,\n\t/* 0xfd        */ 0x18, 0x30, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,\n\t/* 0xfe        */ 0xf0, 0x60, 0x78, 0x6c, 0x6c, 0x78, 0x60, 0xf0,\n\t/* 0xff        */ 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8\n};\n\nstatic unsigned char cursorshape_8x8[] = {\n\t0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF\n};\n\nstruct fbcon_font_desc font_lat9_8x8 = {\n\t\"VGA8x8\",\n\t8,\n\t8,\n\tfontdata_8x8,\n\tcursorshape_8x8\n};\n"
  },
  {
    "path": "drivers/video/fonts.c",
    "content": "/*\n * fiwix/drivers/video/fonts.c\n *\n * Copyright 2021-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/string.h>\n#include <fiwix/font.h>\n#include \"font-lat9-8x8.c\"\n#include \"font-lat9-8x14.c\"\n#include \"font-lat9-8x16.c\"\n\n#define NR_FONTS (sizeof(fbcon_fonts) / sizeof(*fbcon_fonts))\n\nstatic struct fbcon_font_desc *fbcon_fonts[] = {\n\t&font_lat9_8x8,\n\t&font_lat9_8x14,\n\t&font_lat9_8x16\n};\n\nstruct fbcon_font_desc *fbcon_find_font(int height)\n{\n\tint n;\n\n\tfor(n = 0; n < NR_FONTS; n++) {\n\t\tif(fbcon_fonts[n]->height == height) {\n \t\t\treturn fbcon_fonts[n];\n\t\t}\n\t}\n\n\treturn NULL;\n}\n"
  },
  {
    "path": "drivers/video/vgacon.c",
    "content": "/*\n * fiwix/drivers/video/vgacon.c\n *\n * Copyright 2021-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/config.h>\n#include <fiwix/segments.h>\n#include <fiwix/vgacon.h>\n#include <fiwix/console.h>\n#include <fiwix/timer.h>\n#include <fiwix/bios.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n/* ISO/IEC 8859-1:1998 (aka latin1, IBM819, CP819), same as in Linux */\nstatic const char *iso8859 =\n\t\"\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\"\n\t\"\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\"\n\t\" !\\\"#$%&'()*+,-./0123456789:;<=>?\"\n\t\"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_\"\n\t\"`abcdefghijklmnopqrstuvwxyz{|}~\\0\"\n\t\"\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\"\n\t\"\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\"\n\t\"\\377\\255\\233\\234\\376\\235\\174\\025\\376\\376\\246\\256\\252\\055\\376\\376\"\n\t\"\\370\\361\\375\\376\\376\\346\\024\\371\\376\\376\\247\\257\\254\\253\\376\\250\"\n\t\"\\376\\376\\376\\376\\216\\217\\222\\200\\376\\220\\376\\376\\376\\376\\376\\376\"\n\t\"\\376\\245\\376\\376\\376\\376\\231\\376\\350\\376\\376\\376\\232\\376\\376\\341\"\n\t\"\\205\\240\\203\\376\\204\\206\\221\\207\\212\\202\\210\\211\\215\\241\\214\\213\"\n\t\"\\376\\244\\225\\242\\223\\376\\224\\366\\355\\227\\243\\226\\201\\376\\376\\230\"\n;\n\nstatic unsigned char screen_is_off = 0;\n\nvoid vgacon_put_char(struct vconsole *vc, unsigned char ch)\n{\n\tshort int *vidmem, *screen;\n\n\tch = iso8859[ch];\n\tscreen = vc->screen;\n\n\tif(vc->flags & CONSOLE_HAS_FOCUS) {\n\t\tvidmem = (short int *)vc->vidmem;\n\t\tvidmem[(vc->y * vc->columns) + vc->x] = vc->color_attr | ch;\n\t}\n\tscreen[(vc->y * vc->columns) + vc->x] = vc->color_attr | ch;\n\tvcbuf[(video.buf_y * vc->columns) + vc->x] = vc->color_attr | ch;\n}\n\nvoid vgacon_insert_char(struct vconsole *vc)\n{\n\tint n, offset;\n\tshort int tmp, last_char, *vidmem, *screen;\n\n\tscreen = vc->screen;\n\toffset = (vc->y * vc->columns) + vc->x;\n\tn = vc->x;\n\tlast_char = BLANK_MEM;\n\n\twhile(n++ < vc->columns) {\n\t\tif(vc->flags & CONSOLE_HAS_FOCUS) {\n\t\t\tvidmem = (short int *)vc->vidmem;\n\t\t\tmemcpy_w(&tmp, vidmem + offset, 1);\n\t\t\tmemset_w(vidmem + offset, last_char, 1);\n\t\t}\n\t\tmemcpy_w(&tmp, screen + offset, 1);\n\t\tmemset_w(screen + offset, last_char, 1);\n\t\tlast_char = tmp;\n\t\toffset++;\n\t}\n}\n\nvoid vgacon_delete_char(struct vconsole *vc)\n{\n\tint offset, count;\n\tshort int *vidmem, *screen;\n\n\tscreen = vc->screen;\n\toffset = (vc->y * vc->columns) + vc->x;\n\tcount = vc->columns - vc->x;\n\n\tif(vc->flags & CONSOLE_HAS_FOCUS) {\n\t\tvidmem = (short int *)vc->vidmem;\n\t\tmemcpy_w(vidmem + offset, vidmem + offset + 1, count);\n\t\tmemset_w(vidmem + offset + count, BLANK_MEM, 1);\n\t}\n\tmemcpy_w(screen + offset, screen + offset + 1, count);\n\tmemset_w(screen + offset + count, BLANK_MEM, 1);\n}\n\nvoid vgacon_update_curpos(struct vconsole *vc)\n{\n\tunsigned short int curpos;\n\n\tif(vc->flags & CONSOLE_HAS_FOCUS) {\n\t\tcurpos = (vc->y * vc->columns) + vc->x;\n\t\toutport_b(video.port + CRT_INDEX, CRT_CURSOR_POS_HI);\n\t\toutport_b(video.port + CRT_DATA, (curpos >> 8) & 0xFF);\n\t\toutport_b(video.port + CRT_INDEX, CRT_CURSOR_POS_LO);\n\t\toutport_b(video.port + CRT_DATA, (curpos & 0xFF));\n\t}\n}\n\nvoid vgacon_show_cursor(struct vconsole *vc, int mode)\n{\n\tint status;\n\n\tswitch(mode) {\n\t\tcase COND:\n\t\t\tif(!(video.flags & VPF_CURSOR_ON)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t/* fall through */\n\t\tcase ON:\n\t\t\toutport_b(video.port + CRT_INDEX, CRT_CURSOR_STR);\n\t\t\tstatus = inport_b(video.port + CRT_DATA);\n\t\t\toutport_b(video.port + CRT_DATA, status & CURSOR_MASK);\n\t\t\tvideo.flags |= VPF_CURSOR_ON;\n\t\t\tbreak;\n\t\tcase OFF:\n\t\t\toutport_b(video.port + CRT_INDEX, CRT_CURSOR_STR);\n\t\t\tstatus = inport_b(video.port + CRT_DATA);\n\t\t\toutport_b(video.port + CRT_DATA, status | CURSOR_DISABLE);\n\t\t\tvideo.flags &= ~VPF_CURSOR_ON;\n\t\t\tbreak;\n\t}\n}\n\nvoid vgacon_get_curpos(struct vconsole *vc)\n{\n\tunsigned short int curpos;\n\n\toutport_b(video.port + CRT_INDEX, CRT_CURSOR_POS_HI);\n\tcurpos = inport_b(video.port + CRT_DATA) << 8;\n\toutport_b(video.port + CRT_INDEX, CRT_CURSOR_POS_LO);\n\tcurpos |= inport_b(video.port + CRT_DATA);\n\n\tvc->x = curpos % vc->columns;\n\tvc->y = curpos / vc->columns;\n}\t\n\nvoid vgacon_write_screen(struct vconsole *vc, int from, int count, short int color)\n{\n\tshort int *vidmem, *screen;\n\n\tif(vc->flags & CONSOLE_HAS_FOCUS) {\n\t\tvidmem = (short int *)vc->vidmem;\n\t\tmemset_w(vidmem + from, color, count);\n\t}\n\tscreen = vc->screen;\n\tmemset_w(screen + from, color, count);\n}\n\nvoid vgacon_blank_screen(struct vconsole *vc)\n{\n\tshort int *vidmem;\n\n\tif(vc->flags & CONSOLE_BLANKED) {\n\t\treturn;\n\t}\n\n\tif(vc->flags & CONSOLE_HAS_FOCUS) {\n\t\tvidmem = (short int *)vc->vidmem;\n\t\tmemset_w(vidmem, BLANK_MEM, SCREEN_SIZE);\n\t}\n\tvc->flags |= CONSOLE_BLANKED;\n\tvgacon_show_cursor(vc, OFF);\n}\n\nvoid vgacon_scroll_screen(struct vconsole *vc, int top, int mode)\n{\n\tint n, offset, count;\n\tshort int *vidmem, *screen;\n\n\tvidmem = (short int *)vc->vidmem;\n\tscreen = vc->screen;\n\n\tif(!top) {\n\t\ttop = vc->top;\n\t}\n\tswitch(mode) {\n\t\tcase SCROLL_UP:\n\t\t\tcount = vc->columns * (vc->lines - top - 1);\n\t\t\toffset = top * vc->columns;\n\t\t\ttop = (top + 1) * vc->columns;\n\t\t\tif(vc->flags & CONSOLE_HAS_FOCUS) {\n\t\t\t\tmemcpy_w(vidmem + offset, screen + top, count);\n\t\t\t\tmemset_w(vidmem + offset + count, BLANK_MEM, vc->columns);\n\t\t\t}\n\t\t\tmemcpy_w(screen + offset, screen + top, count);\n\t\t\tmemset_w(screen + offset + count, BLANK_MEM, vc->columns);\n\t\t\tbreak;\n\t\tcase SCROLL_DOWN:\n\t\t\tcount = vc->columns;\n\t\t\tfor(n = vc->lines - 1; n > top; n--) {\n\t\t\t\tmemcpy_w(screen + (vc->columns * n), screen + (vc->columns * (n - 1)), count);\n\t\t\t\tif(vc->flags & CONSOLE_HAS_FOCUS) {\n\t\t\t\t\tmemcpy_w(vidmem + (vc->columns * n), screen + (vc->columns * (n - 1)), count);\n\t\t\t\t}\n\t\t\t}\n\t\t\tmemset_w(screen + (top * vc->columns), BLANK_MEM, count);\n\t\t\tif(vc->flags & CONSOLE_HAS_FOCUS) {\n\t\t\t\tmemset_w(vidmem + (top * vc->columns), BLANK_MEM, count);\n\t\t\t}\n\t\t\tbreak;\n\t}\n\treturn;\n}\n\nvoid vgacon_restore_screen(struct vconsole *vc)\n{\n\tshort int *vidmem;\n\n\tif(vc->flags & CONSOLE_HAS_FOCUS) {\n\t\tvidmem = (short int *)vc->vidmem;\n\t\tmemcpy_w(vidmem, vc->screen, SCREEN_SIZE);\n\t}\n}\n\nvoid vgacon_screen_on(struct vconsole *vc)\n{\n\tunsigned int flags;\n\tstruct callout_req creq;\n\n\tif(screen_is_off) {\n\t\tSAVE_FLAGS(flags); CLI();\n\t\tinport_b(INPUT_STAT1);\n\t\tinport_b(0x3BA);\n\t\toutport_b(ATTR_CONTROLLER, ATTR_CONTROLLER_PAS);\n\t\tRESTORE_FLAGS(flags);\n\t}\n\n\tif(BLANK_INTERVAL) {\n\t\tcreq.fn = vgacon_screen_off;\n\t\tcreq.arg = 0;\n\t\tadd_callout(&creq, BLANK_INTERVAL);\n\t}\n}\n\nvoid vgacon_screen_off(unsigned int arg)\n{\n\tunsigned int flags;\n\n\tscreen_is_off = 1;\n\tSAVE_FLAGS(flags); CLI();\n\tinport_b(INPUT_STAT1);\n\tinport_b(0x3BA);\n\toutport_b(ATTR_CONTROLLER, 0);\n\tRESTORE_FLAGS(flags);\n}\n\nvoid vgacon_buf_scroll(struct vconsole *vc, int mode)\n{\n\tshort int *vidmem;\n\n\tif(video.buf_y <= SCREEN_LINES) {\n\t\treturn;\n\t}\n\n\tvidmem = (short int *)vc->vidmem;\n\tif(mode == SCROLL_UP) {\n\t\tif(video.buf_top < 0) {\n\t\t\treturn;\n\t\t}\n\t\tif(!video.buf_top) {\n\t\t\tvideo.buf_top = (video.buf_y - SCREEN_LINES + 1) * SCREEN_COLS;\n\t\t}\n\t\tvideo.buf_top -= (SCREEN_LINES / 2) * SCREEN_COLS;\n\t\tif(video.buf_top < 0) {\n\t\t\tvideo.buf_top = 0;\n\t\t}\n\t\tmemcpy_w(vidmem, vcbuf + video.buf_top, SCREEN_SIZE);\n\t\tif(!video.buf_top) {\n\t\t\tvideo.buf_top = -1;\n\t\t}\n\t\tvgacon_show_cursor(vc, OFF);\n\t\treturn;\n\t}\n\tif(mode == SCROLL_DOWN) {\n\t\tif(!video.buf_top) {\n\t\t\treturn;\n\t\t}\n\t\tif(video.buf_top == video.buf_y * SCREEN_COLS) {\n\t\t\treturn;\n\t\t}\n\t\tif(video.buf_top < 0) {\n\t\t\tvideo.buf_top = 0;\n\t\t}\n\t\tvideo.buf_top += (SCREEN_LINES / 2) * SCREEN_COLS;\n\t\tif(video.buf_top >= (video.buf_y - SCREEN_LINES + 1) * SCREEN_COLS) {\n\t\t\tvgacon_restore_screen(vc);\n\t\t\tvideo.buf_top = 0;\n\t\t\tvgacon_show_cursor(vc, ON);\n\t\t\tvgacon_update_curpos(vc);\n\t\t\treturn;\n\t\t}\n\t\tmemcpy_w(vidmem, vcbuf + video.buf_top, SCREEN_SIZE);\n\t\treturn;\n\t}\n}\n\nvoid vgacon_cursor_blink(unsigned int arg)\n{\n\t/* not used */\n}\n\nvoid vgacon_init(void)\n{\n\tshort int *hw_detected;;\n\n\t/* find out the VGA type from the BIOS Data Area */\n\thw_detected = (short int *)(bios_data + 0x10);\n\tif((*hw_detected & 0x30) == 0x30) {\n\t\t/* monochrome = 0x30 */\n\t\tvideo.address = (unsigned int *)(MONO_ADDR + PAGE_OFFSET);\n\t\tvideo.port = MONO_6845_ADDR;\n\t\tstrcpy((char *)video.signature, \"VGA monochrome 80x25\");\n\t} else {\n\t\t/* color = 0x00 || 0x20 */\n\t\tvideo.address = (unsigned int *)(COLOR_ADDR + PAGE_OFFSET);\n\t\tvideo.port = COLOR_6845_ADDR;\n\t\tstrcpy((char *)video.signature, \"VGA color 80x25\");\n\t}\n\n\t/* some parameters already set in multiboot.c */\n\n\tvideo.put_char = vgacon_put_char;\n\tvideo.insert_char = vgacon_insert_char;\n\tvideo.delete_char = vgacon_delete_char;\n\tvideo.update_curpos = vgacon_update_curpos;\n\tvideo.show_cursor = vgacon_show_cursor;\n\tvideo.get_curpos = vgacon_get_curpos;\n\tvideo.write_screen = vgacon_write_screen;\n\tvideo.blank_screen = vgacon_blank_screen;\n\tvideo.scroll_screen = vgacon_scroll_screen;\n\tvideo.restore_screen = vgacon_restore_screen;\n\tvideo.screen_on = vgacon_screen_on;\n\tvideo.buf_scroll = vgacon_buf_scroll;\n\tvideo.cursor_blink = vgacon_cursor_blink;\n\n\tmemcpy_w(vcbuf, video.address, SCREEN_SIZE * 2);\n}\n"
  },
  {
    "path": "drivers/video/video.c",
    "content": "/*\n * fiwix/drivers/video/video.c\n *\n * Copyright 2021-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/config.h>\n#include <fiwix/vgacon.h>\n#include <fiwix/fb.h>\n#include <fiwix/fbcon.h>\n#include <fiwix/bga.h>\n#include <fiwix/console.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nvoid video_init(void)\n{\n\tmemset_b(vcbuf, 0, (video.columns * video.lines * SCREENS_LOG * 2 * sizeof(short int)));\n\n\tif(video.flags & VPF_VGA) {\n\t\tvgacon_init();\n\t\treturn;\n\t}\n\n#ifdef CONFIG_PCI\n#ifdef CONFIG_BGA\n\tif(video.flags & VPF_VESAFB) {\n\t\tbga_init();\n\t}\n#endif /* CONFIG_BGA */\n#endif /* CONFIG_PCI */\n\n\tif(video.flags & VPF_VESAFB) {\n\t\tfb_init();\n\t\tfbcon_init();\n\t}\n}\n"
  },
  {
    "path": "fiwix.ld",
    "content": "/*\n * Linker script for the Fiwix kernel.\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/linker.h>\n\nOUTPUT_FORMAT(\"elf32-i386\")\nOUTPUT_ARCH(\"i386\")\nENTRY(_start)\t\t\t/* entry point */\nvaddr = PAGE_OFFSET;\t\t/* virtual start address */\npaddr = KERNEL_ADDR;\t\t/* physical address at 1MB */\n\n/* define output sections */\nSECTIONS\n{\n\t. = paddr;\n\n\t/* kernel setup code */\n\t.setup ALIGN(4096) :\n\t{\n\t\t*(.setup)\n\t}\n\n\t. += vaddr;\n\n\t/* kernel code */\n\t.text : AT(ADDR(.text) - vaddr)\n\t{\n\t\t*(.text)\n\t}\n\t_etext = .;\n\n\t/* initialized data */\n\t.data ALIGN(4096) : AT(ADDR(.data) - vaddr)\n\t{\n\t\t*(.data)\n\t\t*(.rodata*)\n\t}\n\t_edata = .;\n\n\t/* uninitialized data */\n\t.bss ALIGN(4096) : AT(ADDR(.bss) - vaddr)\n\t{\n\t\t*(COMMON*)\n\t\t*(.bss*)\n\t}\n\t_end = .;\n\n\t/* remove information not needed */\n\t/DISCARD/ :\n\t{\n\t\t*(.eh_frame)\n\t}\n}\n"
  },
  {
    "path": "fs/Makefile",
    "content": "# fiwix/fs/Makefile\n#\n# Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n# Distributed under the terms of the Fiwix License.\n#\n\n.c.o:\n\t$(CC) $(CFLAGS) -c -o $@ $<\n\nDIRS = minix ext2 pipefs iso9660 procfs sockfs devpts\nOBJS = filesystems.o devices.o buffer.o fd.o locks.o super.o inode.o \\\n\tnamei.o elf.o script.o\n\nall:\t$(OBJS)\n\t@for n in $(DIRS) ; do (cd $$n ; $(MAKE)) ; done\n\nclean:\n\t@for n in $(DIRS) ; do (cd $$n ; $(MAKE) clean) ; done\n\trm -f *.o\n\n"
  },
  {
    "path": "fs/buffer.c",
    "content": "/*\n * fiwix/fs/buffer.c\n *\n * Copyright 2018-2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/sleep.h>\n#include <fiwix/sched.h>\n#include <fiwix/buffer.h>\n#include <fiwix/devices.h>\n#include <fiwix/fs.h>\n#include <fiwix/mm.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n#include <fiwix/stat.h>\n#include <fiwix/blk_queue.h>\n\n#define NR_BUF_HASH\t\t(buffer_hash_table_size / sizeof(unsigned int))\n#define BUFFER_HASH(dev, block)\t(((__dev_t)(dev) ^ (__blk_t)(block)) % (NR_BUF_HASH))\n#define BUFHEAD_INDEX(size)\t((size / BLKSIZE_1K) - 1)\n\n#define NO_GROW\t\t0\n#define GROW_IF_NEEDED\t1\n\nstruct buffer *buffer_table;\t\t/* buffer pool */\nstruct buffer **buffer_hash_table;\n\n/* [0] = 1KB, [1] = 2KB, [2] = unused, [3] = 4KB */\nstruct buffer *buffer_head[4];\t\t/* heads of free list */\nstruct buffer *buffer_dirty_head[4];\t/* heads of dirty list */\n\nstatic struct resource sync_resource = { 0, 0 };\n\nstatic struct buffer *add_buffer_to_pool(void)\n{\n\tstruct buffer *buf;\n\n\tif(!(buf = (struct buffer *)kmalloc(sizeof(struct buffer)))) {\n\t\treturn NULL;\n\t}\n\tmemset_b(buf, 0, sizeof(struct buffer));\n\n\tif(!buffer_table) {\n\t\tbuffer_table = buf;\n\t} else {\n\t\tbuf->prev = buffer_table->prev;\n\t\tbuffer_table->prev->next = buf;\n\t}\n\tbuffer_table->prev = buf;\n\tkstat.nr_buffers++;\n\treturn buf;\n}\n\nstatic void del_buffer_from_pool(struct buffer *buf)\n{\n\tstruct buffer *tmp;\n\n\ttmp = buf;\n\n\tif(!buf->next && !buf->prev) {\n\t\tprintk(\"WARNING: %s(): trying to delete an unexistent buffer (block %d).\\n\", __FUNCTION__, buf->block);\n\t\treturn;\n\t}\n\n\tif(buf->next) {\n\t\tbuf->next->prev = buf->prev;\n\t}\n\tif(buf->prev) {\n\t\tif(buf != buffer_table) {\n\t\t\tbuf->prev->next = buf->next;\n\t\t}\n\t}\n\tif(!buf->next) {\n\t\tbuffer_table->prev = buf->prev;\n\t}\n\tif(buf == buffer_table) {\n\t\tbuffer_table = buf->next;\n\t}\n\n\tkfree((unsigned int)tmp);\n\tkstat.nr_buffers--;\n}\n\nstatic void insert_to_hash(struct buffer *buf)\n{\n\tstruct buffer **h;\n\tint i;\n\n\ti = BUFFER_HASH(buf->dev, buf->block);\n\th = &buffer_hash_table[i];\n\n\tif(!*h) {\n\t\t*h = buf;\n\t\t(*h)->prev_hash = (*h)->next_hash = NULL;\n\t} else {\n\t\tbuf->prev_hash = NULL;\n\t\tbuf->next_hash = *h;\n\t\t(*h)->prev_hash = buf;\n\t\t*h = buf;\n\t}\n}\n\nstatic void remove_from_hash(struct buffer *buf)\n{\n\tstruct buffer **h;\n\tint i;\n\n\ti = BUFFER_HASH(buf->dev, buf->block);\n\th = &buffer_hash_table[i];\n\n\twhile(*h) {\n\t\tif(*h == buf) {\n\t\t\tif((*h)->next_hash) {\n\t\t\t\t(*h)->next_hash->prev_hash = (*h)->prev_hash;\n\t\t\t}\n\t\t\tif((*h)->prev_hash) {\n\t\t\t\t(*h)->prev_hash->next_hash = (*h)->next_hash;\n\t\t\t}\n\t\t\tif(h == &buffer_hash_table[i]) {\n\t\t\t\t*h = (*h)->next_hash;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\th = &(*h)->next_hash;\n\t}\n}\n\nstatic void insert_on_dirty_list(struct buffer *buf)\n{\n\tstruct buffer *h;\n\tint index;\n\n\tindex = BUFHEAD_INDEX(buf->size);\n\th = buffer_dirty_head[index];\n\n\tif(buf->prev_dirty || buf->next_dirty) {\n\t\treturn;\n\t}\n\tif(!h) {\n\t\tbuffer_dirty_head[index] = buf;\n\t\th = buffer_dirty_head[index];\n\t} else {\n\t\tbuf->prev_dirty = h->prev_dirty;\n\t\th->prev_dirty->next_dirty = buf;\n\t}\n\th->prev_dirty = buf;\n\n\tkstat.dirty_buffers += (index + 1);\n\tkstat.nr_dirty_buffers++;\n        if(kstat.nr_dirty_buffers > kstat.max_dirty_buffers) {\n                wakeup(&kbdflushd);\n        }\n}\n\nstatic void remove_from_dirty_list(struct buffer *buf)\n{\n\tstruct buffer *h;\n\tint index;\n\n\tindex = BUFHEAD_INDEX(buf->size);\n\th = buffer_dirty_head[index];\n\n\tif(!h) {\n\t\treturn;\n\t}\n\n\tif(buf->next_dirty) {\n\t\tbuf->next_dirty->prev_dirty = buf->prev_dirty;\n\t}\n\tif(buf->prev_dirty) {\n\t\tif(buf != h) {\n\t\t\tbuf->prev_dirty->next_dirty = buf->next_dirty;\n\t\t}\n\t}\n\tif(!buf->next_dirty) {\n\t\th->prev_dirty = buf->prev_dirty;\n\t}\n\tif(buf == h) {\n\t\tbuffer_dirty_head[index] = buf->next_dirty;\n\t}\n\tbuf->prev_dirty = buf->next_dirty = NULL;\n\n\tkstat.dirty_buffers -= (index + 1);\n\tkstat.nr_dirty_buffers--;\n}\n\nstatic void insert_on_free_list(struct buffer *buf)\n{\n\tstruct buffer *h;\n\tint index;\n\n\tindex = BUFHEAD_INDEX(buf->size);\n\th = buffer_head[index];\n\n\tif(!h) {\n\t\tbuffer_head[index] = buf;\n\t\th = buffer_head[index];\n\t} else {\n\t\tbuf->prev_free = h->prev_free;\n\n\t\t/*\n\t\t * If is not marked as valid then this buffer\n\t\t * is placed at the beginning of the free list.\n\t\t */\n\t\tif(!(buf->flags & BUFFER_VALID)) {\n\t\t\tbuf->next_free = h;\n\t\t\th->prev_free = buf;\n\t\t\tbuffer_head[index] = buf;\n\t\t\treturn;\n\t\t} else {\n\t\t\th->prev_free->next_free = buf;\n\t\t}\n\t}\n\th->prev_free = buf;\n}\n\nstatic void append_on_free_list(struct buffer *buf)\n{\n\tstruct buffer *h;\n\tint index;\n\n\tindex = BUFHEAD_INDEX(buf->size);\n\th = buffer_head[index];\n\n\tif(!h) {\n\t\tbuffer_head[index] = buf;\n\t\th = buffer_head[index];\n\t} else {\n\t\tbuf->prev_free = h->prev_free;\n\t\th->prev_free->next_free = buf;\n\t}\n\th->prev_free = buf;\n}\n\nstatic void remove_from_free_list(struct buffer *buf)\n{\n\tstruct buffer *h;\n\tint index;\n\n\tindex = BUFHEAD_INDEX(buf->size);\n\th = buffer_head[index];\n\n\tif(!h) {\n\t\treturn;\n\t}\n\n\tif(buf->next_free) {\n\t\tbuf->next_free->prev_free = buf->prev_free;\n\t}\n\tif(buf->prev_free) {\n\t\tif(buf != h) {\n\t\t\tbuf->prev_free->next_free = buf->next_free;\n\t\t}\n\t}\n\tif(!buf->next_free) {\n\t\th->prev_free = buf->prev_free;\n\t}\n\tif(buf == h) {\n\t\tbuffer_head[index] = buf->next_free;\n\t}\n\tbuf->prev_free = buf->next_free = NULL;\n}\n\nstatic void buffer_wait(struct buffer *buf)\n{\n\tunsigned int flags;\n\n\tfor(;;) {\n\t\tSAVE_FLAGS(flags); CLI();\n\t\tif(buf->flags & BUFFER_LOCKED) {\n\t\t\tsleep(&buffer_wait, PROC_UNINTERRUPTIBLE);\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t\tRESTORE_FLAGS(flags);\n\t}\n\tbuf->flags |= BUFFER_LOCKED;\n\tRESTORE_FLAGS(flags);\n}\n\nstatic struct buffer *create_buffers(int size)\n{\n\tstruct buffer *buf, *prev, *first;\n\tchar *data;\n\tint n;\n\n\tif(!(data = (char *)kmalloc(PAGE_SIZE))) {\n\t\tprintk(\"%s(): returning NULL\\n\", __FUNCTION__);\n\t\treturn NULL;\n\t}\n\n\tbuf = prev = first = NULL;\n\tfor(n = 0; n < (PAGE_SIZE / size); n++) {\n\t\tif(!(buf = add_buffer_to_pool())) {\n\t\t\tif(!n) {\n\t\t\t\tkfree((unsigned int)data);\n\t\t\t\treturn NULL;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tif(prev) {\n\t\t\tbrelse(prev);\n\t\t\tprev->next_sibling = buf;\n\t\t}\n\t\tbuf->data = data + (n * size);\n\t\tbuf->size = size;\n\t\tbuf->first_sibling = first;\n\t\tkstat.buffers_size += size / 1024;\n\t\tprev = buf;\n\t\tif(!first) {\n\t\t\tfirst = buf;\n\t\t}\n\t}\n\tbuf = buf ? buf : prev;\n\tif(buf) {\n\t\tbuf->flags |= BUFFER_LOCKED;\n\t}\n\treturn buf;\n}\n\nstatic struct buffer *get_free_buffer(int mode, int size)\n{\n\tunsigned int flags;\n\tstruct buffer *buf;\n\tint index, min;\n\n\tindex = BUFHEAD_INDEX(size);\n\tbuf = buffer_head[index];\n\n\t/*\n\t * We check buf->dev to see if this buffer has been already used\n\t * and, if so, then we know that there aren't more unused buffers,\n\t * so let's try to create new ones instead of reusing them.\n\t */\n\tif(!buf || (buf && buf->dev)) {\n\t\tif(mode == GROW_IF_NEEDED) {\n\t\t\tmin = (kstat.total_mem_pages * FREE_PAGES_RATIO) / 100;\n\t\t\tif(kstat.free_pages > min) {\n\t\t\t\tif((buf = create_buffers(size))) {\n\t\t\t\t\treturn buf;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfor(;;) {\n\t\tSAVE_FLAGS(flags); CLI();\n\t\tif(!(buf = buffer_head[index])) {\n\t\t\t/* no more buffers in this free list */\n\t\t\tRESTORE_FLAGS(flags);\n\t\t\treturn NULL;\n\t\t}\n\t\tif(buf->flags & BUFFER_LOCKED) {\n\t\t\tsleep(&buffer_wait, PROC_UNINTERRUPTIBLE);\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t\tRESTORE_FLAGS(flags);\n\t}\n\n\tremove_from_free_list(buf);\n\tbuf->flags |= BUFFER_LOCKED;\n\n\tRESTORE_FLAGS(flags);\n\treturn buf;\n}\n\nstatic struct buffer *get_dirty_buffer(int size)\n{\n\tunsigned int flags;\n\tstruct buffer *buf;\n\tint index;\n\n\tindex = BUFHEAD_INDEX(size);\n\n\tfor(;;) {\n\t\tSAVE_FLAGS(flags); CLI();\n\t\tif(!(buf = buffer_dirty_head[index])) {\n\t\t\t/* no buffers in this dirty list */\n\t\t\tRESTORE_FLAGS(flags);\n\t\t\treturn NULL;\n\t\t}\n\t\tif(buf->flags & BUFFER_LOCKED) {\n\t\t\tsleep(&buffer_wait, PROC_UNINTERRUPTIBLE);\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t\tRESTORE_FLAGS(flags);\n\t}\n\n\tremove_from_dirty_list(buf);\n\tbuf->flags |= BUFFER_LOCKED;\n\n\tRESTORE_FLAGS(flags);\n\treturn buf;\n}\n\nstatic int sync_one_buffer(struct buffer *buf)\n{\n\tstruct device *d;\n\tint errno;\n\n\tif(!(d = get_device(BLK_DEV, buf->dev))) {\n\t\tprintk(\"WARNING: %s(): block device %d,%d not registered!\\n\", __FUNCTION__, MAJOR(buf->dev), MINOR(buf->dev));\n\t\treturn 1;\n\t}\n\n\tif((errno = do_blk_request(d, d->fsop->write_block, buf)) < 0) {\n\t\tif(errno == -EROFS) {\n\t\t\tprintk(\"WARNING: %s(): unable to write block %d, write protection on device %d,%d.\\n\", __FUNCTION__, buf->block, MAJOR(buf->dev), MINOR(buf->dev));\n\t\t} else {\n\t\t\tprintk(\"WARNING: %s(): unable to write block %d, I/O error on device %d,%d.\\n\", __FUNCTION__, buf->block, MAJOR(buf->dev), MINOR(buf->dev));\n\t\t}\n\t\treturn 1;\n\t}\n\tbuf->flags &= ~BUFFER_DIRTY;\n\treturn 0;\n}\n\nstatic struct buffer *search_buffer_hash(__dev_t dev, __blk_t block, int size)\n{\n\tstruct buffer *buf;\n\tint i;\n\n\ti = BUFFER_HASH(dev, block);\n\tbuf = buffer_hash_table[i];\n\n\twhile(buf) {\n\t\tif(buf->dev == dev && buf->block == block && buf->size == size) {\n\t\t\treturn buf;\n\t\t}\n\t\tbuf = buf->next_hash;\n\t}\n\n\treturn NULL;\n}\n\nstatic struct buffer *getblk(__dev_t dev, __blk_t block, int size)\n{\n\tunsigned int flags;\n\tstruct buffer *buf;\n\n\tfor(;;) {\n\t\tif((buf = search_buffer_hash(dev, block, size))) {\n\t\t\tSAVE_FLAGS(flags); CLI();\n\t\t\tif(buf->flags & BUFFER_LOCKED) {\n\t\t\t\tsleep(&buffer_wait, PROC_UNINTERRUPTIBLE);\n\t\t\t\tRESTORE_FLAGS(flags);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbuf->flags |= BUFFER_LOCKED;\n\t\t\tremove_from_free_list(buf);\n\t\t\tRESTORE_FLAGS(flags);\n\t\t\treturn buf;\n\t\t}\n\n\t\tif(!(buf = get_free_buffer(GROW_IF_NEEDED, size))) {\n\t\t\twakeup(&kswapd);\n\t\t\tsleep(&get_free_buffer, PROC_UNINTERRUPTIBLE);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif(buf->flags & BUFFER_DIRTY) {\n\t\t\tif(!sync_one_buffer(buf)) {\n\t\t\t\tremove_from_dirty_list(buf);\n\t\t\t}\n\t\t\tbrelse(buf);\n\t\t\tcontinue;\n\t\t}\n\n\t\tSAVE_FLAGS(flags); CLI();\n\t\tremove_from_hash(buf);\t/* remove it from its old hash */\n\t\tbuf->dev = dev;\n\t\tbuf->block = block;\n\t\tinsert_to_hash(buf);\n\t\tbuf->flags &= ~BUFFER_VALID;\n\t\tRESTORE_FLAGS(flags);\n\t\treturn buf;\n\t}\n}\n\n/* read a group of blocks */\nint gbread(struct device *d, struct blk_request *brh)\n{\n\tstruct blk_request *br;\n\tstruct buffer *buf;\n\n\tbr = brh->next_group;\n\twhile(br) {\n\t\tif(!(br->flags & BRF_NOBLOCK)) {\n\t\t\tif((buf = getblk(br->dev, br->block, br->size))) {\n\t\t\t\tbr->buffer = buf;\n\t\t\t\tif(buf->flags & BUFFER_VALID) {\n\t\t\t\t\tbr = br->next_group;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tbrh->left++;\n\t\t\t\tadd_blk_request(br);\n\t\t\t} else {\n\t\t\t\t/* cancel the previous requests already queued */\n\t\t\t\t/* FIXME: not tested!! */\n\t\t\t\tbr = brh->next_group;\n\t\t\t\twhile(br) {\n\t\t\t\t\tif(!br->status) {\n\t\t\t\t\t\tbr->status = BR_COMPLETED;\n\t\t\t\t\t}\n\t\t\t\t\tbr = br->next_group;\n\t\t\t\t}\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t}\n\t\tbr = br->next_group;\n\t}\n\n\trun_blk_request(d);\n\tif(brh->left) {\n\t\tsleep(brh, PROC_UNINTERRUPTIBLE);\n\t}\n\treturn brh->errno;\n}\n\n/* read a single block */\nstruct buffer *bread(__dev_t dev, __blk_t block, int size)\n{\n\tstruct buffer *buf;\n\tstruct device *d;\n\n\tif((buf = getblk(dev, block, size))) {\n\t\tif(buf->flags & BUFFER_VALID) {\n\t\t\treturn buf;\n\t\t}\n\t\tif(!(d = get_device(BLK_DEV, dev))) {\n\t\t\treturn NULL;\n\t\t}\n\t\tif(do_blk_request(d, d->fsop->read_block, buf) == size) {\n\t\t\tbuf->flags |= BUFFER_VALID;\n\t\t\treturn buf;\n\t\t}\n\t\tbrelse(buf);\n\t}\n\tprintk(\"WARNING: %s(): returning NULL!\\n\", __FUNCTION__);\n\treturn NULL;\n}\n\nvoid bwrite(struct buffer *buf)\n{\n\tbuf->flags |= (BUFFER_DIRTY | BUFFER_VALID);\n\tbrelse(buf);\n}\n\nvoid brelse(struct buffer *buf)\n{\n\tunsigned int flags;\n\n\tSAVE_FLAGS(flags); CLI();\n\n\tif(buf->flags & BUFFER_DIRTY) {\n\t\tinsert_on_dirty_list(buf);\n\t}\n\n\tinsert_on_free_list(buf);\n\tbuf->flags &= ~BUFFER_LOCKED;\n\n\tRESTORE_FLAGS(flags);\n\n\twakeup(&get_free_buffer);\n\twakeup(&buffer_wait);\n}\n\nvoid sync_buffers(__dev_t dev)\n{\n\tstruct buffer *buf, *first;\n\tint flushed, size;\n\n\tlock_resource(&sync_resource);\n\tflushed = 0;\n\tfor(size = BLKSIZE_1K; size <= PAGE_SIZE; size <<= 1) {\n\t\tfirst = NULL;\n\t\tfor(;;) {\n\t\t\tif(!(buf = get_dirty_buffer(size))) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif(first == buf) {\n\t\t\t\tinsert_on_dirty_list(buf);\n\t\t\t\tbuf->flags &= ~BUFFER_LOCKED;\n\t\t\t\tflushed = 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif(!dev || buf->dev == dev) {\n\t\t\t\tif(sync_one_buffer(buf)) {\n\t\t\t\t\tinsert_on_dirty_list(buf);\n\t\t\t\t\tbuf->flags &= ~BUFFER_LOCKED;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tflushed = 1;\n\t\t\t} else {\n\t\t\t\tif(!first) {\n\t\t\t\t\tfirst = buf;\n\t\t\t\t}\n\t\t\t\tinsert_on_dirty_list(buf);\n\t\t\t}\n\t\t\tbuf->flags &= ~BUFFER_LOCKED;\n\t\t}\n\t}\n\tif(flushed) {\n\t\twakeup(&buffer_wait);\n\t}\n\tunlock_resource(&sync_resource);\n}\n\nvoid invalidate_buffers(__dev_t dev)\n{\n\tunsigned int flags;\n\tstruct buffer *buf;\n\n\tbuf = buffer_table;\n\tSAVE_FLAGS(flags); CLI();\n\n\twhile(buf) {\n\t\tif(!(buf->flags & BUFFER_LOCKED) && buf->dev == dev) {\n\t\t\tbuffer_wait(buf);\n\t\t\tremove_from_hash(buf);\n\t\t\tbuf->flags &= ~(BUFFER_VALID | BUFFER_LOCKED);\n\t\t\twakeup(&buffer_wait);\n\t\t}\n\t\tbuf = buf->next;\n\t}\n\n\tRESTORE_FLAGS(flags);\n\t/* FIXME: invalidate_pages(dev); */\n}\n\nstatic int reclaim_siblings(struct buffer *buf)\n{\n\tstruct buffer *orig, *tmp;\n\tunsigned int flags;\n\n\torig = buf;\n\n\tif(buf->first_sibling) {\n\t\tbuf = buf->first_sibling;\n\t}\n\t/* abort if one of the siblings is locked */\n\tdo {\n\t\tif(buf != orig) {\n\t\t\tif(buf->flags & BUFFER_LOCKED) {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t}\n\t\tbuf = buf->next_sibling;\n\t} while(buf);\n\n\t/* OK, all siblings are eligible to be freed up, let's lock them all */\n\tSAVE_FLAGS(flags); CLI();\n\tbuf = orig;\n\tif(buf->first_sibling) {\n\t\tbuf = buf->first_sibling;\n\t}\n\tdo {\n\t\tif(buf != orig) {\n\t\t\tbuf->flags |= BUFFER_LOCKED;\n\t\t}\n\t\tbuf = buf->next_sibling;\n\t} while(buf);\n\tRESTORE_FLAGS(flags);\n\n\t/* now free them up */\n\tbuf = orig;\n\tif(buf->first_sibling) {\n\t\tbuf = buf->first_sibling;\n\t}\n\tdo {\n\t\tif(buf == orig) {\n\t\t\tbuf = buf->next_sibling;\n\t\t\tcontinue;\n\t\t}\n\t\tif(buf->flags & BUFFER_DIRTY) {\n\t\t\tif(!sync_one_buffer(buf)) {\n\t\t\t\tremove_from_dirty_list(buf);\n\t\t\t} else {\n\t\t\t\t/* FIXME: undo all locks and give up */\n\t\t\t}\n\t\t}\n\t\ttmp = buf;\n\t\tbuf = buf->next_sibling;\n\t\tremove_from_hash(tmp);\n\t\tremove_from_free_list(tmp);\n\t\tkstat.buffers_size -= tmp->size / 1024;\n\t\tdel_buffer_from_pool(tmp);\n\t} while(buf);\n\treturn 0;\n}\n\n/*\n * When kernel runs out of pages, kswapd is awaken to call this function which\n * goes across the buffer cache, freeing up to NR_BUF_RECLAIM pages.\n */\nint reclaim_buffers(void)\n{\n\tstruct buffer *buf;\n\tint size, found, reclaimed;\n\tunsigned int flags, mark;\n\n\tfound = reclaimed = 0;\n\tsize = BLKSIZE_1K;\n\tmark = kstat.uptime;\n\n\t/* iterate through all buffer sizes */\n\tSTI();\n\tfor(;;) {\n\t\tif((buf = get_free_buffer(NO_GROW, size))) {\n\t\t\tif(buf->mark == mark) {\n\t\t\t\tSAVE_FLAGS(flags); CLI();\n\t\t\t\tbuf->flags &= ~BUFFER_LOCKED;\n\t\t\t\tbuf->mark = 0;\n\t\t\t\tappend_on_free_list(buf);\n\t\t\t\tRESTORE_FLAGS(flags);\n\t\t\t\tgoto next;\n\t\t\t}\n\t\t\tfound++;\n\t\t\tif(buf->flags & BUFFER_DIRTY) {\n\t\t\t\tif(!sync_one_buffer(buf)) {\n\t\t\t\t\tremove_from_dirty_list(buf);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(reclaim_siblings(buf)) {\n\t\t\t\t/*\n\t\t\t\t * If one of the siblings is not eligible to be\n\t\t\t\t * freed up, then we release this buffer without\n\t\t\t\t * using brelse(), otherwise get_free_buffer()\n\t\t\t\t * will return the same buffer again.\n\t\t\t\t */\n\t\t\t\tSAVE_FLAGS(flags); CLI();\n\t\t\t\tbuf->flags &= ~BUFFER_LOCKED;\n\t\t\t\tbuf->mark = mark;\n\t\t\t\tappend_on_free_list(buf);\n\t\t\t\tRESTORE_FLAGS(flags);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tkfree((unsigned int)(buf->data) & PAGE_MASK);\n\t\t\tremove_from_hash(buf);\n\t\t\tkstat.buffers_size -= buf->size / 1024;\n\t\t\tdel_buffer_from_pool(buf);\n\t\t\tif(++reclaimed == NR_BUF_RECLAIM) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\nnext:\n\t\tsize <<= 1;\n\t\tif(size > PAGE_SIZE) {\n\t\t\tif(!found) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tsize = BLKSIZE_1K;\n\t\t\tfound = 0;\n\t\t}\n\t}\n\n\twakeup(&get_free_buffer);\n\twakeup(&buffer_wait);\n\n\t/*\n\t * If some buffers were reclaimed, then wakeup any process\n\t * waiting for a new page because release_page() won't do it.\n\t */\n\tif(reclaimed) {\n\t\twakeup(&get_free_page);\n\t}\n\treturn reclaimed;\n}\n\nint kbdflushd(void)\n{\n\tstruct buffer *buf, *first;\n\tint flushed, size;\n\n\tfor(;;) {\n\t\tsleep(&kbdflushd, PROC_INTERRUPTIBLE);\n\t\tflushed = 0;\n\n\t\tlock_resource(&sync_resource);\n\t\tfor(size = BLKSIZE_1K; size <= PAGE_SIZE; size <<= 1) {\n\t\t\tfirst = NULL;\n\t\t\tfor(;;) {\n\t\t\t\tif(!(buf = get_dirty_buffer(size))) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif(!(buf->flags & BUFFER_DIRTY)) {\n\t\t\t\t\tprintk(\"WARNING: %s(): a dirty buffer (dev %x, block %d, flags = %x) is not marked as dirty!\\n\", __FUNCTION__, buf->dev, buf->block, buf->flags);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif(first) {\n\t\t\t\t\tif(first == buf) {\n\t\t\t\t\t\tinsert_on_dirty_list(buf);\n\t\t\t\t\t\tbuf->flags &= ~BUFFER_LOCKED;\n\t\t\t\t\t\twakeup(&buffer_wait);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tfirst = buf;\n\t\t\t\t}\n\n\t\t\t\tif(sync_one_buffer(buf)) {\n\t\t\t\t\tinsert_on_dirty_list(buf);\n\t\t\t\t\tbuf->flags &= ~BUFFER_LOCKED;\n\t\t\t\t\twakeup(&buffer_wait);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tbuf->flags &= ~BUFFER_LOCKED;\n\t\t\t\twakeup(&buffer_wait);\n\t\t\t\tflushed++;\n\n\t\t\t\tif(flushed >= NR_BUF_RECLAIM) {\n\t\t\t\t\tif(kstat.nr_dirty_buffers < kstat.max_dirty_buffers) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tdo_sched();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tunlock_resource(&sync_resource);\n\t}\n}\n\nvoid buffer_init(void)\n{\n\tbuffer_table = NULL;\n\tmemset_b(buffer_head, 0, sizeof(buffer_head));\n\tmemset_b(buffer_dirty_head, 0, sizeof(buffer_dirty_head));\n\tkstat.max_dirty_buffers = (kstat.max_buffers_size * BUFFER_DIRTY_RATIO) / 100;\n\tmemset_b(buffer_hash_table, 0, buffer_hash_table_size);\n}\n"
  },
  {
    "path": "fs/devices.c",
    "content": "/*\n * fiwix/fs/devices.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/buffer.h>\n#include <fiwix/devices.h>\n#include <fiwix/fs.h>\n#include <fiwix/mm.h>\n#include <fiwix/process.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstruct device *chr_device_table[NR_CHRDEV];\nstruct device *blk_device_table[NR_BLKDEV];\n\nstruct fs_operations def_chr_fsop = {\n\t0,\n\t0,\n\n\tchr_dev_open,\n\tNULL,\t\t\t/* close */\n\tNULL,\t\t\t/* read */\n\tNULL,\t\t\t/* write */\n\tNULL,\t\t\t/* ioctl */\n\tNULL,\t\t\t/* llseek */\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lockup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* stats */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nstruct fs_operations def_blk_fsop = {\n\t0,\n\t0,\n\n\tblk_dev_open,\n\tblk_dev_close,\n\tblk_dev_read,\n\tblk_dev_write,\n\tblk_dev_ioctl,\n\tblk_dev_llseek,\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lockup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* stats */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nint register_device(int type, struct device *new_d)\n{\n\tstruct device **d;\n\tint n, minors;\n\n\tswitch(type) {\n\t\tcase CHR_DEV:\n\t\t\tif(new_d->major >= NR_CHRDEV) {\n\t\t\t\tprintk(\"%s(): character device major %d is greater than NR_CHRDEV (%d).\\n\", __FUNCTION__, new_d->major, NR_CHRDEV);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\td = &chr_device_table[new_d->major];\n\t\t\tbreak;\n\t\tcase BLK_DEV:\n\t\t\tif(new_d->major >= NR_BLKDEV) {\n\t\t\t\tprintk(\"%s(): block device major %d is greater than NR_BLKDEV (%d).\\n\", __FUNCTION__, new_d->major, NR_BLKDEV);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\td = &blk_device_table[new_d->major];\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tprintk(\"WARNING: %s(): invalid device type %d.\\n\", __FUNCTION__, type);\n\t\t\treturn 1;\n\t\t\tbreak;\n\t}\n\n\t/* make sure there are minors defined */\n\tfor(n = 0, minors = 0; n < 8; n++) {\n\t\tminors += new_d->minors[n];\n\t}\n\tif(!minors) {\n\t\tprintk(\"WARNING: %s(): device major %d with no defined minors.\\n\", __FUNCTION__, new_d->major);\n\t\treturn 1;\n\t}\n\n\tif(*d) {\n\t\tif(&(*d)->minors == &new_d->minors || ((*d)->next && &(*d)->next->minors == &new_d->minors)) {\n\t\t\treturn 1;\n\t\t}\n\t\tdo {\n\t\t\td = &(*d)->next;\n\t\t} while(*d);\n\t}\n\t*d = new_d;\n\n\treturn 0;\n}\n\nvoid unregister_device(int type, struct device *device)\n{\n\tstruct device **d, **tmp;\n\tint n;\n\n\t/* make sure there are not minors defined */\n\tfor(n = 0; n < 8; n++) {\n\t\tif(device->minors[n]) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\tswitch(type) {\n\t\tcase CHR_DEV:\n\t\t\td = &chr_device_table[device->major];\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tprintk(\"WARNING: %s(): invalid device type %d.\\n\", __FUNCTION__, type);\n\t\t\treturn;\n\t}\n\ttmp = NULL;\n\twhile(*d) {\n\t\tif(&(*d)->minors == &device->minors) {\n\t\t\tif(!tmp) {\n\t\t\t\t*d = (*d)->next;\n\t\t\t} else {\n\t\t\t\t*tmp = (*d)->next;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\ttmp = d;\n\t\td = &(*d)->next;\n\t}\n}\n\nstruct device *get_device(int type, __dev_t dev)\n{\n\tchar *name;\n\tunsigned char major;\n\tstruct device *d;\n\n\tmajor = MAJOR(dev);\n\n\tswitch(type) {\n\t\tcase CHR_DEV:\n\t\t\tif(major >= NR_CHRDEV) {\n\t\t\t\tprintk(\"%s(): character device major %d is greater than NR_CHRDEV (%d).\\n\", __FUNCTION__, major, NR_CHRDEV);\n\t\t\t\treturn NULL;\n\t\t\t}\n\t\t\td = chr_device_table[major];\n\t\t\tname = \"character\";\n\t\t\tbreak;\n\t\tcase BLK_DEV:\n\t\t\tif(major >= NR_BLKDEV) {\n\t\t\t\tprintk(\"%s(): block device major %d is greater than NR_BLKDEV (%d).\\n\", __FUNCTION__, major, NR_BLKDEV);\n\t\t\t\treturn NULL;\n\t\t\t}\n\t\t\td = blk_device_table[major];\n\t\t\tname = \"block\";\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tprintk(\"WARNING: %s(): invalid device type %d.\\n\", __FUNCTION__, type);\n\t\t\treturn NULL;\n\t}\n\n\twhile(d) {\n\t\tif(d->major == major) {\n\t\t\tif(TEST_MINOR(d->minors, MINOR(dev))) {\n\t\t\t\treturn d;\n\t\t\t}\n\t\t\td = d->next;\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\n\tprintk(\"WARNING: %s(): %s device %d,%d not found.\\n\", __FUNCTION__, name, major, MINOR(dev));\n\treturn NULL;\n}\n\nint chr_dev_open(struct inode *i, struct fd *f)\n{\n\tstruct device *d;\n\n\tif((d = get_device(CHR_DEV, i->rdev))) {\n\t\ti->fsop = d->fsop;\n\t\treturn i->fsop->open(i, f);\n\t}\n\n\treturn -ENXIO;\n}\n\nint blk_dev_open(struct inode *i, struct fd *f)\n{\n\tstruct device *d;\n\n\tif((d = get_device(BLK_DEV, i->rdev))) {\n\t\treturn d->fsop->open(i, f);\n\t}\n\n\treturn -ENXIO;\n}\n\nint blk_dev_close(struct inode *i, struct fd *f)\n{\n\tstruct device *d;\n\n\tif((d = get_device(BLK_DEV, i->rdev))) {\n\t\treturn d->fsop->close(i, f);\n\t}\n\n\treturn -ENXIO;\n}\n\nint blk_dev_read(struct inode *i, struct fd *f, char *buffer, __size_t count)\n{\n\t__blk_t block;\n\t__size_t total_read;\n\t__loff_t device_size;\n\tint n, blksize, blksize_bits;\n\tunsigned int boffset, bytes;\n\tstruct buffer *buf;\n\tstruct device *d;\n\n\tif(!(d = get_device(BLK_DEV, i->rdev))) {\n\t\treturn -ENXIO;\n\t}\n\n\ttotal_read = 0;\n\tif(!d->device_data) {\n\t\tprintk(\"%s(): don't know the size of the block device %d,%d.\\n\", __FUNCTION__, MAJOR(i->rdev), MINOR(i->rdev));\n\t\treturn -EIO;\n\t}\n\n\tblksize = ((unsigned int *)d->blksize)[MINOR(i->rdev)];\n\tdevice_size = ((unsigned int *)d->device_data)[MINOR(i->rdev)];\n\tdevice_size *= 1024LLU;\n\n\tfor(n = blksize, blksize_bits = 0; n != 1; n >>= 1) {\n\t\tblksize_bits++;\n\t}\n\n\tcount = (f->offset + count > device_size) ? device_size - f->offset : count;\n\tif(!count || f->offset > device_size) {\n\t\treturn 0;\n\t}\n\twhile(count) {\n\t\tboffset = f->offset & (blksize - 1);\t/* mod blksize */\n\t\tblock = (f->offset >> blksize_bits);\n\t\tif(!(buf = bread(i->rdev, block, blksize))) {\n\t\t\treturn -EIO;\n\t\t}\n\t\tbytes = blksize - boffset;\n\t\tbytes = MIN(bytes, count);\n\t\tmemcpy_b(buffer + total_read, buf->data + boffset, bytes);\n\t\ttotal_read += bytes;\n\t\tcount -= bytes;\n\t\tf->offset += bytes;\n\t\tbrelse(buf);\n\t}\n\treturn total_read;\n}\n\nint blk_dev_write(struct inode *i, struct fd *f, const char *buffer, __size_t count)\n{\n\t__blk_t block;\n\t__size_t total_written;\n\t__loff_t device_size;\n\tint n, blksize, blksize_bits;\n\tunsigned int boffset, bytes;\n\tstruct buffer *buf;\n\tstruct device *d;\n\n\tif(!(d = get_device(BLK_DEV, i->rdev))) {\n\t\treturn -ENXIO;\n\t}\n\n\ttotal_written = 0;\n\tif(!d->device_data) {\n\t\tprintk(\"%s(): don't know the size of the block device %d,%d.\\n\", __FUNCTION__, MAJOR(i->rdev), MINOR(i->rdev));\n\t\treturn -EIO;\n\t}\n\n\tblksize = ((unsigned int *)d->blksize)[MINOR(i->rdev)];\n\tdevice_size = ((unsigned int *)d->device_data)[MINOR(i->rdev)];\n\tdevice_size *= 1024LLU;\n\n\tfor(n = blksize, blksize_bits = 0; n != 1; n >>= 1) {\n\t\tblksize_bits++;\n\t}\n\n\tcount = (f->offset + count > device_size) ? device_size - f->offset : count;\n\tif(!count || f->offset > device_size) {\n\t\treturn -ENOSPC;\n\t}\n\twhile(count) {\n\t\tboffset = f->offset & (blksize - 1);\t/* mod blksize */\n\t\tblock = (f->offset >> blksize_bits);\n\t\tif(!(buf = bread(i->rdev, block, blksize))) {\n\t\t\treturn -EIO;\n\t\t}\n\t\tbytes = blksize - boffset;\n\t\tbytes = MIN(bytes, count);\n\t\tmemcpy_b(buf->data + boffset, buffer + total_written, bytes);\n\t\ttotal_written += bytes;\n\t\tcount -= bytes;\n\t\tf->offset += bytes;\n\t\tbwrite(buf);\n\t}\n\treturn total_written;\n}\n\nint blk_dev_ioctl(struct inode *i, struct fd *f, int cmd, unsigned int arg)\n{\n\tstruct device *d;\n\n\tif((d = get_device(BLK_DEV, i->rdev))) {\n\t\treturn d->fsop->ioctl(i, f, cmd, arg);\n\t}\n\n\treturn -ENXIO;\n}\n\n__loff_t blk_dev_llseek(struct inode *i, __loff_t offset)\n{\n\tstruct device *d;\n\n\tif((d = get_device(BLK_DEV, i->rdev))) {\n\t\treturn d->fsop->llseek(i, offset);\n\t}\n\n\treturn -ENXIO;\n}\n\nvoid dev_init(void)\n{\n\tmemset_b(chr_device_table, 0, sizeof(chr_device_table));\n\tmemset_b(blk_device_table, 0, sizeof(blk_device_table));\n}\n"
  },
  {
    "path": "fs/devpts/Makefile",
    "content": "# fiwix/fs/devpts/Makefile\n#\n# Copyright 2025, Jordi Sanfeliu. All rights reserved.\n# Distributed under the terms of the Fiwix License.\n#\n\n.c.o:\n\t$(CC) $(CFLAGS) -c -o $@ $<\n\nOBJS = super.o inode.o namei.o dir.o\n\nall:\t$(OBJS)\n\nclean:\n\trm -f *.o\n\n"
  },
  {
    "path": "fs/devpts/dir.c",
    "content": "/*\n * fiwix/fs/devpts/dir.c\n *\n * Copyright 2025, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_devpts.h>\n#include <fiwix/dirent.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#ifdef CONFIG_UNIX98_PTYS\nstruct fs_operations devpts_dir_fsop = {\n\t0,\n\t0,\n\n\tdevpts_dir_open,\n\tdevpts_dir_close,\n\tdevpts_dir_read,\n\tNULL,\t\t\t/* write */\n\tNULL,\t\t\t/* ioctl */\n\tNULL,\t\t\t/* llseek */\n\tdevpts_readdir,\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tdevpts_lookup,\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nint devpts_dir_open(struct inode *i, struct fd *f)\n{\n\tf->offset = 0;\n\treturn 0;\n}\n\nint devpts_dir_close(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\nint devpts_dir_read(struct inode *i, struct fd *f, char *buffer, __size_t count)\n{\n\treturn -EISDIR;\n}\n\nint devpts_readdir(struct inode *i, struct fd *f, struct dirent *dirent, __size_t count)\n{\n\tunsigned int offset;\n\tint rec_len, name_len;\n\t__size_t total_read;\n\tint base_dirent_len;\n\tchar *name, numstr[10 + 1];\n\n\tbase_dirent_len = sizeof(dirent->d_ino) + sizeof(dirent->d_off) + sizeof(dirent->d_reclen);\n\n\toffset = f->offset;\n\ttotal_read = 0;\n\tmemset_b(numstr, 0, sizeof(numstr));\n\n\twhile(offset < NR_PTYS && count > 0) {\n\t\tif(offset == 0) {\n\t\t\tname = \".\";\n\t\t\tdirent->d_ino = DEVPTS_ROOT_INO;\n\t\t} else if(offset == 1) {\n\t\t\tname = \"..\";\n\t\t\tdirent->d_ino = DEVPTS_ROOT_INO;\n\t\t} else {\n\t\t\tif(devpts_list[offset - 2].count) {\n\t\t\t\tdirent->d_ino = devpts_list[offset - 2].inode->inode;\n\t\t\t\tsprintk(numstr, \"%d\", offset - 2);\n\t\t\t\tname = numstr;\n\t\t\t} else {\n\t\t\t\toffset++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\tname_len = strlen(name);\n\t\trec_len = (base_dirent_len + (name_len + 1)) + 3;\n\t\trec_len &= ~3;\t/* round up */\n\t\tif(total_read + rec_len < count) {\n\t\t\tdirent->d_off = offset;\n\t\t\tdirent->d_reclen = rec_len;\n\t\t\tmemcpy_b(dirent->d_name, name, name_len);\n\t\t\tdirent->d_name[name_len] = 0;\n\t\t\tdirent = (struct dirent *)((char *)dirent + rec_len);\n\t\t\ttotal_read += rec_len;\n\t\t\tcount -= rec_len;\n\t\t} else {\n\t\t\tcount = 0;\n\t\t}\n\t\toffset++;\n\t}\n\tf->offset = offset;\n\treturn total_read;\n}\n#endif /* CONFIG_UNIX98_PTYS */\n"
  },
  {
    "path": "fs/devpts/inode.c",
    "content": "/*\n * fiwix/fs/devpts/inode.c\n *\n * Copyright 2025, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_devpts.h>\n#include <fiwix/statfs.h>\n#include <fiwix/stat.h>\n#include <fiwix/stdio.h>\n\n#ifdef CONFIG_UNIX98_PTYS\nint devpts_read_inode(struct inode *i)\n{\n\t__mode_t mode;\n\t__nlink_t nlink;\n\n\tif(i->inode == DEVPTS_ROOT_INO) {\n\t\tmode = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;\n\t\tnlink = 2;\n\t\ti->fsop = &devpts_dir_fsop;\n\t} else {\n\t\tmode = S_IFCHR | S_IRUSR | S_IWUSR;\n\t\tnlink = 1;\n\t\ti->fsop = &def_chr_fsop;\n\t}\n\n\ti->i_mode = mode;\n\ti->i_uid = 0;\n\ti->i_size = 0;\n\ti->i_atime = CURRENT_TIME;\n\ti->i_ctime = CURRENT_TIME;\n\ti->i_mtime = CURRENT_TIME;\n\ti->i_gid = 0;\n\ti->i_nlink = nlink;\n\ti->i_blocks = 0;\n\ti->i_flags = 0;\n\ti->state = INODE_LOCKED;\n\ti->count = 1;\n\treturn 0;\n}\n\nvoid devpts_statfs(struct superblock *sb, struct statfs *statfsbuf)\n{\n\tstatfsbuf->f_type = DEVPTS_SUPER_MAGIC;\n\tstatfsbuf->f_bsize = sb->s_blocksize;\n\tstatfsbuf->f_blocks = 0;\n\tstatfsbuf->f_bfree = 0;\n\tstatfsbuf->f_bavail = 0;\n\tstatfsbuf->f_files = 0;\n\tstatfsbuf->f_ffree = 0;\n\t/* statfsbuf->f_fsid = ? */\n\tstatfsbuf->f_namelen = NAME_MAX;\n}\n#endif /* CONFIG_UNIX98_PTYS */\n"
  },
  {
    "path": "fs/devpts/namei.c",
    "content": "/*\n * fiwix/fs/devpts/namei.c\n *\n * Copyright 2025, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_devpts.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#ifdef CONFIG_UNIX98_PTYS\nint devpts_lookup(const char *name, struct inode *dir, struct inode **i_res)\n{\n\t__ino_t inode;\n\tint numpty;\n\n\tif(name[0] == '.' && name[1] == '\\0') {\n\t\t*i_res = dir;\n\t\treturn 0;\n\t} else if(name[0] == '.' && name[1] == '.') {\n\t\treturn 0;\n\t}\n\n\tif((numpty = atoi(name)) >= NR_PTYS) {\n\t\tiput(dir);\n\t\treturn -ENOENT;\n\t}\n\tif(devpts_list[numpty].count) {\n\t\tinode = devpts_list[numpty].inode->inode;\n\t\tif(!(*i_res = iget(dir->sb, inode))) {\n\t\t\tiput(dir);\n\t\t\treturn -EACCES;\n\t\t}\n\t\tiput(dir);\n\t\treturn 0;\n\t}\n\tiput(dir);\n\treturn -ENOENT;\n}\n#endif /* CONFIG_UNIX98_PTYS */\n"
  },
  {
    "path": "fs/devpts/super.c",
    "content": "/*\n * fiwix/fs/devpts/super.c\n *\n * Copyright 2025, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_devpts.h>\n#include <fiwix/stat.h>\n#include <fiwix/mm.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#ifdef CONFIG_UNIX98_PTYS\nstruct devpts_files *devpts_list;\n\nstruct fs_operations devpts_fsop = {\n\t0,\n\tDEVPTS_DEV,\n\n\tNULL,\t\t\t/* open */\n\tNULL,\t\t\t/* close */\n\tNULL,\t\t\t/* read */\n\tNULL,\t\t\t/* write */\n\tNULL, \t\t\t/* ioctl */\n\tNULL,\t\t\t/* llseek */\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lookup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tdevpts_read_inode,\n\tNULL,\t\t\t/* write_inode */\n\tdevpts_ialloc,\n\tdevpts_ifree,\n\tdevpts_statfs,\n\tdevpts_read_superblock,\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nint devpts_ialloc(struct inode *i, int mode)\n{\n\tstruct superblock *sb = i->sb;\n\tint n;\n\n\tsuperblock_lock(sb);\n\tfor(n = 0; n < NR_PTYS; n++) {\n\t\tif(!devpts_list[n].count) {\n\t\t\tdevpts_list[n].count = 1;\n\t\t\tbreak;\n\t\t}\n\t}\n\tsuperblock_unlock(sb);\n\tif(n == NR_PTYS) {\n\t\treturn -ENOSPC;\n\t}\n\n\ti->i_mode = mode | S_IRUSR | S_IWUSR;\n\ti->dev = sb->dev;\n\ti->rdev = MKDEV(0, 0);\n\ti->inode = DEVPTS_ROOT_INO + 1 + n;\n\ti->count = 1;\n\ti->fsop = &def_chr_fsop;\n\ti->i_uid = 0;\n\ti->i_size = 0;\n\ti->i_atime = CURRENT_TIME;\n\ti->i_ctime = CURRENT_TIME;\n\ti->i_mtime = CURRENT_TIME;\n\ti->i_gid = 0;\n\ti->i_nlink = 1;\n\ti->i_blocks = 0;\n\ti->i_flags = 0;\n\tdevpts_list[n].inode = i;\n\treturn 0;\n}\n\nvoid devpts_ifree(struct inode *i)\n{\n\tint n;\n\n\tfor(n = 0; n < NR_PTYS; n++) {\n\t\tif(devpts_list[n].inode == i) {\n\t\t\tdevpts_list[n].count = 0;\n\t\t\tmemset_b(&devpts_list[n], 0, sizeof(struct devpts_files));\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nint devpts_read_superblock(__dev_t dev, struct superblock *sb)\n{\n\tsuperblock_lock(sb);\n\tsb->dev = dev;\n\tsb->fsop = &devpts_fsop;\n\tsb->s_blocksize = BLKSIZE_1K;\n\n\tif(!(sb->root = iget(sb, DEVPTS_ROOT_INO))) {\n\t\tprintk(\"WARNING: %s(): unable to get root inode.\\n\", __FUNCTION__);\n\t\tsuperblock_unlock(sb);\n\t\treturn -EINVAL;\n\t}\n\tsuperblock_unlock(sb);\n\treturn 0;\n}\n\nint devpts_init(void)\n{\n\tif(!(devpts_list = (struct devpts_files *)kmalloc(sizeof(struct devpts_files) * NR_PTYS))) {\n\t\treturn -ENOMEM;\n\t}\n\tmemset_b(devpts_list, 0, sizeof(struct devpts_files) * NR_PTYS);\n\treturn register_filesystem(\"devpts\", &devpts_fsop);\n}\n#endif /* CONFIG_UNIX98_PTYS */\n"
  },
  {
    "path": "fs/elf.c",
    "content": "/*\n * fiwix/fs/elf.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/asm.h>\n#include <fiwix/types.h>\n#include <fiwix/buffer.h>\n#include <fiwix/fs.h>\n#include <fiwix/i386elf.h>\n#include <fiwix/mm.h>\n#include <fiwix/mman.h>\n#include <fiwix/fs.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#define AT_ITEMS\t12\t/* ELF Auxiliary Vectors */\n\n/*\n * Setup the initial process stack (UNIX System V ABI for i386)\n * ------------------------------------------------------------\n * 0xBFFFFFFF\n * \t+---------------+ \\\n * \t| envp[] str    | |\n * \t+---------------+ |\n * \t| argv[] str    | |\n * \t+---------------+ |\n * \t| NULL          | |\n * \t+---------------+ |\n * \t| ELF Aux.Vect. | |\n * \t+---------------+ |\n * \t| NULL          | | elf_create_stack() setups this section\n * \t+---------------+ |\n * \t| envp[] ptr    | |\n * \t+---------------+ |\n * \t| NULL          | |\n * \t+---------------+ |\n * \t| argv[] ptr    | |\n * \t+---------------+ |\n * \t| argc          | |\n * \t+---------------+ /\n * \t| stack pointer | grows toward lower addresses\n * \t+---------------+ ||\n * \t|...............| \\/\n * \t|...............|\n * \t|...............|\n * \t|...............| /\\\n * \t+---------------+ ||\n * \t|  brk (heap)   | grows toward higher addresses\n * \t+---------------+\n * \t| .bss section  |\n * \t+---------------+\n * \t| .data section |\n * \t+---------------+\n * \t| .text section |\n * \t+---------------+\n * 0x08048000\n */\nstatic void elf_create_stack(struct binargs *barg, unsigned int *sp, unsigned int str_ptr, int at_base, struct elf32_hdr *elf32_h, unsigned int phdr_addr)\n{\n\tunsigned int n, addr;\n\tchar *str;\n\n\t/* copy strings */\n\tfor(n = 0; n < ARG_MAX; n++) {\n\t\tif(barg->page[n]) {\n\t\t\taddr = PAGE_OFFSET - ((ARG_MAX - n) * PAGE_SIZE);\n\t\t\tmemcpy_b((void *)addr, (void *)barg->page[n], PAGE_SIZE);\n\t\t}\n\t}\n\n#ifdef __DEBUG__\n\tprintk(\"sp = 0x%08x\\n\", sp);\n#endif /*__DEBUG__ */\n\n\t/* copy the value of 'argc' into the stack */\n\tcurrent->argc = barg->argc;\n\t*sp = barg->argc;\n#ifdef __DEBUG__\n\tprintk(\"at 0x%08x -> argc\\n\", sp);\n#endif /*__DEBUG__ */\n\tsp++;\n\n\t/* copy as many pointers to strings as 'argc' */\n\tcurrent->argv = (char **)sp;\n\tfor(n = 0; n < barg->argc; n++) {\n\t\t*sp = str_ptr;\n\t\tstr = (char *)str_ptr;\n#ifdef __DEBUG__\n\t\tprintk(\"at 0x%08x -> str_ptr(%d) = 0x%08x (+ %d)\\n\", sp, n, str_ptr, strlen(str) + 1);\n#endif /*__DEBUG__ */\n\t\tsp++;\n\t\tstr_ptr += strlen(str) + 1;\n\t}\n\n\t/* the last element of 'argv[]' must be a NULL-pointer */\n\t*sp = 0;\n#ifdef __DEBUG__\n\tprintk(\"at 0x%08x -> -------------- = 0x%08x\\n\", sp, 0);\n#endif /*__DEBUG__ */\n\tsp++;\n\n\t/* copy as many pointers to strings as 'envc' */\n\tcurrent->envc = barg->envc;\n\tcurrent->envp = (char **)sp;\n\tfor(n = 0; n < barg->envc; n++) {\n\t\t*sp = str_ptr;\n\t\tstr = (char *)str_ptr;\n#ifdef __DEBUG__\n\t\tprintk(\"at 0x%08x -> str_ptr(%d) = 0x%08x (+ %d)\\n\", sp, n, str_ptr, strlen(str) + 1);\n#endif /*__DEBUG__ */\n\t\tsp++;\n\t\tstr_ptr += strlen(str) + 1;\n\t}\n\n\t/* the last element of 'envp[]' must be a NULL-pointer */\n\t*sp = 0;\n#ifdef __DEBUG__\n\tprintk(\"at 0x%08x -> -------------- = 0x%08x\\n\", sp, 0);\n#endif /*__DEBUG__ */\n\tsp++;\n\n\n\t/* copy the Auxiliar Table Items (dlinfo_items) */\n\tif(at_base) {\n\t\t*sp = AT_PHDR;\n#ifdef __DEBUG__\n\t\tprintk(\"at 0x%08x -> AT_PHDR = %d\", sp, *sp);\n#endif /*__DEBUG__ */\n\t\tsp++;\n\n\t\t*sp = (unsigned int)phdr_addr;\n#ifdef __DEBUG__\n\t\tprintk(\"\\t\\tAT_PHDR = 0x%08x\\n\", *sp);\n#endif /*__DEBUG__ */\n\t\tsp++;\n\n\t\t*sp = AT_PHENT;\n#ifdef __DEBUG__\n\t\tprintk(\"at 0x%08x -> AT_PHENT = %d\", sp, *sp);\n#endif /*__DEBUG__ */\n\t\tsp++;\n\n\t\t*sp = sizeof(struct elf32_phdr);\n#ifdef __DEBUG__\n\t\tprintk(\"\\t\\tAT_PHENT = %d\\n\", *sp);\n#endif /*__DEBUG__ */\n\t\tsp++;\n\n\t\t*sp = AT_PHNUM;\n#ifdef __DEBUG__\n\t\tprintk(\"at 0x%08x -> AT_PHNUM = %d\", sp, *sp);\n#endif /*__DEBUG__ */\n\t\tsp++;\n\n\t\t*sp = (unsigned int)elf32_h->e_phnum;\n#ifdef __DEBUG__\n\t\tprintk(\"\\t\\tAT_PHNUM = %d\\n\", *sp);\n#endif /*__DEBUG__ */\n\t\tsp++;\n\n\t\t*sp = AT_PAGESZ;\n#ifdef __DEBUG__\n\t\tprintk(\"at 0x%08x -> AT_PGSIZE = %d\", sp, *sp);\n#endif /*__DEBUG__ */\n\t\tsp++;\n\n\t\t*sp = PAGE_SIZE;\n#ifdef __DEBUG__\n\t\tprintk(\"\\t\\tAT_PGSIZE = %d\\n\", *sp);\n#endif /*__DEBUG__ */\n\t\tsp++;\n\n\t\t*sp = AT_BASE;\n#ifdef __DEBUG__\n\t\tprintk(\"at 0x%08x -> AT_BASE = %d\", sp, *sp);\n#endif /*__DEBUG__ */\n\t\tsp++;\n\n\t\t*sp = (unsigned int)at_base;\n#ifdef __DEBUG__\n\t\tprintk(\"\\t\\tAT_BASE = 0x%08x\\n\", sp);\n#endif /*__DEBUG__ */\n\t\tsp++;\n\n\t\t*sp = AT_FLAGS;\n#ifdef __DEBUG__\n\t\tprintk(\"at 0x%08x -> AT_FLAGS = %d\", sp, *sp);\n#endif /*__DEBUG__ */\n\t\tsp++;\n\n\t\t*sp = 0;\n#ifdef __DEBUG__\n\t\tprintk(\"\\t\\tAT_FLAGS = %d\\n\", *sp);\n#endif /*__DEBUG__ */\n\t\tsp++;\n\n\t\t*sp = AT_ENTRY;\n#ifdef __DEBUG__\n\t\tprintk(\"at 0x%08x -> AT_ENTRY = %d \", sp, *sp);\n#endif /*__DEBUG__ */\n\t\tsp++;\n\n\t\t*sp = (unsigned int)elf32_h->e_entry;\n#ifdef __DEBUG__\n\t\tprintk(\"\\t\\tAT_ENTRY = 0x%08x\\n\", *sp);\n#endif /*__DEBUG__ */\n\t\tsp++;\n\n\t\t*sp = AT_UID;\n#ifdef __DEBUG__\n\t\tprintk(\"at 0x%08x -> AT_UID = %d\", sp, *sp);\n#endif /*__DEBUG__ */\n\t\tsp++;\n\n\t\t*sp = current->uid;\n#ifdef __DEBUG__\n\t\tprintk(\"\\t\\tAT_UID = %d\\n\", *sp);\n#endif /*__DEBUG__ */\n\t\tsp++;\n\n\t\t*sp = AT_EUID;\n#ifdef __DEBUG__\n\t\tprintk(\"at 0x%08x -> AT_EUID = %d\", sp, *sp);\n#endif /*__DEBUG__ */\n\t\tsp++;\n\n\t\t*sp = current->euid;\n#ifdef __DEBUG__\n\t\tprintk(\"\\t\\tAT_EUID = %d\\n\", *sp);\n#endif /*__DEBUG__ */\n\t\tsp++;\n\n\t\t*sp = AT_GID;\n#ifdef __DEBUG__\n\t\tprintk(\"at 0x%08x -> AT_GID = %d\", sp, *sp);\n#endif /*__DEBUG__ */\n\t\tsp++;\n\n\t\t*sp = current->gid;\n#ifdef __DEBUG__\n\t\tprintk(\"\\t\\tAT_GID = %d\\n\", *sp);\n#endif /*__DEBUG__ */\n\t\tsp++;\n\n\t\t*sp = AT_EGID;\n#ifdef __DEBUG__\n\t\tprintk(\"at 0x%08x -> AT_EGID = %d\", sp, *sp);\n#endif /*__DEBUG__ */\n\t\tsp++;\n\n\t\t*sp = current->egid;\n#ifdef __DEBUG__\n\t\tprintk(\"\\t\\tAT_EGID = %d\\n\", *sp);\n#endif /*__DEBUG__ */\n\t\tsp++;\n\t}\n\n\t*sp = AT_NULL;\n#ifdef __DEBUG__\n\tprintk(\"at 0x%08x -> AT_NULL = %d\", sp, *sp);\n#endif /*__DEBUG__ */\n\tsp++;\n\n\t*sp = 0;\n#ifdef __DEBUG__\n\tprintk(\"\\t\\tAT_NULL = %d\\n\", *sp);\n#endif /*__DEBUG__ */\n\n#ifdef __DEBUG__\n\tfor(n = 0; n < barg->argc; n++) {\n\t\tprintk(\"at 0x%08x -> argv[%d] = '%s'\\n\", current->argv[n], n, current->argv[n]);\n\t}\n\tfor(n = 0; n < barg->envc; n++) {\n\t\tprintk(\"at 0x%08x -> envp[%d] = '%s'\\n\", current->envp[n], n, current->envp[n]);\n\t}\n#endif /*__DEBUG__ */\n}\n\nstatic int elf_load_interpreter(struct inode *ii)\n{\n\tint n, errno;\n\tstruct buffer *buf;\n\tstruct elf32_hdr *elf32_h;\n\tstruct elf32_phdr *elf32_ph, *last_ptload;\n\t__blk_t block;\n\tunsigned int start, end, length, offset;\n\tunsigned int prot;\n\tchar *data;\n\tchar type;\n\n\tif((block = bmap(ii, 0, FOR_READING)) < 0) {\n\t\treturn block;\n\t}\n\tif(!(buf = bread(ii->dev, block, ii->sb->s_blocksize))) {\n\t\treturn -EIO;\n\t}\n\n\t/*\n\t * The contents of the buffer is copied and then freed immediately to\n\t * make sure that it won't conflict while zeroing the BSS fractional\n\t * page, in case that the same block is requested during the page fault.\n\t */\n\tif(!(data = (void *)kmalloc(PAGE_SIZE))) {\n\t\tbrelse(buf);\n\t\treturn -ENOMEM;\n\t}\n\tmemcpy_b(data, buf->data, ii->sb->s_blocksize);\n\tbrelse(buf);\n\n\telf32_h = (struct elf32_hdr *)data;\n\tif(check_elf(elf32_h)) {\n\t\tkfree((unsigned int)data);\n\t\treturn -ELIBBAD;\n\t}\n\n\tlast_ptload = NULL;\n\tfor(n = 0; n < elf32_h->e_phnum; n++) {\n\t\telf32_ph = (struct elf32_phdr *)(data + elf32_h->e_phoff + (sizeof(struct elf32_phdr) * n));\n\t\tif(elf32_ph->p_type == PT_LOAD) {\n#ifdef __DEBUG__\n\t\t\tprintk(\"p_offset = 0x%08x\\n\", elf32_ph->p_offset);\n\t\t\tprintk(\"p_vaddr  = 0x%08x\\n\", elf32_ph->p_vaddr);\n\t\t\tprintk(\"p_paddr  = 0x%08x\\n\", elf32_ph->p_paddr);\n\t\t\tprintk(\"p_filesz = 0x%08x\\n\", elf32_ph->p_filesz);\n\t\t\tprintk(\"p_memsz  = 0x%08x\\n\\n\", elf32_ph->p_memsz);\n#endif /*__DEBUG__ */\n\t\t\tstart = (elf32_ph->p_vaddr & PAGE_MASK) + MMAP_START;\n\t\t\tlength = (elf32_ph->p_vaddr & ~PAGE_MASK) + elf32_ph->p_filesz;\n\t\t\toffset = elf32_ph->p_offset - (elf32_ph->p_vaddr & ~PAGE_MASK);\n\t\t\ttype = P_DATA;\n\t\t\tprot = 0;\n\t\t\tif(elf32_ph->p_flags & PF_R) {\n\t\t\t\tprot = PROT_READ;\n\t\t\t}\n\t\t\tif(elf32_ph->p_flags & PF_W) {\n\t\t\t\tprot |= PROT_WRITE;\n\t\t\t}\n\t\t\tif(elf32_ph->p_flags & PF_X) {\n\t\t\t\tprot |= PROT_EXEC;\n\t\t\t\ttype = P_TEXT;\n\t\t\t}\n\t\t\terrno = do_mmap(ii, start, length, prot, MAP_PRIVATE | MAP_FIXED, offset, type, O_RDONLY, NULL);\n\t\t\tif(errno < 0 && errno > -PAGE_SIZE) {\n\t\t\t\tkfree((unsigned int)data);\n\t\t\t\tsend_sig(current, SIGSEGV);\n\t\t\t\treturn -ENOEXEC;\n\t\t\t}\n\t\t\tlast_ptload = elf32_ph;\n\t\t}\n\t}\n\n\tif(!last_ptload) {\n\t\tprintk(\"%s(): no headers in interpreter.\");\n\t\tkfree((unsigned int)data);\n\t\treturn -ENOEXEC;\n\t}\n\n\telf32_ph = last_ptload;\n\n\t/* zero-fill the fractional page of the DATA section */\n\tend = PAGE_ALIGN(elf32_ph->p_vaddr + elf32_ph->p_filesz) + MMAP_START;\n\tstart = (elf32_ph->p_vaddr + elf32_ph->p_filesz) + MMAP_START;\n\tlength = end - start;\n\n\t/* this will generate a page fault which will load the page in */\n\tmemset_b((void *)start, 0, length);\n\n\t/* setup the BSS section */\n\tstart = (elf32_ph->p_vaddr + elf32_ph->p_filesz) + MMAP_START;\n\tstart = PAGE_ALIGN(start);\n\tend = (elf32_ph->p_vaddr + elf32_ph->p_memsz) + MMAP_START;\n\tend = PAGE_ALIGN(end);\n\tlength = end - start;\n\terrno = do_mmap(NULL, start, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, 0, P_BSS, 0, NULL);\n\tif(errno < 0 && errno > -PAGE_SIZE) {\n\t\tkfree((unsigned int)data);\n\t\tsend_sig(current, SIGSEGV);\n\t\treturn -ENOEXEC;\n\t}\n\tkfree((unsigned int)data);\n\treturn elf32_h->e_entry + MMAP_START;\n}\n\nint check_elf(struct elf32_hdr *elf32_h)\n{\n\tif(elf32_h->e_ident[EI_MAG0] != ELFMAG0 ||\n\t\telf32_h->e_ident[EI_MAG1] != ELFMAG1 ||\n\t\telf32_h->e_ident[EI_MAG2] != ELFMAG2 ||\n\t\telf32_h->e_ident[EI_MAG3] != ELFMAG3 ||\n\t\t(elf32_h->e_type != ET_EXEC && elf32_h->e_type != ET_DYN) ||\n\t\telf32_h->e_machine != EM_386) {\n\t\treturn -EINVAL;\n\t}\n\treturn 0;\n}\n\nint elf_load(struct inode *i, struct binargs *barg, struct sigcontext *sc, char *data)\n{\n\tint n, errno;\n\tstruct elf32_hdr *elf32_h;\n\tstruct elf32_phdr *elf32_ph, *last_ptload;\n\tstruct inode *ii;\n\tunsigned int start, end, length, offset;\n\tunsigned int prot;\n\tchar *interpreter;\n\tint at_base, phdr_addr;\n\tchar type;\n\tunsigned int ae_ptr_len, ae_str_len;\n\tunsigned int sp, str;\n\n\telf32_h = (struct elf32_hdr *)data;\n\tif(check_elf(elf32_h)) {\n\t\tif(current->pid == INIT) {\n\t\t\tPANIC(\"%s has an unrecognized binary format.\\n\", INIT_PROGRAM);\n\t\t}\n\t\treturn -ENOEXEC;\n\t}\n\n\t/* check if an interpreter is required */\n\tinterpreter = NULL;\n\tii = NULL;\n\tphdr_addr = at_base = 0;\n\tfor(n = 0; n < elf32_h->e_phnum; n++) {\n\t\telf32_ph = (struct elf32_phdr *)(data + elf32_h->e_phoff + (sizeof(struct elf32_phdr) * n));\n\t\tif(elf32_ph->p_type == PT_INTERP) {\n\t\t\tat_base = MMAP_START;\n\t\t\tinterpreter = data + elf32_ph->p_offset;\n\t\t\tif(namei(interpreter, &ii, NULL, FOLLOW_LINKS)) {\n\t\t\t\tprintk(\"%s(): can't find interpreter '%s'.\\n\", __FUNCTION__, interpreter);\n\t\t\t\tsend_sig(current, SIGSEGV);\n\t\t\t\treturn -ELIBACC;\n\t\t\t}\n#ifdef __DEBUG__\n\t\t\tprintk(\"p_offset = 0x%08x\\n\", elf32_ph->p_offset);\n\t\t\tprintk(\"p_vaddr  = 0x%08x\\n\", elf32_ph->p_vaddr);\n\t\t\tprintk(\"p_paddr  = 0x%08x\\n\", elf32_ph->p_paddr);\n\t\t\tprintk(\"p_filesz = 0x%08x\\n\", elf32_ph->p_filesz);\n\t\t\tprintk(\"p_memsz  = 0x%08x\\n\", elf32_ph->p_memsz);\n\t\t\tprintk(\"using interpreter '%s'\\n\", interpreter);\n#endif /*__DEBUG__ */\n\t\t}\n\t}\n\n\t/*\n\t * calculate the final size of 'ae_ptr_len' based on:\n\t *  - argc = 4 bytes (unsigned int)\n\t *  - barg.argc = (num. of pointers to strings + 1 NULL) x 4 bytes (unsigned int)\n\t *  - barg.envc = (num. of pointers to strings + 1 NULL) x 4 bytes (unsigned int)\n\t */\n\tae_ptr_len = (1 + (barg->argc + 1) + (barg->envc + 1)) * sizeof(unsigned int);\n\tae_str_len = barg->argv_len + barg->envp_len;\n\n#ifdef __DEBUG__\n\tprintk(\"argc=%d (argv_len=%d) envc=%d (envp_len=%d)  ae_ptr_len=%d ae_str_len=%d\\n\", barg->argc, barg->argv_len, barg->envc, barg->envp_len, ae_ptr_len, ae_str_len);\n#endif /*__DEBUG__ */\n\n\n\t/* point of no return */\n\n\trelease_binary();\n\tcurrent->rss = 0;\n\n\tcurrent->entry_address = elf32_h->e_entry;\n\tif(interpreter) {\n\t\terrno = elf_load_interpreter(ii);\n\t\tif(errno < 0) {\n\t\t\tprintk(\"%s(): unable to load the interpreter '%s'.\\n\", __FUNCTION__, interpreter);\n\t\t\tiput(ii);\n\t\t\tsend_sig(current, SIGKILL);\n\t\t\treturn errno;\n\t\t}\n\t\tcurrent->entry_address = errno;\n\t\tiput(ii);\n\t}\n\n\tlast_ptload = NULL;\n\tfor(n = 0; n < elf32_h->e_phnum; n++) {\n\t\telf32_ph = (struct elf32_phdr *)(data + elf32_h->e_phoff + (sizeof(struct elf32_phdr) * n));\n\t\tif(elf32_ph->p_type == PT_PHDR) {\n\t\t\tphdr_addr = elf32_ph->p_vaddr;\n\t\t}\n\t\tif(elf32_ph->p_type == PT_LOAD) {\n\t\t\tstart = elf32_ph->p_vaddr & PAGE_MASK;\n\t\t\tlength = (elf32_ph->p_vaddr & ~PAGE_MASK) + elf32_ph->p_filesz;\n\t\t\toffset = elf32_ph->p_offset - (elf32_ph->p_vaddr & ~PAGE_MASK);\n\t\t\ttype = P_DATA;\n\t\t\tprot = 0;\n\t\t\tif(elf32_ph->p_flags & PF_R) {\n\t\t\t\tprot = PROT_READ;\n\t\t\t}\n\t\t\tif(elf32_ph->p_flags & PF_W) {\n\t\t\t\tprot |= PROT_WRITE;\n\t\t\t}\n\t\t\tif(elf32_ph->p_flags & PF_X) {\n\t\t\t\tprot |= PROT_EXEC;\n\t\t\t\ttype = P_TEXT;\n\t\t\t\tcurrent->end_code = start + length;\n\t\t\t}\n\t\t\terrno = do_mmap(i, start, length, prot, MAP_PRIVATE | MAP_FIXED, offset, type, O_RDONLY, NULL);\n\t\t\tif(errno < 0 && errno > -PAGE_SIZE) {\n\t\t\t\tsend_sig(current, SIGSEGV);\n\t\t\t\treturn -ENOEXEC;\n\t\t\t}\n\t\t\tlast_ptload = elf32_ph;\n\t\t}\n\t}\n\n\tif(!last_ptload) {\n\t\tprintk(\"%s(): no program headers.\");\n\t\tsend_sig(current, SIGKILL);\n\t\treturn -ENOEXEC;\n\t}\n\n\telf32_ph = last_ptload;\n\n\t/* zero-fill the fractional page of the DATA section */\n\tend = PAGE_ALIGN(elf32_ph->p_vaddr + elf32_ph->p_filesz);\n\tstart = elf32_ph->p_vaddr + elf32_ph->p_filesz;\n\tlength = end - start;\n\n\t/* this will generate a page fault which will load the page in */\n\tmemset_b((void *)start, 0, length);\n\n\t/* setup the BSS section */\n\tstart = elf32_ph->p_vaddr + elf32_ph->p_filesz;\n\tstart = PAGE_ALIGN(start);\n\tend = elf32_ph->p_vaddr + elf32_ph->p_memsz;\n\tend = PAGE_ALIGN(end);\n\tlength = end - start;\n\terrno = do_mmap(NULL, start, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, 0, P_BSS, 0, NULL);\n\tif(errno < 0 && errno > -PAGE_SIZE) {\n\t\tsend_sig(current, SIGSEGV);\n\t\treturn -ENOEXEC;\n\t}\n\tcurrent->brk_lower = start;\n\n\t/* setup the HEAP section */\n\tstart = elf32_ph->p_vaddr + elf32_ph->p_memsz;\n\tstart = PAGE_ALIGN(start);\n\tlength = PAGE_SIZE;\n\terrno = do_mmap(NULL, start, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, 0, P_HEAP, 0, NULL);\n\tif(errno < 0 && errno > -PAGE_SIZE) {\n\t\tsend_sig(current, SIGSEGV);\n\t\treturn -ENOEXEC;\n\t}\n\tcurrent->brk = start;\n\n\t/* setup the STACK section */\n\tsp = PAGE_OFFSET - 4;\t/* formerly 0xBFFFFFFC */\n\tsp -= ae_str_len;\n\tstr = sp;\t/* this is the address of the first string (argv[0]) */\n\tsp &= ~3;\n\tsp -= at_base ? (AT_ITEMS * 2) * sizeof(unsigned int) : 2 * sizeof(unsigned int);\n\tsp -= ae_ptr_len;\n\tlength = PAGE_OFFSET - (sp & PAGE_MASK);\n\terrno = do_mmap(NULL, sp & PAGE_MASK, length, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_FIXED, 0, P_STACK, 0, NULL);\n\tif(errno < 0 && errno > -PAGE_SIZE) {\n\t\tsend_sig(current, SIGSEGV);\n\t\treturn -ENOEXEC;\n\t}\n\n\telf_create_stack(barg, (unsigned int *)sp, str, at_base, elf32_h, phdr_addr);\n\n\t/* set %esp to point to 'argc' */\n\tsc->oldesp = sp;\n\tsc->eflags = 0x202;\t/* FIXME: linux 2.2 = 0x292 */\n\tsc->eip = current->entry_address;\n\tsc->err = 0;\n\tsc->eax = 0;\n\tsc->ecx = 0;\n\tsc->edx = 0;\n\tsc->ebx = 0;\n\tsc->ebp = 0;\n\tsc->esi = 0;\n\tsc->edi = 0;\n\treturn 0;\n}\n"
  },
  {
    "path": "fs/ext2/Makefile",
    "content": "# fiwix/fs/ext2/Makefile\n#\n# Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n# Distributed under the terms of the Fiwix License.\n#\n\n.c.o:\n\t$(CC) $(CFLAGS) -c -o $@ $<\n\nOBJS = inode.o super.o namei.o symlink.o dir.o file.o bitmaps.o\n\nall:\t$(OBJS)\n\nclean:\n\trm -f *.o\n\n"
  },
  {
    "path": "fs/ext2/bitmaps.c",
    "content": "/*\n * fiwix/fs/ext2/bitmaps.c\n *\n * Copyright 2019, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_ext2.h>\n#include <fiwix/buffer.h>\n#include <fiwix/mm.h>\n#include <fiwix/errno.h>\n#include <fiwix/stat.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstatic int find_first_zero(struct superblock *sb, __blk_t bmblock, struct buffer **buf)\n{\n\tunsigned char c;\n\tint n, n2;\n\n\tif(!(*buf = bread(sb->dev, bmblock, sb->s_blocksize))) {\n\t\treturn -EIO;\n\t}\n\tfor(n = 0; n < sb->s_blocksize; n++) {\n\t\tif((c = (unsigned char)(*buf)->data[n]) == 0xFF) {\n\t\t\tcontinue;\n\t\t}\n\t\tfor(n2 = 0; n2 < 8; n2++) {\n\t\t\tif(!(c & (1 << n2))) {\n\t\t\t\treturn (n * 8) + n2;\n\t\t\t}\n\t\t}\n\t}\n\treturn -ENOSPC;\n}\n\nstatic int change_bit(int mode, struct superblock *sb, __blk_t bmblock, struct buffer *bmbuf, int item)\n{\n\tint byte, bit, mask;\n\tstruct buffer *buf;\n\n\tbyte = (item % (sb->s_blocksize * 8)) / 8;\n\tbit = (item % (sb->s_blocksize * 8)) % 8;\n\tmask = 1 << bit;\n\n\tif(!bmbuf) {\n\t\tif(!(buf = bread(sb->dev, bmblock, sb->s_blocksize))) {\n\t\t\treturn -EIO;\n\t\t}\n\t} else {\n\t\tbuf = bmbuf;\n\t}\n\n\tif(mode == CLEAR_BIT) {\n\t\tif(!(buf->data[byte] & mask)) {\n\t\t\tbrelse(buf);\n\t\t\treturn 1;\n\t\t}\n\t\tbuf->data[byte] &= ~mask;\n\t}\n\tif(mode == SET_BIT) {\n\t\tif((buf->data[byte] & mask)) {\n\t\t\tbrelse(buf);\n\t\t\treturn 1;\n\t\t}\n\t\tbuf->data[byte] |= mask;\n\t}\n\n\tbwrite(buf);\n\treturn 0;\n}\n\n/*\n * Unlike of what Ext2 specifies/suggests, this inode allocation does NOT\n * try to assign inodes in the same block group of the directory in which\n * they will be created.\n */\nint ext2_ialloc(struct inode *i, int mode)\n{\n\t__ino_t inode;\n\t__blk_t block;\n\tstruct superblock *sb;\n\tstruct ext2_group_desc *gd;\n\tstruct buffer *buf, *bmbuf;\n\tint bg, d, errno;\n\n\tsb = i->sb;\n\tsuperblock_lock(sb);\n\n\tblock = SUPERBLOCK + sb->u.ext2.sb.s_first_data_block;\n\tbuf = bmbuf = NULL;\n\tgd = NULL;\n\terrno = -ENOSPC;\n\n\t/* read through all group descriptors to find the first unallocated inode */\n\tfor(bg = 0, d = 0; bg < sb->u.ext2.block_groups; bg++, d++) {\n\t\tif(!(bg % EXT2_DESC_PER_BLOCK(sb))) {\n\t\t\tif(buf) {\n\t\t\t\tbrelse(buf);\n\t\t\t\tblock++;\n\t\t\t\td = 0;\n\t\t\t}\n\t\t\tif(!(buf = bread(sb->dev, block, sb->s_blocksize))) {\n\t\t\t\tsuperblock_unlock(sb);\n\t\t\t\treturn -EIO;\n\t\t\t}\n\t\t}\n\t\tgd = (struct ext2_group_desc *)(buf->data + (d * sizeof(struct ext2_group_desc)));\n\t\tif(gd->bg_free_inodes_count) {\n\t\t\tif((errno = find_first_zero(sb, gd->bg_inode_bitmap, &bmbuf)) != -ENOSPC) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbrelse(bmbuf);\n\t\t}\n\t}\n\tif(errno < 0) {\n\t\tbrelse(buf);\n\t\tsuperblock_unlock(sb);\n\t\treturn errno;\n\t}\n\n\tinode = errno;\n\terrno = change_bit(SET_BIT, sb, gd->bg_inode_bitmap, bmbuf, inode);\n\tif(errno) {\n\t\tif(errno < 0) {\n\t\t\tprintk(\"WARNING: %s(): unable to set inode %d.\\n\", __FUNCTION__, inode);\n\t\t\tbrelse(buf);\n\t\t\tsuperblock_unlock(sb);\n\t\t\treturn errno;\n\t\t} else {\n\t\t\tprintk(\"WARNING: %s(): inode %d is already marked as used!\\n\", __FUNCTION__, inode);\n\t\t}\n\t}\n\n\tinode += (bg * EXT2_INODES_PER_GROUP(sb)) + 1;\n\tgd->bg_free_inodes_count--;\n\tsb->u.ext2.sb.s_free_inodes_count--;\n\tsb->state |= SUPERBLOCK_DIRTY;\n\tif(S_ISDIR(mode)) {\n\t\tgd->bg_used_dirs_count++;\n\t}\n\tbwrite(buf);\n\n\ti->inode = inode;\n\ti->i_atime = CURRENT_TIME;\n\ti->i_mtime = CURRENT_TIME;\n\ti->i_ctime = CURRENT_TIME;\n\n\tsuperblock_unlock(sb);\n\treturn 0;\n}\n\nvoid ext2_ifree(struct inode *i)\n{\n\tstruct ext2_group_desc *gd;\n\tstruct buffer *buf;\n\tstruct superblock *sb;\n\t__blk_t b, bg;\n\tint errno;\n\n\tif(!i->inode || i->inode > i->sb->u.ext2.sb.s_inodes_count) {\n\t\tprintk(\"WARNING: %s(): invalid inode %d!\\n\", __FUNCTION__, i->inode);\n\t\treturn;\n\t}\n\n\tif(i->i_blocks) {\n\t\tinvalidate_inode_pages(i);\n\t\text2_truncate(i, 0);\n\t}\n\n\tsb = i->sb;\n\tsuperblock_lock(sb);\n\n\tb = SUPERBLOCK + sb->u.ext2.sb.s_first_data_block;\n\tbg = (i->inode - 1) / EXT2_INODES_PER_GROUP(sb);\n\tif(!(buf = bread(sb->dev, b + (bg / EXT2_DESC_PER_BLOCK(sb)), sb->s_blocksize))) {\n\t\tsuperblock_unlock(sb);\n\t\treturn;\n\t}\n\tgd = (struct ext2_group_desc *)(buf->data + ((bg % EXT2_DESC_PER_BLOCK(sb)) * sizeof(struct ext2_group_desc)));\n\terrno = change_bit(CLEAR_BIT, sb, gd->bg_inode_bitmap, NULL, (i->inode - 1) % EXT2_INODES_PER_GROUP(sb));\n\n\tif(errno) {\n\t\tif(errno < 0) {\n\t\t\tprintk(\"WARNING: %s(): unable to free inode %d.\\n\", __FUNCTION__, i->inode);\n\t\t\tbrelse(buf);\n\t\t\tsuperblock_unlock(sb);\n\t\t\treturn;\n\t\t} else {\n\t\t\tprintk(\"WARNING: %s(): inode %d is already marked as free!\\n\", __FUNCTION__, i->inode);\n\t\t}\n\t}\n\n\tgd->bg_free_inodes_count++;\n\tsb->u.ext2.sb.s_free_inodes_count++;\n\tsb->state |= SUPERBLOCK_DIRTY;\n\tif(S_ISDIR(i->i_mode)) {\n\t\tgd->bg_used_dirs_count--;\n\t}\n\tbwrite(buf);\n\n\ti->i_size = 0;\n\ti->i_mtime = CURRENT_TIME;\n\ti->i_ctime = CURRENT_TIME;\n\ti->state |= INODE_DIRTY;\n\n\tsuperblock_unlock(sb);\n\treturn;\n}\n\nint ext2_balloc(struct superblock *sb)\n{\n\t__blk_t block;\n\tstruct ext2_group_desc *gd;\n\tstruct buffer *buf, *bmbuf;\n\tint bg, d, errno;\n\n\tsuperblock_lock(sb);\n\n\tblock = SUPERBLOCK + sb->u.ext2.sb.s_first_data_block;\n\tbuf = bmbuf = NULL;\n\tgd = NULL;\n\terrno = -ENOSPC;\n\n\t/* read through all group descriptors to find the first unallocated block */\n\tfor(bg = 0, d = 0; bg < sb->u.ext2.block_groups; bg++, d++) {\n\t\tif(!(bg % EXT2_DESC_PER_BLOCK(sb))) {\n\t\t\tif(buf) {\n\t\t\t\tbrelse(buf);\n\t\t\t\tblock++;\n\t\t\t\td = 0;\n\t\t\t}\n\t\t\tif(!(buf = bread(sb->dev, block, sb->s_blocksize))) {\n\t\t\t\tsuperblock_unlock(sb);\n\t\t\t\treturn -EIO;\n\t\t\t}\n\t\t}\n\t\tgd = (struct ext2_group_desc *)(buf->data + (d * sizeof(struct ext2_group_desc)));\n\t\tif(gd->bg_free_blocks_count) {\n\t\t\tif((errno = find_first_zero(sb, gd->bg_block_bitmap, &bmbuf)) != -ENOSPC) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbrelse(bmbuf);\n\t\t}\n\t}\n\tif(errno < 0) {\n\t\tbrelse(buf);\n\t\tsuperblock_unlock(sb);\n\t\treturn errno;\n\t}\n\n\tblock = errno;\n\terrno = change_bit(SET_BIT, sb, gd->bg_block_bitmap, bmbuf, block);\n\tif(errno) {\n\t\tif(errno < 0) {\n\t\t\tprintk(\"WARNING: %s(): unable to set block %d.\\n\", __FUNCTION__, block);\n\t\t\tbrelse(buf);\n\t\t\tsuperblock_unlock(sb);\n\t\t\treturn errno;\n\t\t} else {\n\t\t\tprintk(\"WARNING: %s(): block %d is already marked as used!\\n\", __FUNCTION__, block);\n\t\t}\n\t}\n\n\tblock += (bg * EXT2_BLOCKS_PER_GROUP(sb)) + sb->u.ext2.sb.s_first_data_block;\n\tgd->bg_free_blocks_count--;\n\tsb->u.ext2.sb.s_free_blocks_count--;\n\tsb->state |= SUPERBLOCK_DIRTY;\n\tbwrite(buf);\n\n\tsuperblock_unlock(sb);\n\treturn block;\n}\n\nvoid ext2_bfree(struct superblock *sb, int block)\n{\n\tstruct ext2_group_desc *gd;\n\tstruct buffer *buf;\n\t__blk_t b, bg;\n\tint errno;\n\n\tif(!block || block > sb->u.ext2.sb.s_blocks_count) {\n\t\tprintk(\"WARNING: %s(): invalid block %d!\\n\", __FUNCTION__, block);\n\t\treturn;\n\t}\n\n\tsuperblock_lock(sb);\n\n\tb = SUPERBLOCK + sb->u.ext2.sb.s_first_data_block;\n\tbg = (block - sb->u.ext2.sb.s_first_data_block) / EXT2_BLOCKS_PER_GROUP(sb);\n\tif(!(buf = bread(sb->dev, b + (bg / EXT2_DESC_PER_BLOCK(sb)), sb->s_blocksize))) {\n\t\tsuperblock_unlock(sb);\n\t\treturn;\n\t}\n\tgd = (struct ext2_group_desc *)(buf->data + ((bg % EXT2_DESC_PER_BLOCK(sb)) * sizeof(struct ext2_group_desc)));\n\terrno = change_bit(CLEAR_BIT, sb, gd->bg_block_bitmap, NULL, (block - sb->u.ext2.sb.s_first_data_block) % EXT2_BLOCKS_PER_GROUP(sb));\n\n\tif(errno) {\n\t\tif(errno < 0) {\n\t\t\tprintk(\"WARNING: %s(): unable to free block %d.\\n\", __FUNCTION__, block);\n\t\t\tbrelse(buf);\n\t\t\tsuperblock_unlock(sb);\n\t\t\treturn;\n\t\t} else {\n\t\t\tprintk(\"WARNING: %s(): block %d is already marked as free!\\n\", __FUNCTION__, block);\n\t\t}\n\t}\n\n\tgd->bg_free_blocks_count++;\n\tsb->u.ext2.sb.s_free_blocks_count++;\n\tsb->state |= SUPERBLOCK_DIRTY;\n\tbwrite(buf);\n\n\tsuperblock_unlock(sb);\n\treturn;\n}\n"
  },
  {
    "path": "fs/ext2/dir.c",
    "content": "/*\n * fiwix/fs/ext2/dir.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/buffer.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/stat.h>\n#include <fiwix/dirent.h>\n#include <fiwix/mm.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstruct fs_operations ext2_dir_fsop = {\n\t0,\n\t0,\n\n\text2_dir_open,\n\text2_dir_close,\n\text2_dir_read,\n\tNULL,\t\t\t/* write */\n\tNULL,\t\t\t/* ioctl */\n\tNULL,\t\t\t/* llseek */\n\text2_readdir,\n\text2_readdir64,\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\text2_bmap,\n\text2_lookup,\n\text2_rmdir,\n\text2_link,\n\text2_unlink,\n\text2_symlink,\n\text2_mkdir,\n\text2_mknod,\n\tNULL,\t\t\t/* truncate */\n\text2_create,\n\text2_rename,\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nint ext2_dir_open(struct inode *i, struct fd *f)\n{\n\tf->offset = 0;\n\treturn 0;\n}\n\nint ext2_dir_close(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\nint ext2_dir_read(struct inode *i, struct fd *f, char *buffer, __size_t count)\n{\n\treturn -EISDIR;\n}\n\nint ext2_readdir(struct inode *i, struct fd *f, struct dirent *dirent, __size_t count)\n{\n\t__blk_t block;\n\tunsigned int doffset, offset;\n\tunsigned int size, dirent_len;\n\tstruct ext2_dir_entry_2 *d;\n\tint base_dirent_len;\n\tint blksize;\n\tstruct buffer *buf;\n\n\tif(!(S_ISDIR(i->i_mode))) {\n\t\treturn -EBADF;\n\t}\n\n\tblksize = i->sb->s_blocksize;\n\tif(f->offset > i->i_size) {\n\t\tf->offset = i->i_size;\n\t}\n\n\tbase_dirent_len = sizeof(dirent->d_ino) + sizeof(dirent->d_off) + sizeof(dirent->d_reclen);\n\toffset = size = 0;\n\n\twhile(f->offset < i->i_size && count > 0) {\n\t\tif((block = bmap(i, f->offset, FOR_READING)) < 0) {\n\t\t\treturn block;\n\t\t}\n\t\tif(block) {\n\t\t\tif(!(buf = bread(i->dev, block, blksize))) {\n\t\t\t\treturn -EIO;\n\t\t\t}\n\n\t\t\tdoffset = f->offset;\n\t\t\toffset = f->offset & (blksize - 1);\t/* mod blksize */\n\t\t\twhile(offset < blksize) {\n\t\t\t\td = (struct ext2_dir_entry_2 *)(buf->data + offset);\n\t\t\t\tif(d->inode) {\n\t\t\t\t\tdirent_len = (base_dirent_len + (d->name_len + 1)) + 3;\n\t\t\t\t\tdirent_len &= ~3;\t/* round up */\n\t\t\t\t\tdirent->d_ino = d->inode;\n\t\t\t\t\tif((size + dirent_len) < count) {\n\t\t\t\t\t\tdirent->d_off = doffset;\n\t\t\t\t\t\tdirent->d_reclen = dirent_len;\n\t\t\t\t\t\tmemcpy_b(dirent->d_name, d->name, d->name_len);\n\t\t\t\t\t\tdirent->d_name[d->name_len] = 0;\n\t\t\t\t\t\tdirent = (struct dirent *)((char *)dirent + dirent_len);\n\t\t\t\t\t\tsize += dirent_len;\n\t\t\t\t\t\tcount -= dirent_len;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcount = 0;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tdoffset += d->rec_len;\n\t\t\t\toffset += d->rec_len;\n\t\t\t\tif(!d->rec_len) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbrelse(buf);\n\t\t}\n\t\tf->offset &= ~(blksize - 1);\n\t\tf->offset += offset;\n\t}\n\n\treturn size;\n}\n\nint ext2_readdir64(struct inode *i, struct fd *f, struct dirent64 *dirent, __size_t count)\n{\n\t__blk_t block;\n\tunsigned int doffset, offset;\n\tunsigned int size, dirent_len;\n\tstruct ext2_dir_entry_2 *d;\n\tint base_dirent_len;\n\tint blksize;\n\tstruct buffer *buf;\n\n\tif(!(S_ISDIR(i->i_mode))) {\n\t\treturn -EBADF;\n\t}\n\n\tblksize = i->sb->s_blocksize;\n\tif(f->offset > i->i_size) {\n\t\tf->offset = i->i_size;\n\t}\n\n\tbase_dirent_len = sizeof(dirent->d_ino) + sizeof(dirent->d_off) + sizeof(dirent->d_reclen) + sizeof(dirent->d_type);\n\toffset = size = 0;\n\n\twhile(f->offset < i->i_size && count > 0) {\n\t\tif((block = bmap(i, f->offset, FOR_READING)) < 0) {\n\t\t\treturn block;\n\t\t}\n\t\tif(block) {\n\t\t\tif(!(buf = bread(i->dev, block, blksize))) {\n\t\t\t\treturn -EIO;\n\t\t\t}\n\n\t\t\tdoffset = f->offset;\n\t\t\toffset = f->offset & (blksize - 1);\t/* mod blksize */\n\t\t\twhile(offset < blksize) {\n\t\t\t\td = (struct ext2_dir_entry_2 *)(buf->data + offset);\n\t\t\t\tif(d->inode) {\n\t\t\t\t\tdirent_len = (base_dirent_len + (d->name_len + 1)) + 3;\n\t\t\t\t\tdirent_len &= ~3;\t/* round up */\n\t\t\t\t\tdirent->d_ino = d->inode;\n\t\t\t\t\tif((size + dirent_len) < count) {\n\t\t\t\t\t\tstruct inode *dirent_inode = iget(i->sb, dirent->d_ino);\n\t\t\t\t\t\tdirent->d_off = doffset;\n\t\t\t\t\t\tdirent->d_reclen = dirent_len;\n\t\t\t\t\t\tmemcpy_b(dirent->d_name, d->name, d->name_len);\n\t\t\t\t\t\tdirent->d_name[d->name_len] = 0;\n\t\t\t\t\t\tif (S_ISREG(dirent_inode->i_mode)) {\n\t\t\t\t\t\t\tdirent->d_type = DT_REG;\n\t\t\t\t\t\t} else if (S_ISDIR(dirent_inode->i_mode)) {\n\t\t\t\t\t\t\tdirent->d_type = DT_DIR;\n\t\t\t\t\t\t} else if (S_ISCHR(dirent_inode->i_mode)) {\n\t\t\t\t\t\t\tdirent->d_type = DT_CHR;\n\t\t\t\t\t\t} else if (S_ISBLK(dirent_inode->i_mode)) {\n\t\t\t\t\t\t\tdirent->d_type = DT_BLK;\n\t\t\t\t\t\t} else if (S_ISFIFO(dirent_inode->i_mode)) {\n\t\t\t\t\t\t\tdirent->d_type = DT_FIFO;\n\t\t\t\t\t\t} else if (S_ISSOCK(dirent_inode->i_mode)) {\n\t\t\t\t\t\t\tdirent->d_type = DT_SOCK;\n\t\t\t\t\t\t} else if (S_ISLNK(dirent_inode->i_mode)) {\n\t\t\t\t\t\t\tdirent->d_type = DT_LNK;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tdirent->d_type = DT_UNKNOWN;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tiput(dirent_inode);\n\t\t\t\t\t\tdirent = (struct dirent64 *)((char *)dirent + dirent_len);\n\t\t\t\t\t\tsize += dirent_len;\n\t\t\t\t\t\tcount -= dirent_len;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcount = 0;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tdoffset += d->rec_len;\n\t\t\t\toffset += d->rec_len;\n\t\t\t\tif(!d->rec_len) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbrelse(buf);\n\t\t}\n\t\tf->offset &= ~(blksize - 1);\n\t\tf->offset += offset;\n\t}\n\n\treturn size;\n}\n"
  },
  {
    "path": "fs/ext2/file.c",
    "content": "/*\n * fiwix/fs/ext2/file.c\n *\n * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/buffer.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/mm.h>\n#include <fiwix/mman.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n#include <fiwix/blk_queue.h>\n\nstruct fs_operations ext2_file_fsop = {\n\t0,\n\t0,\n\n\text2_file_open,\n\text2_file_close,\n\tfile_read,\n\text2_file_write,\n\tNULL,\t\t\t/* ioctl */\n\text2_file_llseek,\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\text2_bmap,\n\tNULL,\t\t\t/* lookup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\text2_truncate,\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nint ext2_file_open(struct inode *i, struct fd *f)\n{\n\tf->offset = 0;\n\tif(f->flags & O_TRUNC) {\n\t\ti->i_size = 0;\n\t\text2_truncate(i, 0);\n\t}\n\treturn 0;\n}\n\nint ext2_file_close(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\nint ext2_file_write(struct inode *i, struct fd *f, const char *buffer, __size_t count)\n{\n\t__blk_t block;\n\t__size_t total_written;\n\tunsigned int boffset, bytes;\n\tint blksize, retval;\n\tstruct buffer *buf;\n\tstruct device *d;\n\tstruct blk_request brh, *br, *tmp;\n#ifdef CONFIG_OFFSET64\n\t__loff_t offset;\n#else\n\t__off_t offset;\n#endif /* CONFIG_OFFSET64 */\n\n\tinode_lock(i);\n\n\tblksize = i->sb->s_blocksize;\n\tretval = total_written = 0;\n\n\tif(f->flags & O_APPEND) {\n\t\tf->offset = i->i_size;\n\t}\n\toffset = f->offset;\n\n\tif(count > blksize) {\n\t\tif(!(d = get_device(BLK_DEV, i->dev))) {\n\t\t\tprintk(\"WARNING: %s(): device major %d not found!\\n\", __FUNCTION__, MAJOR(i->dev));\n\t\t\tinode_unlock(i);\n\t\t\treturn -ENXIO;\n\t\t}\n\t\tmemset_b(&brh, 0, sizeof(struct blk_request));\n\t\ttmp = NULL;\n\t\twhile(total_written < count) {\n\t\t\tif(!(br = (struct blk_request *)kmalloc(sizeof(struct blk_request)))) {\n\t\t\t\tprintk(\"WARNING: %s(): no more free memory for block requests.\\n\", __FUNCTION__);\n\t\t\t\tretval = -ENOMEM;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif((block = bmap(i, offset, FOR_WRITING)) < 0) {\n\t\t\t\tretval = block;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tmemset_b(br, 0, sizeof(struct blk_request));\n\t\t\tbr->dev = i->dev;\n\t\t\tbr->block = block;\n\t\t\tbr->size = blksize;\n\t\t\tbr->device = d;\n\t\t\tbr->fn = d->fsop->read_block;\n\t\t\tbr->head_group = &brh;\n\t\t\tif(!brh.next_group) {\n\t\t\t\tbrh.next_group = br;\n\t\t\t} else {\n\t\t\t\ttmp->next_group = br;\n\t\t\t}\n\t\t\ttmp = br;\n\t\t\tboffset = offset & (blksize - 1);\t/* mod blksize */\n\t\t\tbytes = blksize - boffset;\n\t\t\tbytes = MIN(bytes, (count - total_written));\n\t\t\ttotal_written += bytes;\n\t\t\toffset += bytes;\n\t\t}\n\t\tif(!retval) {\n\t\t\tretval = gbread(d, &brh);\n\t\t}\n\t\tbr = brh.next_group;\n\t\toffset = f->offset;\n\t\ttotal_written = 0;\n\t\twhile(br) {\n\t\t\tif(!retval) {\n\t\t\t\tboffset = offset & (blksize - 1);\t/* mod blksize */\n\t\t\t\tbytes = blksize - boffset;\n\t\t\t\tbytes = MIN(bytes, (count - total_written));\n\t\t\t\tmemcpy_b(br->buffer->data + boffset, buffer + total_written, bytes);\n\t\t\t\tupdate_page_cache(i, offset, buffer + total_written, bytes);\n\t\t\t\tbwrite(br->buffer);\n\t\t\t\ttotal_written += bytes;\n\t\t\t\toffset += bytes;\n\t\t\t} else {\n\t\t\t\tif(br->buffer) {\n\t\t\t\t\tbrelse(br->buffer);\n\t\t\t\t}\n\t\t\t}\n\t\t\ttmp = br->next_group;\n\t\t\tkfree((unsigned int)br);\n\t\t\tbr = tmp;\n\t\t}\n\t} else {\n\t\twhile(total_written < count) {\n\t\t\tboffset = offset & (blksize - 1);\t/* mod blksize */\n\t\t\tif((block = bmap(i, offset, FOR_WRITING)) < 0) {\n\t\t\t\tretval = block;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbytes = blksize - boffset;\n\t\t\tbytes = MIN(bytes, (count - total_written));\n\t\t\tif(!(buf = bread(i->dev, block, blksize))) {\n\t\t\t\tretval = -EIO;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tmemcpy_b(buf->data + boffset, buffer + total_written, bytes);\n\t\t\tupdate_page_cache(i, offset, buffer + total_written, bytes);\n\t\t\tbwrite(buf);\n\t\t\ttotal_written += bytes;\n\t\t\toffset += bytes;\n\t\t}\n\t}\n\n\tif(!retval) {\n\t\tf->offset = offset;\n\t\tif(f->offset > i->i_size) {\n\t\t\ti->i_size = f->offset;\n\t\t}\n\t\ti->i_ctime = CURRENT_TIME;\n\t\ti->i_mtime = CURRENT_TIME;\n\t\ti->state |= INODE_DIRTY;\n\t}\n\n\tinode_unlock(i);\n\n\tif(retval) {\n\t\treturn retval;\n\t}\n\treturn total_written;\n}\n\n__loff_t ext2_file_llseek(struct inode *i, __loff_t offset)\n{\n\treturn offset;\n}\n"
  },
  {
    "path": "fs/ext2/inode.c",
    "content": "/*\n * fiwix/fs/ext2/inode.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_ext2.h>\n#include <fiwix/fs_pipe.h>\n#include <fiwix/fs_sock.h>\n#include <fiwix/statfs.h>\n#include <fiwix/sleep.h>\n#include <fiwix/stat.h>\n#include <fiwix/sched.h>\n#include <fiwix/buffer.h>\n#include <fiwix/mm.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#define BLOCKS_PER_IND_BLOCK(sb)\t(EXT2_BLOCK_SIZE(sb) / sizeof(unsigned int))\n#define BLOCKS_PER_DIND_BLOCK(sb)\t(BLOCKS_PER_IND_BLOCK(sb) * BLOCKS_PER_IND_BLOCK(sb))\n#define BLOCKS_PER_TIND_BLOCK(sb)\t(BLOCKS_PER_IND_BLOCK(sb) * BLOCKS_PER_IND_BLOCK(sb) * BLOCKS_PER_IND_BLOCK(sb))\n\n#define EXT2_INODES_PER_BLOCK(sb)\t(EXT2_BLOCK_SIZE(sb) / sizeof(struct ext2_inode))\n\nstatic int free_dblock(struct inode *i, int block, int offset)\n{\n\tint n;\n\tstruct buffer *buf;\n\t__blk_t *dblock;\n\n\tif(!(buf = bread(i->dev, block, i->sb->s_blocksize))) {\n\t\tprintk(\"WARNING: %s(): error reading block %d.\\n\", __FUNCTION__, block);\n\t\treturn -EIO;\n\t}\n\tdblock = (__blk_t *)buf->data;\n\tfor(n = offset; n < BLOCKS_PER_IND_BLOCK(i->sb); n++) {\n\t\tif(dblock[n]) {\n\t\t\text2_bfree(i->sb, dblock[n]);\n\t\t\tdblock[n] = 0;\n\t\t\ti->i_blocks -= i->sb->s_blocksize / 512;\n\t\t}\n\t}\n\tbwrite(buf);\n\treturn 0;\n}\n\nstatic int free_indblock(struct inode *i, int block, int offset)\n{\n\tint n, retval;\n\tstruct buffer *buf;\n\t__blk_t dblock, *indblock;\n\n\tif(!(buf = bread(i->dev, block, i->sb->s_blocksize))) {\n\t\tprintk(\"%s(): error reading doubly indirect block %d.\\n\", __FUNCTION__, block);\n\t\treturn -EIO;\n\t}\n\tindblock = (__blk_t *)buf->data;\n\tdblock = offset % BLOCKS_PER_IND_BLOCK(i->sb);\n\tfor(n = offset / BLOCKS_PER_IND_BLOCK(i->sb); n < BLOCKS_PER_IND_BLOCK(i->sb); n++) {\n\t\tif(indblock[n]) {\n\t\t\tif((retval = free_dblock(i, indblock[n], dblock)) < 0) {\n\t\t\t\tbrelse(buf);\n\t\t\t\treturn retval;\n\t\t\t}\n\t\t\tif(!dblock) {\n\t\t\t\text2_bfree(i->sb, indblock[n]);\n\t\t\t\tindblock[n] = 0;\n\t\t\t\ti->i_blocks -= i->sb->s_blocksize / 512;\n\t\t\t}\n\t\t}\n\t\tdblock = 0;\n\t}\n\tbwrite(buf);\n\treturn 0;\n}\n\nstatic int get_group_desc(struct superblock *sb, __blk_t block_group, struct ext2_group_desc *gd)\n{\n\t__blk_t group_desc_block;\n\tint group_desc;\n\tstruct buffer *buf;\n\n\tgroup_desc_block = block_group / EXT2_DESC_PER_BLOCK(sb);\n\tgroup_desc = block_group % EXT2_DESC_PER_BLOCK(sb);\n\tif(!(buf = bread(sb->dev, SUPERBLOCK + sb->u.ext2.sb.s_first_data_block + group_desc_block, sb->s_blocksize))) {\n\t\treturn -EIO;\n\t}\n\tmemcpy_b(gd, (void *)(buf->data + (group_desc * sizeof(struct ext2_group_desc))), sizeof(struct ext2_group_desc));\n\tbrelse(buf);\n\treturn 0;\n}\n\nint ext2_read_inode(struct inode *i)\n{\n\t__blk_t block_group, block;\n\tunsigned int offset;\n\tstruct superblock *sb;\n\tstruct ext2_inode *ii;\n\tstruct ext2_group_desc gd;\n\tstruct buffer *buf;\n\n\tif(!(sb = get_superblock(i->dev))) {\n\t\tprintk(\"WARNING: %s(): get_superblock() has returned NULL.\\n\");\n\t\treturn -EINVAL;\n\t}\n\tblock_group = ((i->inode - 1) / EXT2_INODES_PER_GROUP(sb));\n\tif(get_group_desc(sb, block_group, &gd)) {\n\t\treturn -EIO;\n\t}\n\tblock = (((i->inode - 1) % EXT2_INODES_PER_GROUP(sb)) / EXT2_INODES_PER_BLOCK(sb));\n\n\tif(!(buf = bread(i->dev, gd.bg_inode_table + block, i->sb->s_blocksize))) {\n\t\treturn -EIO;\n\t}\n\toffset = ((((i->inode - 1) % EXT2_INODES_PER_GROUP(sb)) % EXT2_INODES_PER_BLOCK(sb)) * sizeof(struct ext2_inode));\n\n\tii = (struct ext2_inode *)(buf->data + offset);\n\tmemcpy_b(&i->u.ext2.i_data, ii->i_block, sizeof(ii->i_block));\n\n\ti->i_mode = ii->i_mode;\n\ti->i_uid = (ii->osd2.linux2.l_i_uid_high << 16) | ii->i_uid;\n\ti->i_size = ii->i_size;\n\ti->i_atime = ii->i_atime;\n\ti->i_ctime = ii->i_ctime;\n\ti->i_mtime = ii->i_mtime;\n\ti->i_gid = (ii->osd2.linux2.l_i_gid_high << 16) | ii->i_gid;\n\ti->i_nlink = ii->i_links_count;\n\ti->i_blocks = ii->i_blocks;\n\ti->i_flags = ii->i_flags;\n\ti->count = 1;\n\tswitch(i->i_mode & S_IFMT) {\n\t\tcase S_IFCHR:\n\t\t\ti->fsop = &def_chr_fsop;\n\t\t\ti->rdev = ii->i_block[0];\n\t\t\tbreak;\n\t\tcase S_IFBLK:\n\t\t\ti->fsop = &def_blk_fsop;\n\t\t\ti->rdev = ii->i_block[0];\n\t\t\tbreak;\n\t\tcase S_IFIFO:\n\t\t\ti->fsop = &pipefs_fsop;\n\t\t\t/* it's a union so we need to clear pipefs_i */\n\t\t\tmemset_b(&i->u.pipefs, 0, sizeof(struct pipefs_inode));\n\t\t\tbreak;\n\t\tcase S_IFDIR:\n\t\t\ti->fsop = &ext2_dir_fsop;\n\t\t\tbreak;\n\t\tcase S_IFREG:\n\t\t\ti->fsop = &ext2_file_fsop;\n\t\t\tbreak;\n\t\tcase S_IFLNK:\n\t\t\ti->fsop = &ext2_symlink_fsop;\n\t\t\tbreak;\n\t\tcase S_IFSOCK:\n#ifdef CONFIG_NET\n\t\t\ti->fsop = &sockfs_fsop;\n\t\t\t/* it's a union so we need to clear sockfs_inode */\n\t\t\tmemset_b(&i->u.sockfs, 0, sizeof(struct sockfs_inode));\n#else\n\t\t\ti->fsop = NULL;\n#endif /* CONFIG_NET */\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tprintk(\"WARNING: %s(): invalid inode (%d) mode %08o.\\n\", __FUNCTION__, i->inode, i->i_mode);\n\t\t\tbrelse(buf);\n\t\t\treturn -ENOENT;\n\t}\n\tbrelse(buf);\n\treturn 0;\n}\n\nint ext2_write_inode(struct inode *i)\n{\n\t__blk_t block_group, block;\n\tshort int offset;\n\tstruct superblock *sb;\n\tstruct ext2_inode *ii;\n\tstruct ext2_group_desc gd;\n\tstruct buffer *buf;\n\n\tif(!(sb = get_superblock(i->dev))) {\n\t\tprintk(\"WARNING: %s(): get_superblock() has returned NULL.\\n\");\n\t\treturn -EINVAL;\n\t}\n\tblock_group = ((i->inode - 1) / EXT2_INODES_PER_GROUP(sb));\n\tif(get_group_desc(sb, block_group, &gd)) {\n\t\treturn -EIO;\n\t}\n\tblock = (((i->inode - 1) % EXT2_INODES_PER_GROUP(sb)) / EXT2_INODES_PER_BLOCK(sb));\n\n\tif(!(buf = bread(i->dev, gd.bg_inode_table + block, i->sb->s_blocksize))) {\n\t\treturn -EIO;\n\t}\n\toffset = ((((i->inode - 1) % EXT2_INODES_PER_GROUP(sb)) % EXT2_INODES_PER_BLOCK(sb)) * sizeof(struct ext2_inode));\n\tii = (struct ext2_inode *)(buf->data + offset);\n\tmemset_b(ii, 0, sizeof(struct ext2_inode));\n\n\tii->i_mode = i->i_mode;\n\tii->i_uid = i->i_uid & 0xFFFF;\n\tii->osd2.linux2.l_i_uid_high = i->i_uid >> 16;\n\tii->i_size = i->i_size;\n\tii->i_atime = i->i_atime;\n\tii->i_ctime = i->i_ctime;\n\tii->i_mtime = i->i_mtime;\n\tii->i_dtime = i->u.ext2.i_dtime;\n\tii->i_gid = i->i_gid & 0xFFFF;\n\tii->osd2.linux2.l_i_gid_high = i->i_gid >> 16;\n\tii->i_links_count = i->i_nlink;\n\tii->i_blocks = i->i_blocks;\n\tii->i_flags = i->i_flags;\n\tif(S_ISCHR(i->i_mode) || S_ISBLK(i->i_mode)) {\n\t\tii->i_block[0] = i->rdev;\n\t} else {\n\t\tmemcpy_b(ii->i_block, &i->u.ext2.i_data, sizeof(i->u.ext2.i_data));\n\t}\n\ti->state &= ~INODE_DIRTY;\n\tbwrite(buf);\n\treturn 0;\n}\n\nint ext2_bmap(struct inode *i, __off_t offset, int mode)\n{\n\tunsigned char level;\n\t__blk_t *indblock, *dindblock, *tindblock;\n\t__blk_t block, iblock, dblock, tblock, newblock;\n\tint blksize;\n\tstruct buffer *buf, *buf2, *buf3, *buf4;\n\n\tblksize = i->sb->s_blocksize;\n\tblock = offset >> EXT2_BLOCK_SIZE_BITS(i->sb);\n\tlevel = 0;\n\tbuf3 = NULL;\t/* makes GCC happy */\n\n\tif(block < EXT2_NDIR_BLOCKS) {\n\t\tlevel = EXT2_NDIR_BLOCKS - 1;\n\t} else {\n\t\tif(block < (BLOCKS_PER_IND_BLOCK(i->sb) + EXT2_NDIR_BLOCKS)) {\n\t\t\tlevel = EXT2_IND_BLOCK;\n\t\t} else if(block < ((BLOCKS_PER_IND_BLOCK(i->sb) * BLOCKS_PER_IND_BLOCK(i->sb)) + BLOCKS_PER_IND_BLOCK(i->sb) + EXT2_NDIR_BLOCKS)) {\n\t\t\tlevel = EXT2_DIND_BLOCK;\n\t\t} else {\n\t\t\tlevel = EXT2_TIND_BLOCK;\n\t\t}\n\t\tblock -= EXT2_NDIR_BLOCKS;\n\t}\n\n\tif(level < EXT2_NDIR_BLOCKS) {\n\t\tif(!i->u.ext2.i_data[block] && mode == FOR_WRITING) {\n\t\t\tif((newblock = ext2_balloc(i->sb)) < 0) {\n\t\t\t\treturn -ENOSPC;\n\t\t\t}\n\t\t\t/* initialize the new block */\n\t\t\tif(!(buf = bread(i->dev, newblock, blksize))) {\n\t\t\t\text2_bfree(i->sb, newblock);\n\t\t\t\treturn -EIO;\n\t\t\t}\n\t\t\tmemset_b(buf->data, 0, blksize);\n\t\t\tbwrite(buf);\n\t\t\ti->u.ext2.i_data[block] = newblock;\n\t\t\ti->i_blocks += blksize / 512;\n\t\t}\n\t\treturn i->u.ext2.i_data[block];\n\t}\n\n\tif(!i->u.ext2.i_data[level]) {\n\t\tif(mode == FOR_WRITING) {\n\t\t\tif((newblock = ext2_balloc(i->sb)) < 0) {\n\t\t\t\treturn -ENOSPC;\n\t\t\t}\n\t\t\t/* initialize the new block */\n\t\t\tif(!(buf = bread(i->dev, newblock, blksize))) {\n\t\t\t\text2_bfree(i->sb, newblock);\n\t\t\t\treturn -EIO;\n\t\t\t}\n\t\t\tmemset_b(buf->data, 0, blksize);\n\t\t\tbwrite(buf);\n\t\t\ti->u.ext2.i_data[level] = newblock;\n\t\t\ti->i_blocks += blksize / 512;\n\t\t} else {\n\t\t\treturn 0;\n\t\t}\n\t}\n\tif(!(buf = bread(i->dev, i->u.ext2.i_data[level], blksize))) {\n\t\treturn -EIO;\n\t}\n\tindblock = (__blk_t *)buf->data;\n\tdblock = block - BLOCKS_PER_IND_BLOCK(i->sb);\n\ttblock = block - (BLOCKS_PER_IND_BLOCK(i->sb) * BLOCKS_PER_IND_BLOCK(i->sb)) - BLOCKS_PER_IND_BLOCK(i->sb);\n\n\tif(level == EXT2_DIND_BLOCK) {\n\t\tblock = dblock / BLOCKS_PER_IND_BLOCK(i->sb);\n\t}\n\tif(level == EXT2_TIND_BLOCK) {\n\t\tblock = tblock / (BLOCKS_PER_IND_BLOCK(i->sb) * BLOCKS_PER_IND_BLOCK(i->sb));\n\t}\n\n\tif(!indblock[block]) {\n\t\tif(mode == FOR_WRITING) {\n\t\t\tif((newblock = ext2_balloc(i->sb)) < 0) {\n\t\t\t\tbrelse(buf);\n\t\t\t\treturn -ENOSPC;\n\t\t\t}\n\t\t\t/* initialize the new block */\n\t\t\tif(!(buf2 = bread(i->dev, newblock, blksize))) {\n\t\t\t\text2_bfree(i->sb, newblock);\n\t\t\t\tbrelse(buf);\n\t\t\t\treturn -EIO;\n\t\t\t}\n\t\t\tmemset_b(buf2->data, 0, blksize);\n\t\t\tbwrite(buf2);\n\t\t\tindblock[block] = newblock;\n\t\t\ti->i_blocks += blksize / 512;\n\t\t\tif(level == EXT2_IND_BLOCK) {\n\t\t\t\tbwrite(buf);\n\t\t\t\treturn newblock;\n\t\t\t}\n\t\t\tbuf->flags |= (BUFFER_DIRTY | BUFFER_VALID);\n\t\t} else {\n\t\t\tbrelse(buf);\n\t\t\treturn 0;\n\t\t}\n\t}\n\tif(level == EXT2_IND_BLOCK) {\n\t\tnewblock = indblock[block];\n\t\tbrelse(buf);\n\t\treturn newblock;\n\t}\n\n\tif(level == EXT2_TIND_BLOCK) {\n\t\tif(!(buf3 = bread(i->dev, indblock[block], blksize))) {\n\t\t\tprintk(\"%s(): returning -EIO\\n\", __FUNCTION__);\n\t\t\tbrelse(buf);\n\t\t\treturn -EIO;\n\t\t}\n\t\ttindblock = (__blk_t *)buf3->data;\n\t\ttblock -= BLOCKS_PER_DIND_BLOCK(i->sb) * block;\n\t\tblock = tindblock[tblock / BLOCKS_PER_IND_BLOCK(i->sb)];\n\t\tif(!block) {\n\t\t\tif(mode == FOR_WRITING) {\n\t\t\t\tif((newblock = ext2_balloc(i->sb)) < 0) {\n\t\t\t\t\tbrelse(buf);\n\t\t\t\t\tbrelse(buf3);\n\t\t\t\t\treturn -ENOSPC;\n\t\t\t\t}\n\t\t\t\t/* initialize the new block */\n\t\t\t\tif(!(buf4 = bread(i->dev, newblock, blksize))) {\n\t\t\t\t\text2_bfree(i->sb, newblock);\n\t\t\t\t\tbrelse(buf);\n\t\t\t\t\tbrelse(buf3);\n\t\t\t\t\treturn -EIO;\n\t\t\t\t}\n\t\t\t\tmemset_b(buf4->data, 0, blksize);\n\t\t\t\tbwrite(buf4);\n\t\t\t\ttindblock[tblock / BLOCKS_PER_IND_BLOCK(i->sb)] = newblock;\n\t\t\t\ti->i_blocks += blksize / 512;\n\t\t\t\tbuf3->flags |= (BUFFER_DIRTY | BUFFER_VALID);\n\t\t\t\tblock = newblock;\n\t\t\t} else {\n\t\t\t\tbrelse(buf);\n\t\t\t\tbrelse(buf3);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t\tdblock = tblock;\n\t\tiblock = tblock / BLOCKS_PER_IND_BLOCK(i->sb);\n\t\tif(!(buf2 = bread(i->dev, block, blksize))) {\n\t\t\tprintk(\"%s(): returning -EIO\\n\", __FUNCTION__);\n\t\t\tbrelse(buf);\n\t\t\tbrelse(buf3);\n\t\t\treturn -EIO;\n\t\t}\n\t} else {\n\t\tiblock = block;\n\t\tif(!(buf2 = bread(i->dev, indblock[iblock], blksize))) {\n\t\t\tprintk(\"%s(): returning -EIO\\n\", __FUNCTION__);\n\t\t\tbrelse(buf);\n\t\t\treturn -EIO;\n\t\t}\n\t}\n\n\tdindblock = (__blk_t *)buf2->data;\n\tblock = dindblock[dblock - (iblock * BLOCKS_PER_IND_BLOCK(i->sb))];\n\tif(!block && mode == FOR_WRITING) {\n\t\tif((newblock = ext2_balloc(i->sb)) < 0) {\n\t\t\tbrelse(buf);\n\t\t\tif(level == EXT2_TIND_BLOCK) {\n\t\t\t\tbrelse(buf3);\n\t\t\t}\n\t\t\tbrelse(buf2);\n\t\t\treturn -ENOSPC;\n\t\t}\n\t\t/* initialize the new block */\n\t\tif(!(buf4 = bread(i->dev, newblock, blksize))) {\n\t\t\text2_bfree(i->sb, newblock);\n\t\t\tbrelse(buf);\n\t\t\tif(level == EXT2_TIND_BLOCK) {\n\t\t\t\tbrelse(buf3);\n\t\t\t}\n\t\t\tbrelse(buf2);\n\t\t\treturn -EIO;\n\t\t}\n\t\tmemset_b(buf4->data, 0, blksize);\n\t\tbwrite(buf4);\n\t\tdindblock[dblock - (iblock * BLOCKS_PER_IND_BLOCK(i->sb))] = newblock;\n\t\ti->i_blocks += blksize / 512;\n\t\tbuf2->flags |= (BUFFER_DIRTY | BUFFER_VALID);\n\t\tblock = newblock;\n\t}\n\tbrelse(buf);\n\tif(level == EXT2_TIND_BLOCK) {\n\t\tbrelse(buf3);\n\t}\n\tbrelse(buf2);\n\treturn block;\n}\n\nint ext2_truncate(struct inode *i, __off_t length)\n{\n\t__blk_t block, indblock, *dindblock;\n\tstruct buffer *buf;\n\tint n, retval, blksize;\n\n\tblksize = i->sb->s_blocksize;\n\tblock = length >> EXT2_BLOCK_SIZE_BITS(i->sb);\n\n\tif(!S_ISDIR(i->i_mode) && !S_ISREG(i->i_mode) && !S_ISLNK(i->i_mode)) {\n\t\treturn -EINVAL;\n\t}\n\n\tif(block < EXT2_NDIR_BLOCKS) {\n\t\tfor(n = block; n < EXT2_NDIR_BLOCKS; n++) {\n\t\t\tif(i->u.ext2.i_data[n]) {\n\t\t\t\text2_bfree(i->sb, i->u.ext2.i_data[n]);\n\t\t\t\ti->u.ext2.i_data[n] = 0;\n\t\t\t\ti->i_blocks -= blksize / 512;\n\t\t\t}\n\t\t}\n\t\tblock = 0;\n\t}\n\n\tif(!block || block < (BLOCKS_PER_IND_BLOCK(i->sb) + EXT2_NDIR_BLOCKS)) {\n\t\tif(block) {\n\t\t\tblock -= EXT2_NDIR_BLOCKS;\n\t\t}\n\t\tif(i->u.ext2.i_data[EXT2_IND_BLOCK]) {\n\t\t\tif((retval = free_dblock(i, i->u.ext2.i_data[EXT2_IND_BLOCK], block)) < 0) {\n\t\t\t\treturn retval;\n\t\t\t}\n\t\t\tif(!block) {\n\t\t\t\text2_bfree(i->sb, i->u.ext2.i_data[EXT2_IND_BLOCK]);\n\t\t\t\ti->u.ext2.i_data[EXT2_IND_BLOCK] = 0;\n\t\t\t\ti->i_blocks -= blksize / 512;\n\t\t\t}\n\t\t}\n\t\tblock = 0;\n\t}\n\n\tif(!block || block < (BLOCKS_PER_DIND_BLOCK(i->sb) + BLOCKS_PER_IND_BLOCK(i->sb) + EXT2_NDIR_BLOCKS)) {\n\t\tif(block) {\n\t\t\tblock -= EXT2_NDIR_BLOCKS;\n\t\t\tblock -= BLOCKS_PER_IND_BLOCK(i->sb);\n\t\t}\n\t\tif(i->u.ext2.i_data[EXT2_DIND_BLOCK]) {\n\t\t\tif((retval = free_indblock(i, i->u.ext2.i_data[EXT2_DIND_BLOCK], block)) < 0) {\n\t\t\t\treturn retval;\n\t\t\t}\n\t\t\tif(!block) {\n\t\t\t\text2_bfree(i->sb, i->u.ext2.i_data[EXT2_DIND_BLOCK]);\n\t\t\t\ti->u.ext2.i_data[EXT2_DIND_BLOCK] = 0;\n\t\t\t\ti->i_blocks -= blksize / 512;\n\t\t\t}\n\t\t}\n\t\tblock = 0;\n\t}\n\n\tif(!block || block < (BLOCKS_PER_TIND_BLOCK(i->sb) + BLOCKS_PER_DIND_BLOCK(i->sb) + BLOCKS_PER_IND_BLOCK(i->sb) + EXT2_NDIR_BLOCKS)) {\n\t\tif(block) {\n\t\t\tblock -= EXT2_NDIR_BLOCKS;\n\t\t\tblock -= BLOCKS_PER_IND_BLOCK(i->sb);\n\t\t\tblock -= BLOCKS_PER_DIND_BLOCK(i->sb);\n\t\t}\n\t\tif(i->u.ext2.i_data[EXT2_TIND_BLOCK]) {\n\t\t\tif(!(buf = bread(i->dev, i->u.ext2.i_data[EXT2_TIND_BLOCK], blksize))) {\n\t\t\t\tprintk(\"%s(): error reading the triply indirect block (%d).\\n\", __FUNCTION__, i->u.ext2.i_data[EXT2_TIND_BLOCK]);\n\t\t\t\treturn -EIO;\n\t\t\t}\n\t\t\tdindblock = (__blk_t *)buf->data;\n\t\t\tindblock = block % BLOCKS_PER_IND_BLOCK(i->sb);\n\t\t\tfor(n = block / BLOCKS_PER_IND_BLOCK(i->sb); n < BLOCKS_PER_IND_BLOCK(i->sb); n++) {\n\t\t\t\tif(dindblock[n]) {\n\t\t\t\t\tif((retval = free_indblock(i, dindblock[n], indblock)) < 0) {\n\t\t\t\t\t\tbrelse(buf);\n\t\t\t\t\t\treturn retval;\n\t\t\t\t\t}\n\t\t\t\t\tif(!indblock) {\n\t\t\t\t\t\text2_bfree(i->sb, dindblock[n]);\n\t\t\t\t\t\tdindblock[n] = 0;\n\t\t\t\t\t\ti->i_blocks -= blksize / 512;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tindblock = 0;\n\t\t\t}\n\t\t\tbwrite(buf);\n\t\t\tif(!block) {\n\t\t\t\text2_bfree(i->sb, i->u.ext2.i_data[EXT2_TIND_BLOCK]);\n\t\t\t\ti->u.ext2.i_data[EXT2_TIND_BLOCK] = 0;\n\t\t\t\ti->i_blocks -= blksize / 512;\n\t\t\t}\n\t\t}\n\t}\n\n\ti->i_mtime = CURRENT_TIME;\n\ti->i_ctime = CURRENT_TIME;\n\ti->i_size = length;\n\ti->state |= INODE_DIRTY;\n\n\treturn 0;\n}\n"
  },
  {
    "path": "fs/ext2/namei.c",
    "content": "/*\n * fiwix/fs/ext2/namei.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_ext2.h>\n#include <fiwix/buffer.h>\n#include <fiwix/mm.h>\n#include <fiwix/errno.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/stat.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n/* finds a new entry to fit 'name' in the directory 'dir' */\nstatic struct buffer *find_first_free_dir_entry(struct inode *dir, struct ext2_dir_entry_2 **d_res, char *name)\n{\n\t__blk_t block;\n\tunsigned int blksize;\n\tunsigned int offset, doffset;\n\tstruct buffer *buf;\n\tint basesize, rlen, nlen;\n\n\tbasesize = sizeof((*d_res)->inode) + sizeof((*d_res)->rec_len) + sizeof((*d_res)->name_len) + sizeof((*d_res)->file_type);\n\tblksize = dir->sb->s_blocksize;\n\toffset = 0;\n\n\t/*\n\t * nlen is the length of the new entry to be used when searching for\n\t * the first usable entry.\n\t */\n\tnlen = basesize + strlen(name) + 3;\n\tnlen &= ~3;\n\n\twhile(offset < dir->i_size) {\n\t\tif((block = bmap(dir, offset, FOR_READING)) < 0) {\n\t\t\tbreak;\n\t\t}\n\t\tif(block) {\n\t\t\tif(!(buf = bread(dir->dev, block, blksize))) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdoffset = 0;\n\t\t\tdo {\n\t\t\t\t*d_res = (struct ext2_dir_entry_2 *)(buf->data + doffset);\n\t\t\t\t/* calculates the real length of the current entry */\n\t\t\t\trlen = basesize + strlen((*d_res)->name) + 3;\n\t\t\t\trlen &= ~3;\n\t\t\t\t/* returns the first entry where name can fit in */\n\t\t\t\tif(!(*d_res)->inode) {\n\t\t\t\t\tif(nlen <= (*d_res)->rec_len) {\n\t\t\t\t\t\treturn buf;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif(rlen + nlen <= (*d_res)->rec_len) {\n\t\t\t\t\t\tint nrec_len;\n\n\t\t\t\t\t\tnrec_len = (*d_res)->rec_len - rlen;\n\t\t\t\t\t\t(*d_res)->rec_len = rlen;\n\t\t\t\t\t\tdoffset += (*d_res)->rec_len;\n\t\t\t\t\t\t*d_res = (struct ext2_dir_entry_2 *)(buf->data + doffset);\n\t\t\t\t\t\t(*d_res)->rec_len = nrec_len;\n\t\t\t\t\t\treturn buf;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tdoffset += (*d_res)->rec_len;\n\t\t\t} while(doffset < blksize);\n\t\t\tbrelse(buf);\n\t\t\toffset += blksize;\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t*d_res = NULL;\n\treturn NULL;\n}\n\n/* finds an entry in 'dir' based on the 'name' and/or on the inode 'i' */\nstatic struct buffer *find_dir_entry(struct inode *dir, struct inode *i, struct ext2_dir_entry_2 **d_res, char *name)\n{\n\t__blk_t block;\n\tunsigned int blksize;\n\tunsigned int offset, doffset;\n\tstruct buffer *buf;\n\tint basesize, nlen;\n\n\tbasesize = sizeof((*d_res)->inode) + sizeof((*d_res)->rec_len) + sizeof((*d_res)->name_len) + sizeof((*d_res)->file_type);\n\tblksize = dir->sb->s_blocksize;\n\toffset = 0;\n\n\t/*\n\t * nlen is the length of the new entry to be used when searching for\n\t * the first usable entry.\n\t */\n\tnlen = basesize + strlen(name) + 3;\n\tnlen &= ~3;\n\n\twhile(offset < dir->i_size) {\n\t\tif((block = bmap(dir, offset, FOR_READING)) < 0) {\n\t\t\tbreak;\n\t\t}\n\t\tif(block) {\n\t\t\tif(!(buf = bread(dir->dev, block, blksize))) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdoffset = 0;\n\t\t\tdo {\n\t\t\t\t*d_res = (struct ext2_dir_entry_2 *)(buf->data + doffset);\n\t\t\t\tif(!i) {\n\t\t\t\t\tif((*d_res)->inode) {\n\t\t\t\t\t\t/* returns the first matching name */\n\t\t\t\t\t\tif((*d_res)->name_len == strlen(name)) {\n\t\t\t\t\t\t\tif(!strncmp((*d_res)->name, name, (*d_res)->name_len)) {\n\t\t\t\t\t\t\t\treturn buf;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif((*d_res)->inode == i->inode) {\n\t\t\t\t\t\t/* returns the first matching inode */\n\t\t\t\t\t\tif(!name) {\n\t\t\t\t\t\t\treturn buf;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t/* returns the matching inode and name */\n\t\t\t\t\t\tif((*d_res)->name_len == strlen(name)) {\n\t\t\t\t\t\t\tif(!strncmp((*d_res)->name, name, (*d_res)->name_len)) {\n\t\t\t\t\t\t\t\treturn buf;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tdoffset += (*d_res)->rec_len;\n\t\t\t} while(doffset < blksize);\n\t\t\tbrelse(buf);\n\t\t\toffset += blksize;\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t*d_res = NULL;\n\treturn NULL;\n}\n\nstatic struct buffer *add_dir_entry(struct inode *dir, struct ext2_dir_entry_2 **d_res, char *name)\n{\n\t__blk_t block;\n\tstruct buffer *buf;\n\n\tif(!(buf = find_first_free_dir_entry(dir, d_res, name))) {\n\t\tif((block = bmap(dir, dir->i_size, FOR_WRITING)) < 0) {\n\t\t\treturn NULL;\n\t\t}\n\t\tif(!(buf = bread(dir->dev, block, dir->sb->s_blocksize))) {\n\t\t\treturn NULL;\n\t\t}\n\t\t*d_res = (struct ext2_dir_entry_2 *)buf->data;\n\t\tdir->i_size += dir->sb->s_blocksize;\n\t\t(*d_res)->rec_len = dir->sb->s_blocksize;\n\t}\n\n\treturn buf;\n}\n\nstatic int is_dir_empty(struct inode *dir)\n{\n\t__blk_t block;\n\tunsigned int blksize;\n\tunsigned int offset, doffset;\n\tstruct buffer *buf;\n\tstruct ext2_dir_entry_2 *d;\n\n\tblksize = dir->sb->s_blocksize;\n\toffset = 0;\n\n\twhile(offset < dir->i_size) {\n\t\tif((block = bmap(dir, offset, FOR_READING)) < 0) {\n\t\t\tbreak;\n\t\t}\n\t\tif(block) {\n\t\t\tif(!(buf = bread(dir->dev, block, blksize))) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdoffset = 0;\n\t\t\tdo {\n\t\t\t\tif(doffset + offset >= dir->i_size) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\td = (struct ext2_dir_entry_2 *)(buf->data + doffset);\n\t\t\t\tdoffset += d->rec_len;\n\t\t\t\tif(d->inode && d->name_len == 1 && d->name[0] == '.') {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif(d->inode && d->name_len == 2 && d->name[0] == '.' && d->name[1] == '.') {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif(d->inode) {\n\t\t\t\t\tbrelse(buf);\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t} while(doffset < blksize);\n\t\t\tbrelse(buf);\n\t\t\toffset += blksize;\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn 1;\n}\n\nstatic int is_subdir(struct inode *dir_new, struct inode *i_old)\n{\n\t__ino_t inode;\n\tint errno;\n\n\terrno = 0;\n\tdir_new->count++;\n\tfor(;;) {\n\t\tif(dir_new == i_old) {\n\t\t\terrno = 1;\n\t\t\tbreak;\n\t\t}\n\t\tinode = dir_new->inode;\n\t\tif(ext2_lookup(\"..\", dir_new, &dir_new)) {\n\t\t\tbreak;\n\t\t}\n\t\tif(dir_new->inode == inode) {\n\t\t\tbreak;\n\t\t}\n\t}\n\tiput(dir_new);\n\treturn errno;\n}\n\nint ext2_lookup(const char *name, struct inode *dir, struct inode **i_res)\n{\n\t__blk_t block;\n\tunsigned int blksize;\n\tunsigned int offset, doffset;\n\tstruct buffer *buf;\n\tstruct ext2_dir_entry_2 *d;\n\t__ino_t inode;\n\n\tblksize = dir->sb->s_blocksize;\n\tinode = offset = 0;\n\n\twhile(offset < dir->i_size && !inode) {\n\t\tif((block = bmap(dir, offset, FOR_READING)) < 0) {\n\t\t\treturn block;\n\t\t}\n\t\tif(block) {\n\t\t\tif(!(buf = bread(dir->dev, block, blksize))) {\n\t\t\t\tiput(dir);\n\t\t\t\treturn -EIO;\n\t\t\t}\n\t\t\tdoffset = 0;\n\t\t\tdo {\n\t\t\t\td = (struct ext2_dir_entry_2 *)(buf->data + doffset);\n\t\t\t\t/* check dir entry */\n\t\t\t\tif(d->rec_len < EXT2_DIR_REC_LEN(1)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif(d->inode) {\n\t\t\t\t\tif(d->name_len == strlen(name)) {\n\t\t\t\t\t\tif(strncmp(d->name, name, d->name_len) == 0) {\n\t\t\t\t\t\t\tinode = d->inode;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tdoffset += d->rec_len;\n\t\t\t} while((doffset < blksize) && (!inode));\n\n\t\t\tbrelse(buf);\n\t\t\toffset += blksize;\n\t\t\tif(inode) {\n\t\t\t\t/*\n\t\t\t\t * This prevents a deadlock in iget() when\n\t\t\t\t * trying to lock '.' when 'dir' is the same\n\t\t\t\t * directory (ls -lai <dir>).\n\t\t\t\t */\n\t\t\t\tif(inode == dir->inode) {\n\t\t\t\t\t*i_res = dir;\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\n\t\t\t\tif(!(*i_res = iget(dir->sb, inode))) {\n\t\t\t\t\tiput(dir);\n\t\t\t\t\treturn -EACCES;\n\t\t\t\t}\n\t\t\t\tiput(dir);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t}\n\tiput(dir);\n\treturn -ENOENT;\n}\n\nint ext2_rmdir(struct inode *dir, struct inode *i)\n{\n\tstruct buffer *buf;\n\tstruct ext2_dir_entry_2 *d;\n\n\tinode_lock(i);\n\n\tif(!is_dir_empty(i)) {\n\t\tinode_unlock(i);\n\t\treturn -ENOTEMPTY;\n\t}\n\n\tinode_lock(dir);\n\n\tif(!(buf = find_dir_entry(dir, i, &d, NULL))) {\n\t\tinode_unlock(i);\n\t\tinode_unlock(dir);\n\t\treturn -ENOENT;\n\t}\n\n\td->inode = 0;\n\ti->i_nlink = 0;\n\tdir->i_nlink--;\n\n\ti->i_ctime = CURRENT_TIME;\n\ti->u.ext2.i_dtime = CURRENT_TIME;\n\tdir->i_mtime = CURRENT_TIME;\n\tdir->i_ctime = CURRENT_TIME;\n\n\ti->state |= INODE_DIRTY;\n\tdir->state |= INODE_DIRTY;\n\n\tbwrite(buf);\n\n\tinode_unlock(i);\n\tinode_unlock(dir);\n\treturn 0;\n}\n\nint ext2_link(struct inode *i_old, struct inode *dir_new, char *name)\n{\n\tstruct buffer *buf;\n\tstruct ext2_dir_entry_2 *d;\n\tchar c;\n\tint n;\n\n\tinode_lock(i_old);\n\tinode_lock(dir_new);\n\n\tif(!(buf = add_dir_entry(dir_new, &d, name))) {\n\t\tinode_unlock(i_old);\n\t\tinode_unlock(dir_new);\n\t\treturn -ENOSPC;\n\t}\n\n\td->inode = i_old->inode;\n\td->name_len = strlen(name);\n\t/* strcpy() can't be used here because it places a trailing NULL */\n\tfor(n = 0; n < NAME_MAX; n++) {\n\t\tif((c = name[n])) {\n\t\t\td->name[n] = c;\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\td->file_type = 0;\t/* not used */\n\n\ti_old->i_nlink++;\n\ti_old->i_ctime = CURRENT_TIME;\n\tdir_new->i_mtime = CURRENT_TIME;\n\tdir_new->i_ctime = CURRENT_TIME;\n\n\ti_old->state |= INODE_DIRTY;\n\tdir_new->state |= INODE_DIRTY;\n\n\tbwrite(buf);\n\n\tinode_unlock(i_old);\n\tinode_unlock(dir_new);\n\treturn 0;\n}\n\nint ext2_unlink(struct inode *dir, struct inode *i, char *name)\n{\n\tstruct buffer *buf;\n\tstruct ext2_dir_entry_2 *d;\n\n\tinode_lock(dir);\n\tinode_lock(i);\n\n\tif(!(buf = find_dir_entry(dir, i, &d, name))) {\n\t\tinode_unlock(dir);\n\t\tinode_unlock(i);\n\t\treturn -ENOENT;\n\t}\n\n\t/*\n\t * FIXME: in order to avoid low performance when traversing large\n\t * directories plenty of blank entries, it would be interesting\n\t * to merge every removed entry with the previous entry.\n\t */\n\td->inode = 0;\n\tif(!--i->i_nlink) {\n\t\ti->u.ext2.i_dtime = CURRENT_TIME;\n\t}\n\n\ti->i_ctime = CURRENT_TIME;\n\tdir->i_mtime = CURRENT_TIME;\n\tdir->i_ctime = CURRENT_TIME;\n\n\ti->state |= INODE_DIRTY;\n\tdir->state |= INODE_DIRTY;\n\n\tbwrite(buf);\n\n\tinode_unlock(dir);\n\tinode_unlock(i);\n\treturn 0;\n}\n\nint ext2_symlink(struct inode *dir, char *name, char *oldname)\n{\n\tstruct buffer *buf, *buf2;\n\tstruct inode *i;\n\tstruct ext2_dir_entry_2 *d;\n\t__blk_t block;\n\tchar c, *data;\n\tint n;\n\n\tinode_lock(dir);\n\n\t/* check again to know if this filename already exists */\n\tif((buf = find_dir_entry(dir, NULL, &d, name))) {\n\t\tbrelse(buf);\n\t\tinode_unlock(dir);\n\t\treturn -EEXIST;\n\t}\n\n\tif(!(i = ialloc(dir->sb, S_IFLNK))) {\n\t\tinode_unlock(dir);\n\t\treturn -ENOSPC;\n\t}\n\n\tif(!(buf = add_dir_entry(dir, &d, name))) {\n\t\tiput(i);\n\t\tinode_unlock(dir);\n\t\treturn -ENOSPC;\n\t}\n\n\ti->i_mode = S_IFLNK | (S_IRWXU | S_IRWXG | S_IRWXO);\n\ti->i_uid = current->euid;\n\ti->i_gid = current->egid;\n\ti->dev = dir->dev;\n\ti->count = 1;\n\ti->fsop = &ext2_symlink_fsop;\n\n\tif(strlen(oldname) >= EXT2_N_BLOCKS * sizeof(__u32)) {\n\t\t/* this will be a slow symlink */\n\t\tif((block = ext2_balloc(dir->sb)) < 0) {\n\t\t\tiput(i);\n\t\t\tbrelse(buf);\n\t\t\tinode_unlock(dir);\n\t\t\treturn block;\n\t\t}\n\t\tif(!(buf2 = bread(dir->dev, block, dir->sb->s_blocksize))) {\n\t\t\tiput(i);\n\t\t\tbrelse(buf);\n\t\t\text2_bfree(dir->sb, block);\n\t\t\tinode_unlock(dir);\n\t\t\treturn -EIO;\n\t\t}\n\t\ti->u.ext2.i_data[0] = block;\n\t\tfor(n = 0; n < NAME_MAX; n++) {\n\t\t\tif((c = oldname[n])) {\n\t\t\t\tbuf2->data[n] = c;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tbuf2->data[n] = 0;\n\t\ti->i_blocks = dir->sb->s_blocksize / 512;\n\t\tbwrite(buf2);\n\t} else {\n\t\t/* this will be a fast symlink */\n\t\tdata = (char *)i->u.ext2.i_data;\n\t\tfor(n = 0; n < NAME_MAX; n++) {\n\t\t\tif((c = oldname[n])) {\n\t\t\t\tdata[n] = c;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tdata[n] = 0;\n\t}\n\n\ti->i_size = n;\n\ti->state |= INODE_DIRTY;\n\ti->i_nlink = 1;\n\td->inode = i->inode;\n\td->name_len = strlen(name);\n\t/* strcpy() can't be used here because it places a trailing NULL */\n\tfor(n = 0; n < NAME_MAX; n++) {\n\t\tif((c = name[n])) {\n\t\t\td->name[n] = c;\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\td->file_type = 0;\t/* EXT2_FT_SYMLINK not used */\n\n\tdir->i_mtime = CURRENT_TIME;\n\tdir->i_ctime = CURRENT_TIME;\n\tdir->state |= INODE_DIRTY;\n\n\tbwrite(buf);\n\tiput(i);\n\tinode_unlock(dir);\n\treturn 0;\n}\n\nint ext2_mkdir(struct inode *dir, char *name, __mode_t mode)\n{\n\tstruct buffer *buf, *buf2;\n\tstruct inode *i;\n\tstruct ext2_dir_entry_2 *d, *d2;\n\t__blk_t block;\n\tchar c;\n\tint n;\n\n\tinode_lock(dir);\n\n\t/* check again to know if this filename already exists */\n\tif((buf = find_dir_entry(dir, NULL, &d, name))) {\n\t\tbrelse(buf);\n\t\tinode_unlock(dir);\n\t\treturn -EEXIST;\n\t}\n\n\tif(!(i = ialloc(dir->sb, S_IFDIR))) {\n\t\tinode_unlock(dir);\n\t\treturn -ENOSPC;\n\t}\n\n\ti->i_mode = ((mode & (S_IRWXU | S_IRWXG | S_IRWXO)) & ~current->umask);\n\ti->i_mode |= S_IFDIR;\n\ti->i_uid = current->euid;\n\ti->i_gid = current->egid;\n\ti->dev = dir->dev;\n\ti->count = 1;\n\ti->fsop = &ext2_dir_fsop;\n\n\tif((block = bmap(i, 0, FOR_WRITING)) < 0) {\n\t\tiput(i);\n\t\tinode_unlock(dir);\n\t\treturn block;\n\t}\n\n\tif(!(buf2 = bread(i->dev, block, dir->sb->s_blocksize))) {\n\t\text2_bfree(dir->sb, block);\n\t\tiput(i);\n\t\tinode_unlock(dir);\n\t\treturn -EIO;\n\t}\n\n\tif(!(buf = add_dir_entry(dir, &d, name))) {\n\t\text2_bfree(dir->sb, block);\n\t\tiput(i);\n\t\tbrelse(buf2);\n\t\tinode_unlock(dir);\n\t\treturn -ENOSPC;\n\t}\n\n\td->inode = i->inode;\n\td->name_len = strlen(name);\n\t/* strcpy() can't be used here because it places a trailing NULL */\n\tfor(n = 0; n < NAME_MAX; n++) {\n\t\tif((c = name[n])) {\n\t\t\tif(c != '/') {\n\t\t\t\td->name[n] = c;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\tbreak;\n\t}\n\td->file_type = 0;\t/* EXT2_FT_DIR not used */\n\n\td2 = (struct ext2_dir_entry_2 *)buf2->data;\n\td2->inode = i->inode;\n\td2->name[0] = '.';\n\td2->name[1] = 0;\n\td2->name_len = 1;\n\td2->rec_len = 12;\n\td2->file_type = 0;\t/* EXT2_FT_DIR not used */\n\ti->i_nlink = 1;\n\td2 = (struct ext2_dir_entry_2 *)(buf2->data + 12);\n\td2->inode = dir->inode;\n\td2->name[0] = '.';\n\td2->name[1] = '.';\n\td2->name[2] = 0;\n\td2->name_len = 2;\n\td2->rec_len = i->sb->s_blocksize - 12;\n\td2->file_type = 0;\t/* EXT2_FT_DIR not used */\n\ti->i_nlink++;\n\ti->i_size = i->sb->s_blocksize;\n\ti->i_blocks = dir->sb->s_blocksize / 512;\n\ti->state |= INODE_DIRTY;\n\n\tdir->i_mtime = CURRENT_TIME;\n\tdir->i_ctime = CURRENT_TIME;\n\tdir->i_nlink++;\n\tdir->state |= INODE_DIRTY;\n\n\tbwrite(buf);\n\tbwrite(buf2);\n\tiput(i);\n\tinode_unlock(dir);\n\treturn 0;\n}\n\nint ext2_mknod(struct inode *dir, char *name, __mode_t mode, __dev_t dev)\n{\n\tstruct buffer *buf;\n\tstruct inode *i;\n\tstruct ext2_dir_entry_2 *d;\n\tchar c;\n\tint n;\n\n\tinode_lock(dir);\n\n\t/* check again to know if this filename already exists */\n\tif((buf = find_dir_entry(dir, NULL, &d, name))) {\n\t\tbrelse(buf);\n\t\tinode_unlock(dir);\n\t\treturn -EEXIST;\n\t}\n\n\tif(!(i = ialloc(dir->sb, mode & S_IFMT))) {\n\t\tinode_unlock(dir);\n\t\treturn -ENOSPC;\n\t}\n\n\tif(!(buf = add_dir_entry(dir, &d, name))) {\n\t\ti->i_nlink = 0;\n\t\tiput(i);\n\t\tinode_unlock(dir);\n\t\treturn -ENOSPC;\n\t}\n\n\td->inode = i->inode;\n\td->name_len = strlen(name);\n\t/* strcpy() can't be used here because it places a trailing NULL */\n\tfor(n = 0; n < NAME_MAX; n++) {\n\t\tif((c = name[n])) {\n\t\t\td->name[n] = c;\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\n\ti->i_mode = (mode & ~current->umask) & ~S_IFMT;\n\ti->i_uid = current->euid;\n\ti->i_gid = current->egid;\n\ti->i_nlink = 1;\n\ti->dev = dir->dev;\n\ti->count = 1;\n\ti->state |= INODE_DIRTY;\n\n\tswitch(mode & S_IFMT) {\n\t\tcase S_IFCHR:\n\t\t\ti->fsop = &def_chr_fsop;\n\t\t\ti->rdev = dev;\n\t\t\ti->i_mode |= S_IFCHR;\n\t\t\td->file_type = 0;\t/* EXT2_FT_CHRDEV not used */\n\t\t\tbreak;\n\t\tcase S_IFBLK:\n\t\t\ti->fsop = &def_blk_fsop;\n\t\t\ti->rdev = dev;\n\t\t\ti->i_mode |= S_IFBLK;\n\t\t\td->file_type = 0;\t/* EXT2_FT_BLKDEV not used */\n\t\t\tbreak;\n\t\tcase S_IFIFO:\n\t\t\ti->fsop = &pipefs_fsop;\n\t\t\ti->i_mode |= S_IFIFO;\n\t\t\t/* it's a union so we need to clear pipefs_i */\n\t\t\tmemset_b(&i->u.pipefs, 0, sizeof(struct pipefs_inode));\n\t\t\td->file_type = 0;\t/* EXT2_FT_FIFO not used */\n\t\t\tbreak;\n#ifdef CONFIG_NET\n\t\tcase S_IFSOCK:\n\t\t\ti->fsop = &sockfs_fsop;\n\t\t\ti->i_mode |= S_IFSOCK;\n\t\t\t/* it's a union so we need to clear sockfs_inode */\n\t\t\tmemset_b(&i->u.sockfs, 0, sizeof(struct sockfs_inode));\n\t\t\td->file_type = 0;\t/* EXT2_FT_SOCK not used */\n\t\t\tbreak;\n#endif /* CONFIG_NET */\n\t}\n\n\tdir->i_mtime = CURRENT_TIME;\n\tdir->i_ctime = CURRENT_TIME;\n\tdir->state |= INODE_DIRTY;\n\n\tbwrite(buf);\n\tiput(i);\n\tinode_unlock(dir);\n\treturn 0;\n}\n\nint ext2_create(struct inode *dir, char *name, int flags, __mode_t mode, struct inode **i_res)\n{\n\tstruct buffer *buf;\n\tstruct inode *i;\n\tstruct ext2_dir_entry_2 *d;\n\tchar c;\n\tint n;\n\n\tif(IS_RDONLY_FS(dir)) {\n\t\treturn -EROFS;\n\t}\n\n\tinode_lock(dir);\n\n\tif(flags & O_CREAT) {\n\t\t/* check again to know if this filename already exists */\n\t\tif((buf = find_dir_entry(dir, NULL, &d, name))) {\n\t\t\tbrelse(buf);\n\t\t\tinode_unlock(dir);\n\t\t\treturn -EEXIST;\n\t\t}\n\t}\n\n\tif(!(i = ialloc(dir->sb, S_IFREG))) {\n\t\tinode_unlock(dir);\n\t\treturn -ENOSPC;\n\t}\n\n\tif(!(buf = add_dir_entry(dir, &d, name))) {\n\t\ti->i_nlink = 0;\n\t\tiput(i);\n\t\tinode_unlock(dir);\n\t\treturn -ENOSPC;\n\t}\n\n\td->inode = i->inode;\n\td->name_len = strlen(name);\n\t/* strcpy() can't be used here because it places a trailing NULL */\n\tfor(n = 0; n < NAME_MAX; n++) {\n\t\tif((c = name[n])) {\n\t\t\td->name[n] = c;\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\td->file_type = 0;\t/* EXT2_FT_REG_FILE not used */\n\n\ti->i_mode = (mode & ~current->umask) & ~S_IFMT;\n\ti->i_mode |= S_IFREG;\n\ti->i_uid = current->euid;\n\ti->i_gid = current->egid;\n\ti->i_nlink = 1;\n\ti->i_blocks = 0;\n\ti->dev = dir->dev;\n\ti->fsop = &ext2_file_fsop;\n\ti->count = 1;\n\ti->state |= INODE_DIRTY;\n\n\ti->u.ext2.i_dtime = 0;\n\n\tdir->i_mtime = CURRENT_TIME;\n\tdir->i_ctime = CURRENT_TIME;\n\tdir->state |= INODE_DIRTY;\n\n\t*i_res = i;\n\tbwrite(buf);\n\tinode_unlock(dir);\n\treturn 0;\n}\n\nint ext2_rename(struct inode *i_old, struct inode *dir_old, struct inode *i_new, struct inode *dir_new, char *oldpath, char *newpath)\n{\n\tstruct buffer *buf_old, *buf_new;\n\tstruct ext2_dir_entry_2 *d_old, *d_new;\n\tchar c;\n\tint n, errno;\n\n\terrno = 0;\n\n\tif(is_subdir(dir_new, i_old)) {\n\t\treturn -EINVAL;\n\t}\n\n\tinode_lock(i_old);\n\tinode_lock(dir_old);\n\tif(dir_old != dir_new) {\n\t\tinode_lock(dir_new);\n\t}\n\n\tif(!(buf_old = find_dir_entry(dir_old, i_old, &d_old, oldpath))) {\n\t\terrno = -ENOENT;\n\t\tgoto end;\n\t}\n\tif(dir_old == dir_new) {\n\t\t/* free that buffer now to not block buf_new */\n\t\tbrelse(buf_old);\n\t\tbuf_old = NULL;\n\t}\n\n\tif(i_new) {\n\t\tif(S_ISDIR(i_old->i_mode)) {\n\t\t\tif(!is_dir_empty(i_new)) {\n\t\t\t\tif(buf_old) {\n\t\t\t\t\tbrelse(buf_old);\n\t\t\t\t}\n\t\t\t\terrno = -ENOTEMPTY;\n\t\t\t\tgoto end;\n\t\t\t}\n\t\t}\n\t\tif(!(buf_new = find_dir_entry(dir_new, i_new, &d_new, newpath))) {\n\t\t\tif(buf_old) {\n\t\t\t\tbrelse(buf_old);\n\t\t\t}\n\t\t\terrno = -ENOENT;\n\t\t\tgoto end;\n\t\t}\n\t} else {\n\t\tif(!(buf_new = add_dir_entry(dir_new, &d_new, newpath))) {\n\t\t\tif(buf_old) {\n\t\t\t\tbrelse(buf_old);\n\t\t\t}\n\t\t\terrno = -ENOSPC;\n\t\t\tgoto end;\n\t\t}\n\t\tif(S_ISDIR(i_old->i_mode)) {\n\t\t\tdir_old->i_nlink--;\n\t\t\tdir_new->i_nlink++;\n\t\t}\n\t}\n\tif(i_new) {\n\t\ti_new->i_nlink--;\n\t} else {\n\t\ti_new = i_old;\n\t\td_new->name_len = strlen(newpath);\n\t\t/* strcpy() can't be used here because it places a trailing NULL */\n\t\tfor(n = 0; n < NAME_MAX; n++) {\n\t\t\tif((c = newpath[n])) {\n\t\t\t\td_new->name[n] = c;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\n\td_new->inode = i_old->inode;\n\tdir_new->i_mtime = CURRENT_TIME;\n\tdir_new->i_ctime = CURRENT_TIME;\n\ti_new->state |= INODE_DIRTY;\n\tdir_new->state |= INODE_DIRTY;\n\n\tdir_old->i_mtime = CURRENT_TIME;\n\tdir_old->i_ctime = CURRENT_TIME;\n\ti_old->state |= INODE_DIRTY;\n\tdir_old->state |= INODE_DIRTY;\n\tbwrite(buf_new);\n\n\tif(!buf_old) {\n\t\tif(!(buf_old = find_dir_entry(dir_old, i_old, &d_old, oldpath))) {\n\t\t\terrno = -ENOENT;\n\t\t\tgoto end;\n\t\t}\n\t}\n\td_old->inode = 0;\n\tbwrite(buf_old);\n\n\t/* update the parent directory */\n\tif(S_ISDIR(i_old->i_mode)) {\n\t\tbuf_new = find_dir_entry(i_old, dir_old, &d_new, \"..\");\n\t\tif(buf_new) {\n\t\t\td_new->inode = dir_new->inode;\n\t\t\tbwrite(buf_new);\n\t\t}\n\t}\n\nend:\n\tinode_unlock(i_old);\n\tinode_unlock(dir_old);\n\tinode_unlock(dir_new);\n\treturn errno;\n}\n"
  },
  {
    "path": "fs/ext2/super.c",
    "content": "/*\n * fiwix/fs/ext2/super.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_ext2.h>\n#include <fiwix/buffer.h>\n#include <fiwix/sched.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstruct fs_operations ext2_fsop = {\n\tFSOP_REQUIRES_DEV,\n\t0,\n\n\tNULL,\t\t\t/* open */\n\tNULL,\t\t\t/* close */\n\tNULL,\t\t\t/* read */\n\tNULL,\t\t\t/* write */\n\tNULL,\t\t\t/* ioctl */\n\tNULL,\t\t\t/* llseek */\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lookup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\text2_read_inode,\n\text2_write_inode,\n\text2_ialloc,\n\text2_ifree,\n\text2_statfs,\n\text2_read_superblock,\n\text2_remount_fs,\n\text2_write_superblock,\n\text2_release_superblock\n};\n\nstatic void check_superblock(struct ext2_super_block *sb)\n{\n\tif(!(sb->s_state & EXT2_VALID_FS)) {\n\t\tprintk(\"WARNING: filesystem unchecked, fsck recommended.\\n\");\n\t} else if((sb->s_state & EXT2_ERROR_FS)) {\n\t\tprintk(\"WARNING: filesystem contains errors, fsck recommended.\\n\");\n\t} else if(sb->s_max_mnt_count >= 0 && sb->s_mnt_count >= (unsigned short int)sb->s_max_mnt_count) {\n\t\tprintk(\"WARNING: maximal mount count reached, fsck recommended.\\n\");\n\t} else if(sb->s_checkinterval && (sb->s_lastcheck + sb->s_checkinterval <= CURRENT_TIME)) {\n\t\tprintk(\"WARNING: checktime reached, fsck recommended.\\n\");\n\t}\n}\n\nvoid ext2_statfs(struct superblock *sb, struct statfs *statfsbuf)\n{\n\tstatfsbuf->f_type = EXT2_SUPER_MAGIC;\n\tstatfsbuf->f_bsize = sb->s_blocksize;\n\tstatfsbuf->f_blocks = sb->u.ext2.sb.s_blocks_count;\n\tstatfsbuf->f_bfree = sb->u.ext2.sb.s_free_blocks_count;\n\tif(statfsbuf->f_bfree >= sb->u.ext2.sb.s_r_blocks_count) {\n\t\tstatfsbuf->f_bavail = statfsbuf->f_bfree - sb->u.ext2.sb.s_r_blocks_count;\n\t} else {\n\t\tstatfsbuf->f_bavail = 0;\n\t}\n\tstatfsbuf->f_files = sb->u.ext2.sb.s_inodes_count;\n\tstatfsbuf->f_ffree = sb->u.ext2.sb.s_free_inodes_count;\n\t/* statfsbuf->f_fsid = ? */\n\tstatfsbuf->f_namelen = EXT2_NAME_LEN;\n}\n\nint ext2_read_superblock(__dev_t dev, struct superblock *sb)\n{\n\tstruct buffer *buf;\n\tstruct ext2_super_block *ext2sb;\n\n\tsuperblock_lock(sb);\n\tif(!(buf = bread(dev, SUPERBLOCK, BLKSIZE_1K))) {\n\t\tprintk(\"WARNING: %s(): I/O error on device %d,%d.\\n\", __FUNCTION__, MAJOR(dev), MINOR(dev));\n\t\tsuperblock_unlock(sb);\n\t\treturn -EIO;\n\t}\n\n\text2sb = (struct ext2_super_block *)buf->data;\n\tif(ext2sb->s_magic != EXT2_SUPER_MAGIC) {\n\t\tprintk(\"WARNING: %s(): invalid filesystem type or bad superblock on device %d,%d.\\n\", __FUNCTION__, MAJOR(dev), MINOR(dev));\n\t\tsuperblock_unlock(sb);\n\t\tbrelse(buf);\n\t\treturn -EINVAL;\n\t}\n\n\tif(ext2sb->s_minor_rev_level || ext2sb->s_rev_level) {\n\t\tprintk(\"WARNING: %s(): unsupported ext2 filesystem revision.\\n\", __FUNCTION__);\n\t\tprintk(\"Only revision 0 (original without features) is supported.\\n\");\n\t\tsuperblock_unlock(sb);\n\t\tbrelse(buf);\n\t\treturn -EINVAL;\n\t}\n\n\tsb->dev = dev;\n\tsb->fsop = &ext2_fsop;\n\tsb->s_blocksize_bits = ext2sb->s_log_block_size + EXT2_MIN_BLOCK_LOG_SIZE;\n\tsb->s_blocksize = 1 << sb->s_blocksize_bits;\n\tmemcpy_b(&sb->u.ext2.sb, ext2sb, sizeof(struct ext2_super_block));\n\tsb->u.ext2.desc_per_block = sb->s_blocksize / sizeof(struct ext2_group_desc);\n\tsb->u.ext2.block_groups = 1 + (ext2sb->s_blocks_count - 1) / EXT2_BLOCKS_PER_GROUP(sb);\n\n\tif(!(sb->root = iget(sb, EXT2_ROOT_INO))) {\n\t\tprintk(\"WARNING: %s(): unable to get root inode.\\n\", __FUNCTION__);\n\t\tsuperblock_unlock(sb);\n\t\tbrelse(buf);\n\t\treturn -EINVAL;\n\t}\n\n\tcheck_superblock(ext2sb);\n\tif(!(sb->flags & MS_RDONLY)) {\n\t\tsb->u.ext2.sb.s_state &= ~EXT2_VALID_FS;\n\t\tsb->u.ext2.sb.s_mnt_count++;\n\t\tsb->u.ext2.sb.s_mtime = CURRENT_TIME;\n\t\tmemcpy_b(buf->data, &sb->u.ext2.sb, sizeof(struct ext2_super_block));\n\t\tbwrite(buf);\n\t} else {\n\t\tbrelse(buf);\n\t}\n\tsuperblock_unlock(sb);\n\treturn 0;\n}\n\nint ext2_remount_fs(struct superblock *sb, int flags)\n{\n\tstruct buffer *buf;\n\tstruct ext2_super_block *ext2sb;\n\n\tif((flags & MS_RDONLY) == (sb->flags & MS_RDONLY)) {\n\t\treturn 0;\n\t}\n\n\tsuperblock_lock(sb);\n\tif(!(buf = bread(sb->dev, SUPERBLOCK, BLKSIZE_1K))) {\n\t\tsuperblock_unlock(sb);\n\t\treturn -EIO;\n\t}\n\text2sb = (struct ext2_super_block *)buf->data;\n\n\tif(flags & MS_RDONLY) {\n\t\t/* switching from RW to RO */\n\t\tsb->u.ext2.sb.s_state |= EXT2_VALID_FS;\n\t\text2sb->s_state |= EXT2_VALID_FS;\n\t} else {\n\t\t/* switching from RO to RW */\n\t\tcheck_superblock(ext2sb);\n\t\tmemcpy_b(&sb->u.ext2.sb, ext2sb, sizeof(struct ext2_super_block));\n\t\tsb->u.ext2.sb.s_state &= ~EXT2_VALID_FS;\n\t\tsb->u.ext2.sb.s_mnt_count++;\n\t\tsb->u.ext2.sb.s_mtime = CURRENT_TIME;\n\t\text2sb->s_state &= ~EXT2_VALID_FS;\n\t}\n\n\tsb->state = SUPERBLOCK_DIRTY;\n\tsuperblock_unlock(sb);\n\tbwrite(buf);\n\treturn 0;\n}\n\nint ext2_write_superblock(struct superblock *sb)\n{\n\tstruct buffer *buf;\n\n\tsuperblock_lock(sb);\n\tif(!(buf = bread(sb->dev, SUPERBLOCK, BLKSIZE_1K))) {\n\t\tsuperblock_unlock(sb);\n\t\treturn -EIO;\n\t}\n\n\tmemcpy_b(buf->data, &sb->u.ext2.sb, sizeof(struct ext2_super_block));\n\tsb->state &= ~SUPERBLOCK_DIRTY;\n\tsuperblock_unlock(sb);\n\tbwrite(buf);\n\treturn 0;\n}\n\nvoid ext2_release_superblock(struct superblock *sb)\n{\n\tif(sb->flags & MS_RDONLY) {\n\t\treturn;\n\t}\n\n\tsuperblock_lock(sb);\n\n\tsb->u.ext2.sb.s_state |= EXT2_VALID_FS;\n\tsb->state = SUPERBLOCK_DIRTY;\n\n\tsuperblock_unlock(sb);\n}\n\nint ext2_init(void)\n{\n\treturn register_filesystem(\"ext2\", &ext2_fsop);\n}\n"
  },
  {
    "path": "fs/ext2/symlink.c",
    "content": "/*\n * fiwix/fs/ext2/symlink.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/buffer.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/stat.h>\n#include <fiwix/mm.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstruct fs_operations ext2_symlink_fsop = {\n\t0,\n\t0,\n\n\tNULL,\t\t\t/* open */\n\tNULL,\t\t\t/* close */\n\tNULL,\t\t\t/* read */\n\tNULL,\t\t\t/* write */\n\tNULL,\t\t\t/* ioctl */\n\tNULL,\t\t\t/* llseek */\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\text2_readlink,\n\text2_followlink,\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lookup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nint ext2_readlink(struct inode *i, char *buffer, __size_t count)\n{\n\t__u32 blksize;\n\tstruct buffer *buf;\n\n\tif(!S_ISLNK(i->i_mode)) {\n\t\tprintk(\"%s(): Oops, inode '%d' is not a symlink (!?).\\n\", __FUNCTION__, i->inode);\n\t\treturn 0;\n\t}\n\n\tinode_lock(i);\n\tblksize = i->sb->s_blocksize;\n\tcount = MIN(count, i->i_size);\n\tif(!count) {\n\t\tinode_unlock(i);\n\t\treturn 0;\n\t}\n\tcount = MIN(count, blksize);\n\tif(i->i_blocks) {\t/* slow symlink */\n\t\tif(!(buf = bread(i->dev, i->u.ext2.i_data[0], blksize))) {\n\t\t\tinode_unlock(i);\n\t\t\treturn -EIO;\n\t\t}\n\t\tmemcpy_b(buffer, buf->data, count);\n\t\tbrelse(buf);\n\t} else {\t/* fast symlink */\n\t\tmemcpy_b(buffer, (char *)i->u.ext2.i_data, count);\n\t}\n\tbuffer[count] = 0;\n\tinode_unlock(i);\n\treturn count;\n}\n\nint ext2_followlink(struct inode *dir, struct inode *i, struct inode **i_res)\n{\n\tstruct buffer *buf;\n\tchar *name;\n\t__ino_t errno;\n\n\tif(!i) {\n\t\treturn -ENOENT;\n\t}\n\n\tif(!S_ISLNK(i->i_mode)) {\n\t\tprintk(\"%s(): Oops, inode '%d' is not a symlink (!?).\\n\", __FUNCTION__, i->inode);\n\t\treturn 0;\n\t}\n\n\tif(current->loopcnt > MAX_SYMLINKS) {\n\t\tiput(i);\n\t\tprintk(\"%s(): too many nested symbolic links!\\n\", __FUNCTION__);\n\t\treturn -ELOOP;\n\t}\n\n\tinode_lock(i);\n\tif(i->i_blocks) {\t/* slow symlink */\n\t\tif(!(buf = bread(i->dev, i->u.ext2.i_data[0], i->sb->s_blocksize))) {\n\t\t\tinode_unlock(i);\n\t\t\treturn -EIO;\n\t\t}\n\t\tname = buf->data;\n\t} else {\t/* fast symlink */\n\t\tbuf = NULL;\n\t\tname = (char *)i->u.ext2.i_data;\n\t}\n\tinode_unlock(i);\n\n\tcurrent->loopcnt++;\n\tiput(i);\n\tif(buf) {\n\t\tbrelse(buf);\n\t}\n\terrno = parse_namei(name, dir, i_res, NULL, FOLLOW_LINKS);\n\tcurrent->loopcnt--;\n\treturn errno;\n}\n"
  },
  {
    "path": "fs/fd.c",
    "content": "/*\n * fiwix/fs/fd.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/errno.h>\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/sleep.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstruct fd *fd_table;\n\nstatic struct resource fd_resource = { 0, 0 };\n\nint get_new_fd(struct inode *i)\n{\n\tunsigned int n;\n\n\tlock_resource(&fd_resource);\n\n\tfor(n = 1; n < NR_OPENS; n++) {\n\t\tif(fd_table[n].count == 0) {\n\t\t\tmemset_b(&fd_table[n], 0, sizeof(struct fd));\n\t\t\tfd_table[n].inode = i;\n\t\t\tfd_table[n].count = 1;\n\t\t\tunlock_resource(&fd_resource);\n\t\t\treturn n;\n\t\t}\n\t}\n\n\tunlock_resource(&fd_resource);\n\n\treturn -ENFILE;\n}\n\nvoid release_fd(unsigned int fd)\n{\n\tlock_resource(&fd_resource);\n\tfd_table[fd].count = 0;\n\tunlock_resource(&fd_resource);\n}\n\nint get_new_user_fd(int fd)\n{\n\tint n;\n\n\tfor(n = fd; n < OPEN_MAX && n < current->rlim[RLIMIT_NOFILE].rlim_cur; n++) {\n\t\tif(current->fd[n] == 0) {\n\t\t\tcurrent->fd[n] = -1;\n\t\t\tcurrent->fd_flags[n] = 0;\n\t\t\treturn n;\n\t\t}\n\t}\n\n\treturn -EMFILE;\n}\n\nvoid release_user_fd(int ufd)\n{\n\tcurrent->fd[ufd] = 0;\n}\n\nvoid fd_init(void)\n{\n\tmemset_b(fd_table, 0, fd_table_size);\n}\n"
  },
  {
    "path": "fs/filesystems.c",
    "content": "/*\n * fiwix/fs/filesystems.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstruct filesystems filesystems_table[NR_FILESYSTEMS];\n\nint register_filesystem(const char *name, struct fs_operations *fsop)\n{\n\tint n;\n\t__dev_t dev;\n\n\tfor(n = 0; n < NR_FILESYSTEMS; n++) {\n\t\tif(filesystems_table[n].name) {\n\t\t\tif(strcmp(filesystems_table[n].name, name) == 0) {\n\t\t\t\tprintk(\"WARNING: %s(): filesystem '%s' already registered!\\n\", __FUNCTION__, name);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t}\n\t\tif(!filesystems_table[n].name) {\n\t\t\tfilesystems_table[n].name = name;\n\t\t\tfilesystems_table[n].fsop = fsop;\n\t\t\tif((fsop->flags & FSOP_KERN_MOUNT)) {\n\t\t\t\tdev = fsop->fsdev;\n\t\t\t\treturn kern_mount(dev, &filesystems_table[n]);\n\t\t\t}\n\t\t\treturn 0;\n\t\t}\n\t}\n\tprintk(\"WARNING: %s(): filesystems table is full!\\n\", __FUNCTION__);\n\treturn 1;\n}\n\nstruct filesystems *get_filesystem(const char *name)\n{\n\tint n;\n\n\tif(!name) {\n\t\treturn NULL;\n\t}\n\tfor(n = 0; n < NR_FILESYSTEMS; n++) {\n\t\tif(!filesystems_table[n].name) {\n\t\t\tcontinue;\n\t\t}\n\t\tif(strcmp(filesystems_table[n].name, name) == 0) {\n\t\t\treturn &filesystems_table[n];\n\t\t}\n\t}\n\treturn NULL;\n}\n\nvoid fs_init(void)\n{\n\tmemset_b(filesystems_table, 0, sizeof(filesystems_table));\n\n#ifdef CONFIG_FS_MINIX\n\tif(minix_init()) {\n\t\tprintk(\"%s(): unable to register 'minix' filesystem.\\n\", __FUNCTION__);\n\t}\n#endif /* CONFIG_FS_MINIX */\n\tif(ext2_init()) {\n\t\tprintk(\"%s(): unable to register 'ext2' filesystem.\\n\", __FUNCTION__);\n\t}\n\tif(pipefs_init()) {\n\t\tprintk(\"%s(): unable to register 'pipefs' filesystem.\\n\", __FUNCTION__);\n\t}\n\tif(iso9660_init()) {\n\t\tprintk(\"%s(): unable to register 'iso9660' filesystem.\\n\", __FUNCTION__);\n\t}\n\tif(procfs_init()) {\n\t\tprintk(\"%s(): unable to register 'procfs' filesystem.\\n\", __FUNCTION__);\n\t}\n#ifdef CONFIG_NET\n\tif(sockfs_init()) {\n\t\tprintk(\"%s(): unable to register 'sockfs' filesystem.\\n\", __FUNCTION__);\n\t}\n#endif /* CONFIG_NET */\n#ifdef CONFIG_UNIX98_PTYS\n\tif(devpts_init()) {\n\t\tprintk(\"%s(): unable to register 'devpts' filesystem.\\n\", __FUNCTION__);\n\t}\n#endif /* CONFIG_UNIX98_PTYS */\n}\n"
  },
  {
    "path": "fs/inode.c",
    "content": "/*\n * fiwix/fs/inode.c\n *\n * Copyright 2018-2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n/*\n * inode.c implements a cache with a free list as a doubly circular linked\n * list and a chained hash table with doubly linked lists.\n *\n * hash table\n * +--------+  +--------------+  +--------------+  +--------------+\n * | index  |  |prev|data|next|  |prev|data|next|  |prev|data|next|\n * |   0   --> | /  |    | --->  <--- |    | --->  <--- |    |  / |\n * +--------+  +--------------+  +--------------+  +--------------+\n * +--------+  +--------------+  +--------------+  +--------------+\n * | index  |  |prev|data|next|  |prev|data|next|  |prev|data|next|\n * |   1   --> | /  |    | --->  <--- |    | --->  <--- |    |  / |\n * +--------+  +--------------+  +--------------+  +--------------+\n *              (inode)           (inode)           (inode)\n *    ...\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/sleep.h>\n#include <fiwix/sched.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n#include <fiwix/mm.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#define INODE_HASH(dev, inode)\t(((__dev_t)(dev) ^ (__ino_t)(inode)) % (NR_INO_HASH))\n#define NR_INO_HASH\t(inode_hash_table_size / sizeof(unsigned int))\n\nstruct inode *inode_table;\t\t/* inode pool */\nstruct inode *inode_head;\t\t/* head of free list */\nstruct inode **inode_hash_table;\n\nstatic struct resource sync_resource = { 0, 0 };\n\nstatic struct inode *add_inode_to_pool(void)\n{\n\tunsigned int flags;\n\tstruct inode *i;\n\n\tif(!(i = (struct inode *)kmalloc(sizeof(struct inode)))) {\n\t\treturn NULL;\n\t}\n\tmemset_b(i, 0, sizeof(struct inode));\n\n\tSAVE_FLAGS(flags); CLI();\n\tif(!inode_table) {\n\t\tinode_table = i;\n\t} else {\n\t\ti->prev = inode_table->prev;\n\t\tinode_table->prev->next = i;\n\t}\n\tinode_table->prev = i;\n\tRESTORE_FLAGS(flags);\n\tkstat.nr_inodes++;\n\treturn i;\n}\n\nstatic void del_inode_from_pool(struct inode *i)\n{\n\tunsigned int flags;\n\tstruct inode *tmp;\n\n\ttmp = i;\n\n\tif(!i->next && !i->prev) {\n\t\tprintk(\"WARNING: %s(): trying to delete an unexistent inode (%d).\\n\", __FUNCTION__, i->inode);\n\t\treturn;\n\t}\n\n\tSAVE_FLAGS(flags); CLI();\n\tif(i->next) {\n\t\ti->next->prev = i->prev;\n\t}\n\tif(i->prev) {\n\t\tif(i != inode_table) {\n\t\t\ti->prev->next = i->next;\n\t\t}\n\t}\n\tif(!i->next) {\n\t\tinode_table->prev = i->prev;\n\t}\n\tif(i == inode_table) {\n\t\tinode_table = i->next;\n\t}\n\tRESTORE_FLAGS(flags);\n\n\tkfree((unsigned int)tmp);\n\tkstat.nr_inodes--;\n}\n\nstatic void insert_to_hash(struct inode *i)\n{\n\tstruct inode **h;\n\tint n;\n\n\tn = INODE_HASH(i->dev, i->inode);\n\th = &inode_hash_table[n];\n\n\tif(!*h) {\n\t\t*h = i;\n\t\t(*h)->prev_hash = (*h)->next_hash = NULL;\n\t} else {\n\t\ti->prev_hash = NULL;\n\t\ti->next_hash = *h;\n\t\t(*h)->prev_hash = i;\n\t\t*h = i;\n\t}\n}\n\nstatic void remove_from_hash(struct inode *i)\n{\n\tstruct inode **h;\n\tint n;\n\n\tif(!i->inode) {\n\t\treturn;\n\t}\n\n\tn = INODE_HASH(i->dev, i->inode);\n\th = &inode_hash_table[n];\n\n\twhile(*h) {\n\t\tif(*h == i) {\n\t\t\tif((*h)->next_hash) {\n\t\t\t\t(*h)->next_hash->prev_hash = (*h)->prev_hash;\n\t\t\t}\n\t\t\tif((*h)->prev_hash) {\n\t\t\t\t(*h)->prev_hash->next_hash = (*h)->next_hash;\n\t\t\t}\n\t\t\tif(h == &inode_hash_table[n]) {\n\t\t\t\t*h = (*h)->next_hash;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\th = &(*h)->next_hash;\n\t}\n}\n\nstatic void insert_on_free_list(struct inode *i)\n{\n\tif(!inode_head) {\n\t\tinode_head = i;\n\t} else {\n\t\ti->prev_free = inode_head->prev_free;\n\t\tinode_head->prev_free->next_free = i;\n\t}\n\tinode_head->prev_free = i;\n}\n\nstatic void remove_from_free_list(struct inode *i)\n{\n\tif(!inode_head) {\n\t\treturn;\n\t}\n\n\tif(i->next_free) {\n\t\ti->next_free->prev_free = i->prev_free;\n\t}\n\tif(i->prev_free) {\n\t\tif(i != inode_head) {\n\t\t\ti->prev_free->next_free = i->next_free;\n\t\t}\n\t}\n\tif(!i->next_free) {\n\t\tinode_head->prev_free = i->prev_free;\n\t}\n\tif(i == inode_head) {\n\t\tinode_head = i->next_free;\n\t}\n\ti->prev_free = i->next_free = NULL;\n}\n\nstatic struct inode *get_free_inode(void)\n{\n\tunsigned int flags;\n\tstruct inode *i;\n\n\tif(kstat.nr_inodes < kstat.max_inodes) {\n\t\tif(!(i = add_inode_to_pool())) {\n\t\t\treturn NULL;\n\t\t}\n\t\treturn i;\n\t}\n\n\tSAVE_FLAGS(flags); CLI();\n\tif(!(i = inode_head)) {\n\t\t/* no more inodes on free list */\n\t\tRESTORE_FLAGS(flags);\n\t\treturn NULL;\n\t}\n\n\tremove_from_free_list(i);\n\tremove_from_hash(i);\n\ti->i_mode = 0;\n\ti->i_uid = 0;\n\ti->i_size = 0;\n\ti->i_atime = 0;\n\ti->i_ctime = 0;\n\ti->i_mtime = 0;\n\ti->i_gid = 0;\n\ti->i_nlink = 0;\n\ti->i_blocks = 0;\n\ti->i_flags = 0;\n\ti->mount_point = NULL;\n\ti->state = 0;\n\ti->dev = 0;\n\ti->inode = 0;\n\ti->count = 0;\n\ti->rdev = 0;\n\ti->fsop = NULL;\n\ti->sb = NULL;\n\tmemset_b(&i->u, 0, sizeof(i->u));\n\tRESTORE_FLAGS(flags);\n\treturn i;\n}\n\nstatic int read_inode(struct inode *i)\n{\n\tint errno;\n\n\tinode_lock(i);\n\terrno = i->sb->fsop->read_inode(i);\n\tinode_unlock(i);\n\treturn errno;\n}\n\nstatic int write_inode(struct inode *i)\n{\n\tint errno;\n\n\tif(i->sb && i->sb->fsop && i->sb->fsop->write_inode) {\n\t\terrno = i->sb->fsop->write_inode(i);\n\t} else {\n\t\t/* PIPE_DEV inodes can't be flushed on disk */\n\t\ti->state &= ~INODE_DIRTY;\n\t\terrno = 0;\n\t}\n\n\treturn errno;\n}\n\nstatic struct inode *search_inode_hash(__dev_t dev, __ino_t inode)\n{\n\tstruct inode *i;\n\tint n;\n\n\tn = INODE_HASH(dev, inode);\n\ti = inode_hash_table[n];\n\n\twhile(i) {\n\t\tif(i->dev == dev && i->inode == inode) {\n\t\t\treturn i;\n\t\t}\n\t\ti = i->next_hash;\n\t}\n\n\treturn NULL;\n}\n\nstatic void wait_on_inode(struct inode *i)\n{\n\tfor(;;) {\n\t\tif(i->state & INODE_LOCKED) {\n\t\t\tsleep(i, PROC_UNINTERRUPTIBLE);\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\nvoid inode_lock(struct inode *i)\n{\n\tunsigned int flags;\n\n\tfor(;;) {\n\t\tSAVE_FLAGS(flags); CLI();\n\t\tif(i->state & INODE_LOCKED) {\n\t\t\tRESTORE_FLAGS(flags);\n\t\t\tsleep(i, PROC_UNINTERRUPTIBLE);\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t}\n\ti->state |= INODE_LOCKED;\n\tRESTORE_FLAGS(flags);\n}\n\nvoid inode_unlock(struct inode *i)\n{\n\tunsigned int flags;\n\n\tSAVE_FLAGS(flags); CLI();\n\ti->state &= ~INODE_LOCKED;\n\twakeup(i);\n\tRESTORE_FLAGS(flags);\n}\n\nstruct inode *ialloc(struct superblock *sb, int mode)\n{\n\tstruct inode *i;\n\n\tif((i = get_free_inode())) {\n\t\ti->sb = sb;\n\t\ti->rdev = sb->dev;\n\t\tif(i->sb->fsop->ialloc(i, mode)) {\n\t\t\ti->count = 1;\n\t\t\ti->sb = NULL;\n\t\t\tiput(i);\n\t\t\treturn NULL;\n\t\t}\n\t\ti->dev = sb->dev;\n\t\tinsert_to_hash(i);\n\t\treturn i;\n\t}\n\tprintk(\"WARNING: %s(): no more inodes on free list!\\n\", __FUNCTION__);\n\treturn NULL;\n}\n\nstruct inode *iget(struct superblock *sb, __ino_t inode)\n{\n\tunsigned int flags;\n\tstruct inode *i;\n\n\tif(!inode) {\n\t\treturn NULL;\n\t}\n\n\tfor(;;) {\n\t\tif((i = search_inode_hash(sb->dev, inode))) {\n\t\t\tSAVE_FLAGS(flags); CLI();\n\t\t\tif(i->state & INODE_LOCKED) {\n\t\t\t\tsleep(i, PROC_UNINTERRUPTIBLE);\n\t\t\t\tRESTORE_FLAGS(flags);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif(i->mount_point) {\n\t\t\t\ti = i->mount_point;\n\t\t\t}\n\t\t\tinode_lock(i);\n\t\t\tif(!i->count) {\n\t\t\t\tremove_from_free_list(i);\n\t\t\t}\n\t\t\ti->count++;\n\t\t\tinode_unlock(i);\n\t\t\tRESTORE_FLAGS(flags);\n\t\t\treturn i;\n\t\t}\n\n\t\tif(!(i = get_free_inode())) {\n\t\t\tprintk(\"WARNING: %s(): no more inodes on free list!\\n\", __FUNCTION__);\n\t\t\treturn NULL;\n\t\t}\n\n\t\tSAVE_FLAGS(flags); CLI();\n\t\ti->dev = i->rdev = sb->dev;\n\t\ti->inode = inode;\n\t\ti->sb = sb;\n\t\ti->count = 1;\n\t\tRESTORE_FLAGS(flags);\n\t\tif(read_inode(i)) {\n\t\t\tSAVE_FLAGS(flags); CLI();\n\t\t\ti->count = 0;\n\t\t\tinsert_on_free_list(i);\n\t\t\tRESTORE_FLAGS(flags);\n\t\t\treturn NULL;\n\t\t}\n\t\tinsert_to_hash(i);\n\t\treturn i;\n\t}\n}\n\nint bmap(struct inode *i, __off_t offset, int mode)\n{\n\treturn i->fsop->bmap(i, offset, mode);\n}\n\nint check_fs_busy(__dev_t dev, struct inode *root)\n{\n\tstruct inode *i;\n\n\ti = inode_table;\n\twhile(i) {\n\t\tif(i->dev == dev && i->count) {\n\t\t\tif(i == root && i->count == 1) {\n\t\t\t\ti = i->next;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t/* FIXME: to be removed */\n\t\t\tprintk(\"WARNING: root %d with count %d (on dev %d,%d)\\n\", root->inode, root->count, MAJOR(i->dev), MINOR(i->dev));\n\t\t\tprintk(\"WARNING: inode %d with count %d (on dev %d,%d)\\n\", i->inode, i->count, MAJOR(i->dev), MINOR(i->dev));\n\t\t\treturn 1;\n\t\t}\n\t\ti = i->next;\n\t}\n\treturn 0;\n}\n\nvoid iput(struct inode *i)\n{\n\tunsigned int flags;\n\n\t/* this solves the problem with rmdir('/') and iput(dir) which is NULL */\n\tif(!i) {\n\t\treturn;\n\t}\n\n\twait_on_inode(i);\n\n\tif(!i->count) {\n\t\tprintk(\"WARNING: %s(): trying to free an already freed inode (%d)!\\n\", __FUNCTION__, i->inode);\n\t\treturn;\n\t}\n\n\tif(--i->count > 0) {\n\t\treturn;\n\t}\n\n\tinode_lock(i);\n\tif(!i->i_nlink) {\n\t\tif(i->sb && i->sb->fsop && i->sb->fsop->ifree) {\n\t\t\ti->sb->fsop->ifree(i);\n\t\t}\n\t\tremove_from_hash(i);\n\t}\n\tif(i->state & INODE_DIRTY) {\n\t\tif(write_inode(i)) {\n\t\t\tprintk(\"WARNING: %s(): can't write inode %d (%d,%d), will remain as dirty.\\n\", __FUNCTION__, i->inode, MAJOR(i->dev), MINOR(i->dev));\n\t\t\tif(!i->i_nlink) {\n\t\t\t\tremove_from_hash(i);\n\t\t\t}\n\t\t\ti->count++;\n\t\t\tinode_unlock(i);\n\t\t\treturn;\n\t\t}\n\t}\n\n\tSAVE_FLAGS(flags); CLI();\n\tinode_unlock(i);\n\n\tif(i->rdev > FS_NODEV) {\n\t\t/* inodes from pseudo-filesystems don't need to be cached */\n\t\tremove_from_hash(i);\n\t\tdel_inode_from_pool(i);\n\t} else {\n\t\tinsert_on_free_list(i);\n\t}\n\tRESTORE_FLAGS(flags);\n}\n\nvoid sync_inodes(__dev_t dev)\n{\n\tstruct inode *i;\n\n\ti = inode_table;\n\n\tlock_resource(&sync_resource);\n\twhile(i) {\n\t\tif(i->state & INODE_DIRTY) {\n\t\t\tif(!dev || i->dev == dev) {\n\t\t\t\tinode_lock(i);\n\t\t\t\tif(write_inode(i)) {\n\t\t\t\t\tprintk(\"WARNING: %s(): can't write inode %d (%d,%d), will remain as dirty.\\n\", __FUNCTION__, i->inode, MAJOR(i->dev), MINOR(i->dev));\n\t\t\t\t}\n\t\t\t\tinode_unlock(i);\n\t\t\t}\n\t\t}\n\t\ti = i->next;\n\t}\n\tunlock_resource(&sync_resource);\n}\n\nvoid invalidate_inodes(__dev_t dev)\n{\n\tunsigned int flags;\n\tstruct inode *i;\n\n\ti = inode_table;\n\tSAVE_FLAGS(flags); CLI();\n\n\twhile(i) {\n\t\tif(i->dev == dev) {\n\t\t\tinode_lock(i);\n\t\t\tremove_from_hash(i);\n\t\t\tinode_unlock(i);\n\t\t}\n\t\ti = i->next;\n\t}\n\n\tRESTORE_FLAGS(flags);\n}\n\nvoid inode_init(void)\n{\n\tinode_table = inode_head = NULL;\n\tmemset_b(inode_hash_table, 0, inode_hash_table_size);\n}\n"
  },
  {
    "path": "fs/iso9660/Makefile",
    "content": "# fiwix/fs/iso9660/Makefile\n#\n# Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n# Distributed under the terms of the Fiwix License.\n#\n\n.c.o:\n\t$(CC) $(CFLAGS) -c -o $@ $<\n\nOBJS = inode.o super.o namei.o dir.o file.o rrip.o symlink.o\n\nall:\t$(OBJS)\n\nclean:\n\trm -f *.o\n\n"
  },
  {
    "path": "fs/iso9660/dir.c",
    "content": "/*\n * fiwix/fs/iso9660/dir.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/buffer.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/stat.h>\n#include <fiwix/dirent.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstruct fs_operations iso9660_dir_fsop = {\n\t0,\n\t0,\n\n\tiso9660_dir_open,\n\tiso9660_dir_close,\n\tiso9660_dir_read,\n\tNULL,\t\t\t/* write */\n\tNULL,\t\t\t/* ioctl */\n\tNULL,\t\t\t/* llseek */\n\tiso9660_readdir,\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tiso9660_bmap,\n\tiso9660_lookup,\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statsfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nint iso9660_dir_open(struct inode *i, struct fd *f)\n{\n\tf->offset = 0;\n\treturn 0;\n}\n\nint iso9660_dir_close(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\nint iso9660_dir_read(struct inode *i, struct fd *f, char *buffer, __size_t count)\n{\n\treturn -EISDIR;\n}\n\nint iso9660_readdir(struct inode *i, struct fd *f, struct dirent *dirent, __size_t count)\n{\n\t__blk_t block;\n\tunsigned int doffset, offset;\n\tunsigned int size, dirent_len;\n\tstruct iso9660_directory_record *d;\n\tint base_dirent_len;\n\tint blksize;\n\tstruct buffer *buf;\n\tint nm_len;\n\tchar nm_name[NAME_MAX + 1];\n\n\tif(!(S_ISDIR(i->i_mode))) {\n\t\treturn -EBADF;\n\t}\n\n\tblksize = i->sb->s_blocksize;\n\tif(f->offset > i->i_size) {\n\t\tf->offset = i->i_size;\n\t}\n\n\tbase_dirent_len = sizeof(dirent->d_ino) + sizeof(dirent->d_off) + sizeof(dirent->d_reclen);\n\tdoffset = size = 0;\n\n\twhile(doffset < count) {\n\t\tif((block = bmap(i, f->offset, FOR_READING)) < 0) {\n\t\t\treturn block;\n\t\t}\n\t\tif(block) {\n\t\t\tif(!(buf = bread(i->dev, block, blksize))) {\n\t\t\t\treturn -EIO;\n\t\t\t}\n\n\t\t\tdoffset = f->offset;\n\t\t\toffset = f->offset & (blksize - 1);\t/* mod blksize */\n\n\t\t\twhile(doffset < i->i_size && offset < blksize) {\n\t\t\t\td = (struct iso9660_directory_record *)(buf->data + offset);\n\t\t\t\tif(isonum_711(d->length)) {\n\t\t\t\t\tdirent_len = (base_dirent_len + (isonum_711(d->name_len) + 1)) + 3;\n\t\t\t\t\tdirent_len &= ~3;\t/* round up */\n\t\t\t\t\tif((size + dirent_len) < count) {\n\t\t\t\t\t\tdirent->d_ino = (block << ISO9660_INODE_BITS) + (doffset & ISO9660_INODE_MASK);\n\t\t\t\t\t\tdirent->d_off = doffset;\n\t\t\t\t\t\tdirent->d_reclen = dirent_len;\n\t\t\t\t\t\tif(isonum_711(d->name_len) == 1 && d->name[0] == 0) {\n\t\t\t\t\t\t\tdirent->d_name[0] = '.';\n\t\t\t\t\t\t\tdirent->d_name[1] = 0;\n\t\t\t\t\t\t} else if(isonum_711(d->name_len) == 1 && d->name[0] == 1) {\n\t\t\t\t\t\t\tdirent->d_name[0] = '.';\n\t\t\t\t\t\t\tdirent->d_name[1] = '.';\n\t\t\t\t\t\t\tdirent->d_name[2] = 0;\n\t\t\t\t\t\t\tdirent_len = 16;\n\t\t\t\t\t\t\tdirent->d_reclen = 16;\n\t\t\t\t\t\t\tif(i->u.iso9660.i_parent) {\n\t\t\t\t\t\t\t\tdirent->d_ino = i->u.iso9660.i_parent->inode;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tdirent->d_ino = i->inode;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tnm_len = 0;\n\t\t\t\t\t\t\tif(i->sb->u.iso9660.rrip) {\n\t\t\t\t\t\t\t\tnm_len = get_rrip_filename(d, i, nm_name);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(nm_len) {\n\t\t\t\t\t\t\t\tdirent->d_reclen = (base_dirent_len + nm_len + 1) + 3;\n\t\t\t\t\t\t\t\tdirent->d_reclen &= ~3;\t/* round up */\n\t\t\t\t\t\t\t\tdirent_len = dirent->d_reclen;\n\t\t\t\t\t\t\t\tif((size + dirent_len) < count) {\n\t\t\t\t\t\t\t\t\tdirent->d_name[nm_len] = 0;\n\t\t\t\t\t\t\t\t\tmemcpy_b(dirent->d_name, nm_name, nm_len);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tmemcpy_b(dirent->d_name, d->name, isonum_711(d->name_len));\n\t\t\t\t\t\t\t\tdirent->d_name[isonum_711(d->name_len)] = 0;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(!((char)d->flags[0] & ISO9660_FILE_ISDIR)) {\n\t\t\t\t\t\t\tiso9660_cleanfilename(dirent->d_name, isonum_711(d->name_len));\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdirent = (struct dirent *)((char *)dirent + dirent_len);\n\t\t\t\t\t\tsize += dirent_len;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tdoffset += isonum_711(d->length);\n\t\t\t\t\toffset += isonum_711(d->length);\n\t\t\t\t} else {\n\t\t\t\t\tdoffset &= ~(blksize - 1);\n\t\t\t\t\tdoffset += blksize;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbrelse(buf);\n\t\t}\n\t\tf->offset = doffset;\n\t}\n\treturn size;\n}\n"
  },
  {
    "path": "fs/iso9660/file.c",
    "content": "/*\n * fiwix/fs/iso9660/file.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/buffer.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/mm.h>\n#include <fiwix/mman.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstruct fs_operations iso9660_file_fsop = {\n\t0,\n\t0,\n\n\tiso9660_file_open,\n\tiso9660_file_close,\n\tfile_read,\n\tNULL,\t\t\t/* write */\n\tNULL,\t\t\t/* ioctl */\n\tiso9660_file_llseek,\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tiso9660_bmap,\n\tNULL,\t\t\t/* lookup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nint iso9660_file_open(struct inode *i, struct fd *f)\n{\n\tif(f->flags & (O_WRONLY | O_RDWR | O_TRUNC | O_APPEND)) {\n\t\treturn -ENOENT;\n\t}\n\tf->offset = 0;\n\treturn 0;\n}\n\nint iso9660_file_close(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\n__loff_t iso9660_file_llseek(struct inode *i, __loff_t offset)\n{\n\treturn offset;\n}\n"
  },
  {
    "path": "fs/iso9660/inode.c",
    "content": "/*\n * fiwix/fs/iso9660/inode.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_iso9660.h>\n#include <fiwix/fs_pipe.h>\n#include <fiwix/buffer.h>\n#include <fiwix/stat.h>\n#include <fiwix/mm.h>\n#include <fiwix/sched.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstatic int read_pathtable(struct inode *i)\n{\n\tint n, offset, pt_len, pt_blk;\n\tstruct iso9660_sb_info *sbi;\n\tstruct iso9660_pathtable_record *ptr;\n\tstruct buffer *buf;\n\n\tsbi = (struct iso9660_sb_info *)&i->sb->u.iso9660;\n\tpt_len = isonum_733(sbi->sb->path_table_size);\n\tpt_blk = isonum_731(sbi->sb->type_l_path_table);\n\n\tif(pt_len > PAGE_SIZE) {\n\t\tprintk(\"WARNING: %s(): path table record size (%d) > 4096, not supported yet.\\n\", __FUNCTION__, pt_len);\n\t\treturn -EINVAL;\n\t}\n\n\tif(!(sbi->pathtable_raw = (void *)kmalloc(PAGE_SIZE))) {\n\t\treturn -ENOMEM;\n\t}\n\toffset = 0;\n\twhile(offset < pt_len) {\n\t\tif(!(buf = bread(i->dev, pt_blk++, BLKSIZE_2K))) {\n\t\t\tkfree((unsigned int)sbi->pathtable_raw);\n\t\t\treturn -EIO;\n\t\t}\n\t\tmemcpy_b(sbi->pathtable_raw + offset, (void *)buf->data, MIN(pt_len - offset, BLKSIZE_2K));\n\t\toffset += MIN(pt_len - offset, BLKSIZE_2K);\n\t\tbrelse(buf);\n\t}\n\n\t/* allocate and count the number of records in the Path Table */\n\toffset = n = 0;\n\tif(!(sbi->pathtable = (struct iso9660_pathtable_record **)kmalloc(PAGE_SIZE))) {\n\t\tkfree((unsigned int)sbi->pathtable_raw);\n\t\treturn -ENOMEM;\n\t}\n\tsbi->pathtable[n] = NULL;\n\twhile(offset < pt_len) {\n\t\tptr = (struct iso9660_pathtable_record *)(sbi->pathtable_raw + offset);\n\t\tsbi->pathtable[++n] = ptr;\n\t\toffset += sizeof(struct iso9660_pathtable_record) + isonum_711(ptr->length) + (isonum_711(ptr->length) & 1);\n\t}\n\tsbi->paths = n;\n\n\treturn 0;\n}\n\n/*\nstatic int get_parent_dir_size(struct superblock *sb, __blk_t extent)\n{\n\tint n;\n\tstruct iso9660_pathtable_record *ptr;\n\t__blk_t parent;\n\n\tfor(n = 0; n < sb->u.iso9660.paths; n++) {\n\t\tptr = (struct iso9660_pathtable_record *)sb->u.iso9660.pathtable[n];\n\t\tif(isonum_731(ptr->extent) == extent) {\n\t\t\t\n\t\t\tparent = isonum_723(ptr->parent);\n\t\t\tptr = (struct iso9660_pathtable_record *)sb->u.iso9660.pathtable[parent];\n\t\t\tparent = isonum_731(ptr->extent);\n\t\t\treturn parent;\n\t\t}\n\t}\n\tprintk(\"WARNING: %s(): unable to locate extent '%d' in path table.\\n\", __FUNCTION__, extent);\n\treturn 0;\n}\n*/\n\nint iso9660_read_inode(struct inode *i)\n{\n\tint errno;\n\t__u32 blksize;\n\tstruct superblock *sb;\n\tstruct iso9660_directory_record *d;\n\tstruct buffer *buf;\n\t__blk_t dblock;\n\t__off_t doffset;\n\n\tsb = (struct superblock *)i->sb;\n\tif(!sb->u.iso9660.pathtable) {\n\t\tif((errno = read_pathtable(i))) {\n\t\t\treturn errno;\n\t\t}\n\t}\n\n\tdblock = (i->inode & ~ISO9660_INODE_MASK) >> ISO9660_INODE_BITS;\n\tdoffset = i->inode & ISO9660_INODE_MASK;\n\tblksize = i->sb->s_blocksize;\n\n\t/* FIXME: it only looks in one directory block */\n\tif(!(buf = bread(i->dev, dblock, blksize))) {\n\t\treturn -EIO;\n\t}\n\n\tif(doffset >= blksize) {\n\t\tprintk(\"WARNING: %s(): inode %d (dblock=%d, doffset=%d) not found in directory entry.\\n\", __FUNCTION__, i->inode, dblock, doffset);\n\t\tbrelse(buf);\n\t\treturn -EIO;\n\t}\n\td = (struct iso9660_directory_record *)(buf->data + doffset);\n\n\ti->i_mode = S_IFREG;\n\tif((char)d->flags[0] & ISO9660_FILE_ISDIR) {\n\t\ti->i_mode = S_IFDIR;\n\t}\n\tif(!((char)d->flags[0] & ISO9660_FILE_HASOWNER)) {\n\t\ti->i_mode |= S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;\n\t}\n\ti->i_uid = 0;\n\ti->i_size = isonum_733(d->size);\n\ti->i_atime = isodate(d->date);\n\ti->i_ctime = isodate(d->date);\n\ti->i_mtime = isodate(d->date);\n\ti->i_gid = 0;\n\ti->i_nlink = 1;\n\ti->count = 1;\n\n\ti->u.iso9660.i_extent = isonum_733(d->extent);\n\tcheck_rrip_inode(d, i);\n\tbrelse(buf);\n\n\tswitch(i->i_mode & S_IFMT) {\n\t\tcase S_IFCHR:\n\t\t\ti->fsop = &def_chr_fsop;\n\t\t\tbreak;\n\t\tcase S_IFBLK:\n\t\t\ti->fsop = &def_blk_fsop;\n\t\t\tbreak;\n\t\tcase S_IFIFO:\n\t\t\ti->fsop = &pipefs_fsop;\n\t\t\t/* it's a union so we need to clear pipefs_inode */\n\t\t\tmemset_b(&i->u.pipefs, 0, sizeof(struct pipefs_inode));\n\t\t\tbreak;\n\t\tcase S_IFDIR:\n\t\t\ti->fsop = &iso9660_dir_fsop;\n\t\t\ti->i_nlink++;\n\t\t\tbreak;\n\t\tcase S_IFREG:\n\t\t\ti->fsop = &iso9660_file_fsop;\n\t\t\tbreak;\n\t\tcase S_IFLNK:\n\t\t\ti->fsop = &iso9660_symlink_fsop;\n\t\t\tbreak;\n\t\tcase S_IFSOCK:\n\t\t\ti->fsop = NULL;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tPANIC(\"invalid inode (%d) mode %08o.\\n\", i->inode, i->i_mode);\n\t}\n\treturn 0;\n}\n\nint iso9660_bmap(struct inode *i, __off_t offset, int mode)\n{\n\t__blk_t block;\n\n\tblock = i->u.iso9660.i_extent + (offset / i->sb->s_blocksize);\n\treturn block;\n}\n"
  },
  {
    "path": "fs/iso9660/namei.c",
    "content": "/*\n * fiwix/fs/iso9660/namei.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_iso9660.h>\n#include <fiwix/buffer.h>\n#include <fiwix/stat.h>\n#include <fiwix/mm.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nint iso9660_lookup(const char *name, struct inode *dir, struct inode **i_res)\n{\n\t__blk_t dblock;\n\t__u32 blksize;\n\tint len, dnlen;\n\tunsigned int offset, doffset;\n\tstruct buffer *buf;\n\tstruct iso9660_directory_record *d;\n\t__ino_t inode;\n\tint nm_len;\n\tchar *nm_name;\n\n\tblksize = dir->sb->s_blocksize;\n\tinode = offset = 0;\n\tlen = strlen(name);\n\n\twhile(offset < dir->i_size && !inode) {\n\t\tif((dblock = bmap(dir, offset, FOR_READING)) < 0) {\n\t\t\treturn dblock;\n\t\t}\n\t\tif(dblock) {\n\t\t\tif(!(buf = bread(dir->dev, dblock, blksize))) {\n\t\t\t\treturn -EIO;\n\t\t\t}\n\t\t\tdoffset = 0;\n\t\t\tdo {\n\t\t\t\td = (struct iso9660_directory_record *)(buf->data + doffset);\n\t\t\t\tif(isonum_711(d->length) == 0) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif(len == 1) {\n\t\t\t\t\tif(name[0] == '.' && name[1] == '\\0') {\n\t\t\t\t\t\tif(isonum_711(d->name_len) == 1 && d->name[0] == 0) {\n\t\t\t\t\t\t\tinode = dir->inode;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(len == 2) {\n\t\t\t\t\tif(name[0] == '.' && name[1] == '.' && name[2] == '\\0') {\n\t\t\t\t\t\tif(isonum_711(d->name_len) == 1 && d->name[0] == 1) {\n\t\t\t\t\t\t\tinode = dir->u.iso9660.i_parent->inode;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(!(nm_name = (char *)kmalloc(PAGE_SIZE))) {\n\t\t\t\t\treturn -ENOMEM;\n\t\t\t\t}\n\t\t\t\tnm_len = 0;\n\t\t\t\tif(dir->sb->u.iso9660.rrip) {\n\t\t\t\t\tnm_len = get_rrip_filename(d, dir, nm_name);\n\t\t\t\t}\n\t\t\t\tif(nm_len) {\n\t\t\t\t\tdnlen = nm_len;\n\t\t\t\t} else {\n\t\t\t\t\tdnlen = isonum_711(d->name_len);\n\t\t\t\t\tif(!((char)d->flags[0] & ISO9660_FILE_ISDIR)) {\n\t\t\t\t\t\tiso9660_cleanfilename(d->name, dnlen);\n\t\t\t\t\t\tdnlen = strlen(d->name);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(len == dnlen) {\n\t\t\t\t\tif(nm_len) {\n\t\t\t\t\t\tif(strncmp(nm_name, name, dnlen) == 0) {\n\t\t\t\t\t\t\tinode = (dblock << ISO9660_INODE_BITS) + (doffset & ISO9660_INODE_MASK);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif(strncmp(d->name, name, dnlen) == 0) {\n\t\t\t\t\t\t\tinode = (dblock << ISO9660_INODE_BITS) + (doffset & ISO9660_INODE_MASK);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tkfree((unsigned int)nm_name);\n\t\t\t\tdoffset += isonum_711(d->length);\n\t\t\t} while((doffset < blksize) && (!inode));\n\t\t\tbrelse(buf);\n\t\t\toffset += blksize;\n\t\t\tif(inode) {\n\t\t\t\t/*\n\t\t\t\t * This prevents a deadlock in iget() when\n\t\t\t\t * trying to lock '.' when 'dir' is the same\n\t\t\t\t * directory (ls -lai <tmp>).\n\t\t\t\t */\n\t\t\t\tif(inode == dir->inode) {\n\t\t\t\t\t*i_res = dir;\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\n\t\t\t\tif(!(*i_res = iget(dir->sb, inode))) {\n\t\t\t\t\treturn -EACCES;\n\t\t\t\t}\n\t\t\t\tif(S_ISDIR((*i_res)->i_mode)) {\n\t\t\t\t\tif(!(*i_res)->u.iso9660.i_parent) {\n\t\t\t\t\t\t(*i_res)->u.iso9660.i_parent = dir;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tiput(dir);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t}\n\tiput(dir);\n\treturn -ENOENT;\n}\n"
  },
  {
    "path": "fs/iso9660/rrip.c",
    "content": "/*\n * fiwix/fs/iso9660/rrip.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/buffer.h>\n#include <fiwix/fs_iso9660.h>\n#include <fiwix/mm.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nvoid check_rrip_inode(struct iso9660_directory_record *d, struct inode *i)\n{\n\tunsigned int total_len;\n\tunsigned int len;\n\tunsigned int sig;\n\tint n, nm_len, rootflag;\n\tstruct susp_rrip *rrip;\n\tunsigned int dev_h, dev_l;\n\tunsigned int ce_block, ce_offset, ce_size;\n\tstruct buffer *buf;\n\tunsigned char *sue;\n\tint sl_len;\n\tstruct rrip_sl_component *slc;\n\n\tce_block = ce_offset = ce_size = 0;\n\tbuf = NULL;\n\ttotal_len = isonum_711(d->length);\n\tlen = isonum_711(d->name_len);\n\tif(!(len % 2)) {\n\t\tlen++;\n\t}\n\tsue = (unsigned char *)d->name;\n\tnm_len = 0;\n\nloop:\n\tif(ce_block && ce_size) { \n\t\t/* FIXME: it only looks in one directory block */\n\t\tif(!(buf = bread(i->dev, ce_block, i->sb->s_blocksize))) {\n\t\t\treturn;\n\t\t}\n\t\tsue = (unsigned char *)buf->data + ce_offset;\n\t\ttotal_len = ce_size;\n\t\tlen = 0;\n\t}\n\n\twhile(len < total_len) {\n\t\trrip = (struct susp_rrip *)(sue + len);\n\t\tif(rrip->len == 0) {\n\t\t\tbreak;\n\t\t}\n\t\tsig = GET_SIG(rrip->signature[0], rrip->signature[1]);\n\t\tswitch(sig) {\n\t\t\tcase GET_SIG('S', 'P'):\n\t\t\t\tif(rrip->u.sp.magic[0] != SP_MAGIC1 || rrip->u.sp.magic[1] != SP_MAGIC2) {\n\t\t\t\t\tif(ce_block) {\n\t\t\t\t\t\tbrelse(buf);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase GET_SIG('C', 'E'):\n\t\t\t\tif(ce_block) {\n\t\t\t\t\tbrelse(buf);\n\t\t\t\t}\n\t\t\t\tce_block = isonum_733(rrip->u.ce.block);\n\t\t\t\tce_offset = isonum_733(rrip->u.ce.offset);\n\t\t\t\tce_size = isonum_733(rrip->u.ce.size);\n\t\t\t\tgoto loop;\n\t\t\t\tbreak;\n\t\t\tcase GET_SIG('E', 'R'):\n\t\t\t\ti->sb->u.iso9660.rrip = 1;\n\t\t\t\tprintk(\"ISO 9660 Extensions: \");\n\t\t\t\tfor(n = 0; n < rrip->u.er.len_id; n++) {\n\t\t\t\t\tprintk(\"%c\", rrip->u.er.data[n]);\n\t\t\t\t}\n\t\t\t\tprintk(\"\\n\");\n\t\t\t\tbreak;\n\t\t\tcase GET_SIG('P', 'X'):\n\t\t\t\ti->i_mode  = isonum_733(rrip->u.px.mode);\n\t\t\t\ti->i_nlink = isonum_733(rrip->u.px.nlink);\n\t\t\t\ti->i_uid   = isonum_733(rrip->u.px.uid);\n\t\t\t\ti->i_gid   = isonum_733(rrip->u.px.gid);\n\t\t\t\tbreak;\n\t\t\tcase GET_SIG('P', 'N'):\n\t\t\t\tif(S_ISBLK(i->i_mode) || S_ISCHR(i->i_mode)) {\n\t\t\t\t\tdev_h = isonum_733(rrip->u.pn.dev_h);\n\t\t\t\t\tdev_l = isonum_733(rrip->u.pn.dev_l);\n\t\t\t\t\ti->rdev = MKDEV(dev_h, dev_l);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase GET_SIG('S', 'L'):\n\t\t\t\tsl_len = rootflag = 0;\n\t\t\t\tslc = (struct rrip_sl_component *)&rrip->u.sl.area;\n\t\t\t\twhile(sl_len < (rrip->len - 5)) {\n\t\t\t\t\tif(sl_len && !rootflag) {\n\t\t\t\t\t\tnm_len++;\n\t\t\t\t\t}\n\t\t\t\t\trootflag = 0;\n\t\t\t\t\tswitch(slc->flags & 0xE) {\n\t\t\t\t\t\tcase 0:\n\t\t\t\t\t\t\tnm_len += slc->len;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase SL_CURRENT:\n\t\t\t\t\t\t\tnm_len += 1;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase SL_PARENT:\n\t\t\t\t\t\t\tnm_len += 2;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase SL_ROOT:\n\t\t\t\t\t\t\tnm_len += 1;\n\t\t\t\t\t\t\trootflag = 1;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tprintk(\"WARNING: %s(): unsupported RRIP SL flags %d.\\n\", __FUNCTION__, slc->flags & 0xE);\n\t\t\t\t\t}\n\t\t\t\t\tslc = (struct rrip_sl_component *)(((char *)slc) + slc->len + sizeof(struct rrip_sl_component));\n\t\t\t\t\tsl_len += slc->len + sizeof(struct rrip_sl_component);\n\t\t\t\t}\n\t\t\t\ti->i_size = nm_len;\n\t\t\t\tbreak;\n\t\t\tcase GET_SIG('T', 'F'):\n\t\t\t\tn = 0;\n\t\t\t\tif(rrip->u.tf.flags & TF_CREATION) {\n\t\t\t\t\ti->i_ctime = isodate(rrip->u.tf.times[n++].time);\n\t\t\t\t}\n\t\t\t\tif(rrip->u.tf.flags & TF_MODIFY) {\n\t\t\t\t\ti->i_mtime = isodate(rrip->u.tf.times[n++].time);\n\t\t\t\t}\n\t\t\t\tif(rrip->u.tf.flags & TF_ACCESS) {\n\t\t\t\t\ti->i_atime = isodate(rrip->u.tf.times[n++].time);\n\t\t\t\t}\n\t\t\t\tif(rrip->u.tf.flags & TF_ATTRIBUTES) {\n\t\t\t\t\ti->i_ctime = isodate(rrip->u.tf.times[n++].time);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t\tlen += rrip->len;\n\t}\n\tif(ce_block) {\n\t\tbrelse(buf);\n\t}\n}\n\nint get_rrip_filename(struct iso9660_directory_record *d, struct inode *i, char *name)\n{\n\tunsigned int total_len;\n\tunsigned int len;\n\tunsigned int sig;\n\tint nm_len;\n\tstruct susp_rrip *rrip;\n\tunsigned int ce_block, ce_offset, ce_size;\n\tstruct buffer *buf;\n\tunsigned char *sue;\n\n\tce_block = ce_offset = ce_size = 0;\n\tbuf = NULL;\n\ttotal_len = isonum_711(d->length);\n\tlen = isonum_711(d->name_len);\n\tif(!(len % 2)) {\n\t\tlen++;\n\t}\n\tsue = (unsigned char *)d->name;\n\tnm_len = 0;\n\nloop:\n\tif(ce_block && ce_size) { \n\t\t/* FIXME: it only looks in one directory block */\n\t\tif(!(buf = bread(i->dev, ce_block, i->sb->s_blocksize))) {\n\t\t\treturn 0;\n\t\t}\n\t\tsue = (unsigned char *)buf->data + ce_offset;\n\t\ttotal_len = ce_size;\n\t\tlen = 0;\n\t}\n\n\twhile(len < total_len) {\n\t\trrip = (struct susp_rrip *)(sue + len);\n\t\tif(rrip->len == 0) {\n\t\t\tbreak;\n\t\t}\n\t\tsig = GET_SIG(rrip->signature[0], rrip->signature[1]);\n\t\tswitch(sig) {\n\t\t\tcase GET_SIG('S', 'P'):\n\t\t\t\tif(rrip->u.sp.magic[0] != SP_MAGIC1 || rrip->u.sp.magic[1] != SP_MAGIC2) {\n\t\t\t\t\tif(ce_block) {\n\t\t\t\t\t\tbrelse(buf);\n\t\t\t\t\t}\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase GET_SIG('C', 'E'):\n\t\t\t\tif(ce_block) {\n\t\t\t\t\tbrelse(buf);\n\t\t\t\t}\n\t\t\t\tce_block = isonum_733(rrip->u.ce.block);\n\t\t\t\tce_offset = isonum_733(rrip->u.ce.offset);\n\t\t\t\tce_size = isonum_733(rrip->u.ce.size);\n\t\t\t\tgoto loop;\n\t\t\tcase GET_SIG('N', 'M'):\n\t\t\t\tif(rrip->u.nm.flags) { /* FIXME: & ~(NM_CONTINUE | NM_CURRENT | NM_PARENT)) { */\n\t\t\t\t\tprintk(\"WARNING: %s(): unsupported NM flag settings (%d).\\n\", __FUNCTION__, rrip->u.nm.flags);\n\t\t\t\t\tif(ce_block) {\n\t\t\t\t\t\tbrelse(buf);\n\t\t\t\t\t}\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t\tnm_len = rrip->len - 5;\n\t\t\t\tmemcpy_b(name, rrip->u.nm.name, nm_len);\n\t\t\t\tname[nm_len] = 0;\n\t\t\t\tbreak;\n\t\t}\n\t\tlen += rrip->len;\n\t}\n\tif(ce_block) {\n\t\tbrelse(buf);\n\t}\n\treturn nm_len;\n}\n\nint get_rrip_symlink(struct inode *i, char *name)\n{\n\tunsigned int total_len;\n\tunsigned int len;\n\tunsigned int sig;\n\tint nm_len;\n\tstruct susp_rrip *rrip;\n\tunsigned int ce_block, ce_offset, ce_size;\n\tstruct buffer *buf;\n\tstruct buffer *buf2;\n\tunsigned char *sue;\n\tstruct iso9660_directory_record *d;\n\t__blk_t dblock;\n\t__off_t doffset;\n\tint sl_len, rootflag;\n\tstruct rrip_sl_component *slc;\n\n\tdblock = (i->inode & ~ISO9660_INODE_MASK) >> ISO9660_INODE_BITS;\n\tdoffset = i->inode & ISO9660_INODE_MASK;\n\t/* FIXME: it only looks in one directory block */\n\tif(!(buf = bread(i->dev, dblock, i->sb->s_blocksize))) {\n\t\treturn -EIO;\n\t}\n\td = (struct iso9660_directory_record *)(buf->data + doffset);\n\n\tce_block = ce_offset = ce_size = 0;\n\tbuf2 = NULL;\n\ttotal_len = isonum_711(d->length);\n\tlen = isonum_711(d->name_len);\n\tif(!(len % 2)) {\n\t\tlen++;\n\t}\n\tsue = (unsigned char *)d->name;\n\tnm_len = 0;\n\nloop:\n\tif(ce_block && ce_size) { \n\t\t/* FIXME: it only looks in one directory block */\n\t\tif(!(buf2 = bread(i->dev, ce_block, i->sb->s_blocksize))) {\n\t\t\treturn 0;\n\t\t}\n\t\tsue = (unsigned char *)buf2->data + ce_offset;\n\t\ttotal_len = ce_size;\n\t\tlen = 0;\n\t}\n\n\twhile(len < total_len) {\n\t\trrip = (struct susp_rrip *)(sue + len);\n\t\tif(rrip->len == 0) {\n\t\t\tbreak;\n\t\t}\n\t\tsig = GET_SIG(rrip->signature[0], rrip->signature[1]);\n\t\tswitch(sig) {\n\t\t\tcase GET_SIG('S', 'P'):\n\t\t\t\tif(rrip->u.sp.magic[0] != SP_MAGIC1 || rrip->u.sp.magic[1] != SP_MAGIC2) {\n\t\t\t\t\tif(ce_block) {\n\t\t\t\t\t\tbrelse(buf2);\n\t\t\t\t\t}\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase GET_SIG('C', 'E'):\n\t\t\t\tif(ce_block) {\n\t\t\t\t\tbrelse(buf2);\n\t\t\t\t}\n\t\t\t\tce_block = isonum_733(rrip->u.ce.block);\n\t\t\t\tce_offset = isonum_733(rrip->u.ce.offset);\n\t\t\t\tce_size = isonum_733(rrip->u.ce.size);\n\t\t\t\tgoto loop;\n\t\t\tcase GET_SIG('S', 'L'):\n\t\t\t\tsl_len = rootflag = 0;\n\t\t\t\tslc = (struct rrip_sl_component *)&rrip->u.sl.area;\n\t\t\t\twhile(sl_len < (rrip->len - 5)) {\n\t\t\t\t\tif(sl_len && !rootflag) {\n\t\t\t\t\t\tstrcat(name, \"/\");\n\t\t\t\t\t\tnm_len++;\n\t\t\t\t\t}\n\t\t\t\t\trootflag = 0;\n\t\t\t\t\tswitch(slc->flags & 0xE) {\n\t\t\t\t\t\tcase 0:\n\t\t\t\t\t\t\tnm_len += slc->len;\n\t\t\t\t\t\t\tstrncat(name, slc->name, slc->len);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase SL_CURRENT:\n\t\t\t\t\t\t\tnm_len += 1;\n\t\t\t\t\t\t\tstrcat(name, \".\");\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase SL_PARENT:\n\t\t\t\t\t\t\tnm_len += 2;\n\t\t\t\t\t\t\tstrcat(name, \"..\");\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase SL_ROOT:\n\t\t\t\t\t\t\tnm_len += 1;\n\t\t\t\t\t\t\trootflag = 1;\n\t\t\t\t\t\t\tstrcat(name, \"/\");\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tprintk(\"WARNING: %s(): unsupported RRIP SL flags %d.\\n\", __FUNCTION__, slc->flags & 0xE);\n\t\t\t\t\t}\n\t\t\t\t\tslc = (struct rrip_sl_component *)(((char *)slc) + slc->len + sizeof(struct rrip_sl_component));\n\t\t\t\t\tsl_len += slc->len + sizeof(struct rrip_sl_component);\n\t\t\t\t}\n\t\t\t\tname[nm_len] = 0;\n\t\t\t\tbreak;\n\t\t}\n\t\tlen += rrip->len;\n\t}\n\tif(ce_block) {\n\t\tbrelse(buf2);\n\t}\n\tbrelse(buf);\n\treturn nm_len;\n}\n"
  },
  {
    "path": "fs/iso9660/super.c",
    "content": "/*\n * fiwix/fs/iso9660/super.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_iso9660.h>\n#include <fiwix/buffer.h>\n#include <fiwix/time.h>\n#include <fiwix/sched.h>\n#include <fiwix/mm.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstruct fs_operations iso9660_fsop = {\n\tFSOP_REQUIRES_DEV,\n\t0,\n\n\tNULL,\t\t\t/* open */\n\tNULL,\t\t\t/* close */\n\tNULL,\t\t\t/* read */\n\tNULL,\t\t\t/* write */\n\tNULL,\t\t\t/* ioctl */\n\tNULL,\t\t\t/* llseek */\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lookup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tiso9660_read_inode,\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tiso9660_statfs,\n\tiso9660_read_superblock,\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tiso9660_release_superblock\n};\n\nint isonum_711(char *str)\n{\n\tunsigned char *le;\n\n\tle = (unsigned char *)str;\n\treturn le[0];\n}\n\n/* return a 16bit little-endian number */\nint isonum_723(char *str)\n{\n\tunsigned char *le;\n\n\tle = (unsigned char *)str;\n\treturn le[0] | (le[1] << 8);\n}\n\n/* return a 32bit little-endian number */\nint isonum_731(char *str)\n{\n\tunsigned char *le;\n\n\tle = (unsigned char *)str;\n\treturn le[0] | (le[1] << 8) | (le[2] << 16) | (le[3] << 24);\n}\n\n/* return a 32bit little-endian number */\nint isonum_733(char *p)\n{\n\treturn isonum_731(p);\n}\n\n/* return a date and time format */\nunsigned int isodate(const char *p)\n{\n\tstruct tm tm;\n\n\tif(!p[0]) {\n\t\treturn 0;\n\t}\n\n\ttm.tm_sec = p[5];\n\ttm.tm_min = p[4];\n\ttm.tm_hour = p[3];\n\ttm.tm_mday = p[2];\n\ttm.tm_month = p[1];\n\ttm.tm_year = p[0];\n\ttm.tm_year += 1900;\n\ttm.tm_min += p[6] * 15;\n\n\treturn mktime(&tm);\n}\n\n/* return a clean filename */\nint iso9660_cleanfilename(char *filename, int len)\n{\n\tint n;\n\tchar *p;\n\n\tp = filename;\n\tif(len > 2) {\n\t\tfor(n = 0; n < len; n++) {\n\t\t\tif((len - n) == 2) {\n\t\t\t\tif(p[n] == ';' && p[n + 1] == '1') {\n\t\t\t\t\tfilename[n] = 0;\n\t\t\t\t\tif(p[n - 1] == '.') {\n\t\t\t\t\t\tfilename[n - 1] = 0;\n\t\t\t\t\t}\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn 1;\n}\n\nvoid iso9660_statfs(struct superblock *sb, struct statfs *statfsbuf)\n{\n\tstatfsbuf->f_type = ISO9660_SUPER_MAGIC;\n\tstatfsbuf->f_bsize = sb->s_blocksize;\n\tstatfsbuf->f_blocks = isonum_733(sb->u.iso9660.sb->volume_space_size);\n\tstatfsbuf->f_bfree = 0;\n\tstatfsbuf->f_bavail = 0;\n\tstatfsbuf->f_files = 0;\t\t/* FIXME */\n\tstatfsbuf->f_ffree = 0;\n\t/* statfsbuf->f_fsid = ? */\n\tstatfsbuf->f_namelen = NAME_MAX;\n}\n\nint iso9660_read_superblock(__dev_t dev, struct superblock *sb)\n{\n\tstruct buffer *buf;\n\tstruct iso9660_super_block *iso9660sb;\n\tstruct iso9660_super_block *pvd;\n\tstruct iso9660_directory_record *dr;\n\t__ino_t root_inode;\n\tint n;\n\n\tsuperblock_lock(sb);\n\tpvd = NULL;\n\n\tfor(n = 0; n < ISO9660_MAX_VD; n++) {\n\t\tif(!(buf = bread(dev, ISO9660_SUPERBLOCK + n, BLKSIZE_2K))) {\n\t\t\tsuperblock_unlock(sb);\n\t\t\treturn -EIO;\n\t\t}\n\n\t\tiso9660sb = (struct iso9660_super_block *)buf->data;\n\t\tif(strncmp(iso9660sb->id, ISO9660_STANDARD_ID, sizeof(iso9660sb->id)) || (isonum_711(iso9660sb->type) == ISO9660_VD_END)) {\n\t\t\tbreak;\n\t\t}\n\t\tif(isonum_711(iso9660sb->type) == ISO9660_VD_PRIMARY) {\n\t\t\tpvd = (struct iso9660_super_block *)buf->data;\n\t\t\tbreak;\n\t\t}\n\t\tbrelse(buf);\n\t}\n\tif(!pvd) {\n\t\tprintk(\"WARNING: %s(): invalid filesystem type or bad superblock on device %d,%d.\\n\", __FUNCTION__, MAJOR(dev), MINOR(dev));\n\t\tsuperblock_unlock(sb);\n\t\tbrelse(buf);\n\t\treturn -EINVAL;\n\t}\n\n\tdr = (struct iso9660_directory_record *)pvd->root_directory_record;\n\troot_inode = isonum_711(dr->extent);\n\n\tsb->dev = dev;\n\tsb->fsop = &iso9660_fsop;\n\tsb->flags = MS_RDONLY;\n\tsb->s_blocksize = isonum_723(pvd->logical_block_size);\n\tsb->u.iso9660.rrip = 0;\n\tif(!(sb->u.iso9660.sb = (struct iso9660_super_block *)kmalloc(sizeof(struct iso9660_super_block)))) {\n\t\tsuperblock_unlock(sb);\n\t\tbrelse(buf);\n\t\treturn -ENOMEM;\n\t}\n\tmemcpy_b(sb->u.iso9660.sb, pvd, sizeof(struct iso9660_super_block));\n\tbrelse(buf);\n\n\troot_inode = (root_inode << ISO9660_INODE_BITS) + (0 & ISO9660_INODE_MASK);\n\tif(!(sb->root = iget(sb, root_inode))) {\n\t\tprintk(\"WARNING: %s(): unable to get root inode.\\n\", __FUNCTION__);\n\t\tsuperblock_unlock(sb);\n\t\treturn -EINVAL;\n\t}\n\tsb->u.iso9660.s_root_inode = root_inode;\n\n\tsuperblock_unlock(sb);\n\treturn 0;\n}\n\nvoid iso9660_release_superblock(struct superblock *sb)\n{\n\tkfree((unsigned int)sb->u.iso9660.sb);\n\tkfree((unsigned int)sb->u.iso9660.pathtable);\n\tkfree((unsigned int)sb->u.iso9660.pathtable_raw);\n}\n\nint iso9660_init(void)\n{\n\treturn register_filesystem(\"iso9660\", &iso9660_fsop);\n}\n"
  },
  {
    "path": "fs/iso9660/symlink.c",
    "content": "/*\n * fiwix/fs/iso9660/symlink.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/buffer.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_iso9660.h>\n#include <fiwix/stat.h>\n#include <fiwix/mm.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstruct fs_operations iso9660_symlink_fsop = {\n\t0,\n\t0,\n\n\tNULL,\t\t\t/* open */\n\tNULL,\t\t\t/* close */\n\tNULL,\t\t\t/* read */\n\tNULL,\t\t\t/* write */\n\tNULL,\t\t\t/* ioctl */\n\tNULL,\t\t\t/* llseek */\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tiso9660_readlink,\n\tiso9660_followlink,\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lookup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nint iso9660_readlink(struct inode *i, char *buffer, __size_t count)\n{\n\t__off_t size_read;\n\tchar *name;\n\n\tif(!(name = (char *)kmalloc(PAGE_SIZE))) {\n\t\treturn -ENOMEM;\n\t}\n\n\tinode_lock(i);\n\tname[0] = 0;\n\tif((size_read = get_rrip_symlink(i, name))) {\n\t\tsize_read = MIN(size_read, count);\n\t\tmemcpy_b(buffer, name, size_read);\n\t}\n\tkfree((unsigned int)name);\n\tinode_unlock(i);\n\treturn size_read;\n}\n\nint iso9660_followlink(struct inode *dir, struct inode *i, struct inode **i_res)\n{\n\tchar *name;\n\t__ino_t errno;\n\n\tif(!i) {\n\t\treturn -ENOENT;\n\t}\n\tif(!S_ISLNK(i->i_mode)) {\n\t\tprintk(\"%s(): Oops, inode '%d' is not a symlink (!?).\\n\", __FUNCTION__, i->inode);\n\t\treturn 0;\n\t}\n\n\tif(!(name = (char *)kmalloc(PAGE_SIZE))) {\n\t\treturn -ENOMEM;\n\t}\n\n\tname[0] = 0;\n\tif(get_rrip_symlink(i, name)) {\n\t\tiput(i);\n\t\tif((errno = parse_namei(name, dir, i_res, NULL, FOLLOW_LINKS))) {\n\t\t\tkfree((unsigned int)name);\n\t\t\treturn errno;\n\t\t}\n\t}\n\tkfree((unsigned int)name);\n\treturn 0;\n}\n"
  },
  {
    "path": "fs/locks.c",
    "content": "/*\n * fiwix/fs/locks.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/errno.h>\n#include <fiwix/types.h>\n#include <fiwix/locks.h>\n#include <fiwix/fs.h>\n#include <fiwix/mm.h>\n#include <fiwix/sleep.h>\n#include <fiwix/sched.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstruct flock_file *flock_file_table = NULL;\n\nstatic struct resource flock_resource = { 0, 0 };\n\nstatic struct flock_file *get_new_flock(struct inode *i)\n{\n\tstruct flock_file *ff;\n\n\tif(kstat.nr_flocks + 1 > NR_FLOCKS) {\n\t\tprintk(\"WARNING: tried to exceed NR_FLOCKS (%d).\\n\", NR_FLOCKS);\n\t\treturn NULL;\n\t}\n\n\tif(!(ff = (struct flock_file *)kmalloc(sizeof(struct flock_file)))) {\n\t\treturn NULL;\n\t}\n\tmemset_b(ff, 0, sizeof(struct flock_file));\n\n\tlock_resource(&flock_resource);\n\n\tff->inode = i;\t/* mark it as busy */\n\n\tif(!flock_file_table) {\n\t\tflock_file_table = ff;\n\t} else {\n\t\tff->prev = flock_file_table->prev;\n\t\tflock_file_table->prev->next = ff;\n\t}\n\tflock_file_table->prev = ff;\n\n\tunlock_resource(&flock_resource);\n\tkstat.nr_flocks++;\n\n\treturn ff;\n}\n\nstatic void release_flock(struct flock_file *ff)\n{\n\tunsigned int flags;\n\tstruct flock_file *tmp;\n\n\ttmp = ff;\n\n\tif(!ff->next && !ff->prev) {\n\t\tprintk(\"WARNING: %s(): trying to release an unexistent flock.\\n\", __FUNCTION__);\n\t\treturn;\n\t}\n\n\tSAVE_FLAGS(flags); CLI();\n\tif(ff->next) {\n\t\tff->next->prev = ff->prev;\n\t}\n\tif(ff->prev) {\n\t\tif(ff != flock_file_table) {\n\t\t\tff->prev->next = ff->next;\n\t\t}\n\t}\n\tif(!ff->next) {\n\t\tflock_file_table->prev = ff->prev;\n\t}\n\tif(ff == flock_file_table) {\n\t\tflock_file_table = ff->next;\n\t}\n\tRESTORE_FLAGS(flags);\n\n\tkfree((unsigned int)tmp);\n\tkstat.nr_flocks--;\n}\n\nstatic struct flock_file *get_flock_file(struct inode *i, struct proc *p)\n{\n\tstruct flock_file *ff;\n\n\tlock_resource(&flock_resource);\n\tff = flock_file_table;\n\n\twhile(ff) {\n\t\tif(ff->inode == i && p && p == ff->proc) {\n\t\t\tbreak;\n\t\t}\n\t\tff = ff->next;\n\t}\n\tunlock_resource(&flock_resource);\n\treturn ff;\n}\n\nint posix_lock(int ufd, int cmd, struct flock *fl)\n{\n\tstruct flock_file *ff;\n\tstruct inode *i;\n\tunsigned char type;\n\n\tlock_resource(&flock_resource);\n\tff = flock_file_table;\n\ti = fd_table[current->fd[ufd]].inode;\n\n\twhile(ff) {\n\t\tif(ff->inode == i) {\n\t\t\tbreak;;\n\t\t}\n\t\tff = ff->next;\n\t}\n\tunlock_resource(&flock_resource);\n\n\tif(cmd == F_GETLK) {\n\t\tif(ff && ff->inode == i) {\n\t\t\tfl->l_type = (ff->type & LOCK_SH) ? F_RDLCK : F_WRLCK;\n\t\t\tfl->l_whence = SEEK_SET;\n\t\t\tfl->l_start = 0;\n\t\t\tfl->l_len = 0;\n\t\t\tfl->l_pid = ff->proc->pid;\n\t\t} else {\n\t\t\tfl->l_type = F_UNLCK;\n\t\t}\n\t}\n\n\tswitch(fl->l_type) {\n\t\tcase F_RDLCK:\n\t\t\ttype = LOCK_SH;\n\t\t\tbreak;\n\t\tcase F_WRLCK:\n\t\t\ttype = LOCK_EX;\n\t\t\tbreak;\n\t\tcase F_UNLCK:\n\t\t\ttype = LOCK_UN;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\treturn -EINVAL;\n\t}\n\tif(cmd == F_SETLK) {\n\t\treturn flock_inode(i, type);\n\t}\n\tif(cmd == F_SETLKW) {\n\t\treturn flock_inode(i, type | LOCK_NB);\n\t}\n\treturn 0;\n}\n\nvoid flock_release_inode(struct inode *i)\n{\n\tstruct flock_file *ff;\n\n\tlock_resource(&flock_resource);\n\tff = flock_file_table;\n\n\twhile(ff) {\n\t\tif(ff->inode == i && ff->proc == current) {\n\t\t\twakeup(ff);\n\t\t\trelease_flock(ff);\n\t\t}\n\t\tff = ff->next;\n\t}\n\tunlock_resource(&flock_resource);\n}\n\nint flock_inode(struct inode *i, int op)\n{\n\tstruct flock_file *ff, *new;\n\n\tif(op & LOCK_UN) {\n\t\tif((ff = get_flock_file(i, current))) {\n\t\t\twakeup(ff);\n\t\t\trelease_flock(ff);\n\t\t}\n\t\treturn 0;\n\t}\n\nloop:\n\tlock_resource(&flock_resource);\n\tff = flock_file_table;\n\tnew = NULL;\n\twhile(ff) {\n\t\tif(ff->inode == i) {\n\t\t\tif(op & LOCK_SH) {\n\t\t\t\tif(ff->type & LOCK_EX) {\n\t\t\t\t\tif(ff->proc == current) {\n\t\t\t\t\t\tnew = ff;\n\t\t\t\t\t\twakeup(ff);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tunlock_resource(&flock_resource);\n\t\t\t\t\tif(op & LOCK_NB) {\n\t\t\t\t\t\treturn -EWOULDBLOCK;\n\t\t\t\t\t}\n\t\t\t\t\tif(sleep(ff, PROC_INTERRUPTIBLE)) {\n\t\t\t\t\t\treturn -EINTR;\n\t\t\t\t\t}\n\t\t\t\t\tgoto loop;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(op & LOCK_EX) {\n\t\t\t\tif(ff->proc == current) {\n\t\t\t\t\tnew = ff;\n\t\t\t\t\tff = ff->next;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tunlock_resource(&flock_resource);\n\t\t\t\tif(op & LOCK_NB) {\n\t\t\t\t\treturn -EWOULDBLOCK;\n\t\t\t\t}\n\t\t\t\tif(sleep(ff, PROC_INTERRUPTIBLE)) {\n\t\t\t\t\treturn -EINTR;\n\t\t\t\t}\n\t\t\t\tgoto loop;\n\t\t\t}\n\t\t}\n\t\tff = ff->next;\n\t}\n\tunlock_resource(&flock_resource);\n\n\tif(!new) {\n\t\tif(!(new = get_new_flock(i))) {\n\t\t\treturn -ENOLCK;\n\t\t}\n\t}\n\tnew->inode = i;\n\tnew->type = op;\n\tnew->proc = current;\n\n\treturn 0;\n}\n"
  },
  {
    "path": "fs/minix/Makefile",
    "content": "# fiwix/fs/minix/Makefile\n#\n# Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n# Distributed under the terms of the Fiwix License.\n#\n\n.c.o:\n\t$(CC) $(CFLAGS) -c -o $@ $<\n\nOBJS = super.o bitmaps.o inode.o namei.o symlink.o dir.o file.o v1_inode.o v2_inode.o\n\nall:\t$(OBJS)\n\nclean:\n\trm -f *.o\n\n"
  },
  {
    "path": "fs/minix/bitmaps.c",
    "content": "/*\n * fiwix/fs/minix/bitmaps.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_minix.h>\n#include <fiwix/buffer.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#ifdef CONFIG_FS_MINIX\n#define COUNT\t\t1\n#define FIRST_ZERO\t2\n\nstatic int count_bits(struct superblock *sb, __blk_t offset, int num, int blocks, int mode)\n{\n\tunsigned char c;\n\tint blksize;\n\tint n, n2, last, count, mapb;\n\tstruct buffer *buf;\n\n\tcount = mapb = 0;\n\tblksize = sb->s_blocksize;\n\n\twhile(offset < blocks) {\n\t\tif(!(buf = bread(sb->dev, offset, blksize))) {\n\t\t\treturn -EIO;\n\t\t}\n\t\tlast = (num / 8) > blksize ? blksize : (num / 8);\n\t\tfor(n = 0; n < last; n++) {\n\t\t\tc = (unsigned char)buf->data[n];\n\t\t\tfor(n2 = 0; n2 < 8; n2++) {\n\t\t\t\tif(c & (1 << n2)) {\n\t\t\t\t\tif(mode == COUNT) {\n\t\t\t\t\t\tcount++;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif(mode == FIRST_ZERO) {\n\t\t\t\t\t\tbrelse(buf);\n\t\t\t\t\t\treturn n2 + ((n * 8) + (mapb * blksize * 8));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\toffset++;\n\t\tmapb++;\n\t\tnum -= (blksize * 8);\n\t\tbrelse(buf);\n\t}\n\treturn count;\n}\n\nint minix_change_bit(int mode, struct superblock *sb, int map, int item)\n{\n\tint byte, bit, mask;\n\tstruct buffer *buf;\n\n\tmap += item / (sb->s_blocksize * 8);\n\tbyte = (item % (sb->s_blocksize * 8)) / 8;\n\tbit = (item % (sb->s_blocksize * 8)) % 8;\n\tmask = 1 << bit;\n\n\tif(!(buf = bread(sb->dev, map, sb->s_blocksize))) {\n\t\treturn -EIO;\n\t}\n\n\tif(mode == CLEAR_BIT) {\n\t\tif(!(buf->data[byte] & mask)) {\n\t\t\tbrelse(buf);\n\t\t\treturn 1;\n\t\t}\n\t\tbuf->data[byte] &= ~mask;\n\t}\n\tif(mode == SET_BIT) {\n\t\tif((buf->data[byte] & mask)) {\n\t\t\tbrelse(buf);\n\t\t\treturn 1;\n\t\t}\n\t\tbuf->data[byte] |= mask;\n\t}\n\n\tbwrite(buf);\n\treturn 0;\n}\n\nint minix_balloc(struct superblock *sb)\n{\n\tint map, block, errno;\n\n\tsuperblock_lock(sb);\n\n\tmap = 1 + SUPERBLOCK + sb->u.minix.sb.s_imap_blocks;\n\n\tif(!(block = minix_find_first_zero(sb, map, sb->u.minix.nzones, map + sb->u.minix.sb.s_zmap_blocks))) {\n\t\tsuperblock_unlock(sb);\n\t\treturn -ENOSPC;\n\t}\n\n\terrno = minix_change_bit(SET_BIT, sb, map, block);\n\tblock += sb->u.minix.sb.s_firstdatazone - 1;\n\n\tif(errno) {\n\t\tif(errno < 0) {\n\t\t\tprintk(\"WARNING: %s(): unable to set block %d.\\n\", __FUNCTION__, block);\n\t\t\tsuperblock_unlock(sb);\n\t\t\treturn errno;\n\t\t} else {\n\t\t\tprintk(\"WARNING: %s(): block %d is already marked as used!\\n\", __FUNCTION__, block);\n\t\t}\n\t}\n\n\tsuperblock_unlock(sb);\n\treturn block;\n}\n\nvoid minix_bfree(struct superblock *sb, int block)\n{\n\tint map, errno;\n\n\tif(block < sb->u.minix.sb.s_firstdatazone || block > sb->u.minix.nzones) {\n\t\tprintk(\"WARNING: %s(): block %d is not in datazone.\\n\", __FUNCTION__, block);\n\t\treturn;\n\t}\n\n\tsuperblock_lock(sb);\n\n\tmap = 1 + SUPERBLOCK + sb->u.minix.sb.s_imap_blocks;\n\tblock -= sb->u.minix.sb.s_firstdatazone - 1;\n\terrno = minix_change_bit(CLEAR_BIT, sb, map, block);\n\n\tif(errno) {\n\t\tif(errno < 0) {\n\t\t\tprintk(\"WARNING: %s(): unable to free block %d.\\n\", __FUNCTION__, block);\n\t\t} else {\n\t\t\tprintk(\"WARNING: %s(): block %d is already marked as free!\\n\", __FUNCTION__, block);\n\t\t}\n\t}\n\n\tsuperblock_unlock(sb);\n\treturn;\n}\n\nint minix_count_free_inodes(struct superblock *sb)\n{\n\t__blk_t offset;\n\n\toffset = 1 + SUPERBLOCK;\n\treturn count_bits(sb, offset, sb->u.minix.sb.s_ninodes, offset + sb->u.minix.sb.s_imap_blocks, COUNT);\n}\n\nint minix_count_free_blocks(struct superblock *sb)\n{\n\t__blk_t offset;\n\n\toffset = 1 + SUPERBLOCK + sb->u.minix.sb.s_imap_blocks;\n\treturn count_bits(sb, offset, sb->u.minix.nzones, offset + sb->u.minix.sb.s_zmap_blocks, COUNT);\n}\n\nint minix_find_first_zero(struct superblock *sb, __blk_t offset, int num, int blocks)\n{\n\treturn count_bits(sb, offset, num, blocks, FIRST_ZERO);\n}\n#endif /* CONFIG_FS_MINIX */\n"
  },
  {
    "path": "fs/minix/dir.c",
    "content": "/*\n * fiwix/fs/minix/dir.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/buffer.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/stat.h>\n#include <fiwix/dirent.h>\n#include <fiwix/mm.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#ifdef CONFIG_FS_MINIX\nstruct fs_operations minix_dir_fsop = {\n\t0,\n\t0,\n\n\tminix_dir_open,\n\tminix_dir_close,\n\tminix_dir_read,\n\tNULL,\t\t\t/* write */\n\tNULL,\t\t\t/* ioctl */\n\tNULL,\t\t\t/* llseek */\n\tminix_readdir,\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tminix_bmap,\n\tminix_lookup,\n\tminix_rmdir,\n\tminix_link,\n\tminix_unlink,\n\tminix_symlink,\n\tminix_mkdir,\n\tminix_mknod,\n\tNULL,\t\t\t/* truncate */\n\tminix_create,\n\tminix_rename,\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nint minix_dir_open(struct inode *i, struct fd *f)\n{\n\tf->offset = 0;\n\treturn 0;\n}\n\nint minix_dir_close(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\nint minix_dir_read(struct inode *i, struct fd *f, char *buffer, __size_t count)\n{\n\treturn -EISDIR;\n}\n\nint minix_readdir(struct inode *i, struct fd *f, struct dirent *dirent, __size_t count)\n{\n\t__blk_t block;\n\tunsigned int doffset, offset;\n\tunsigned int size, dirent_len;\n\tstruct minix_dir_entry *d;\n\tint base_dirent_len;\n\tint blksize;\n\tstruct buffer *buf;\n\n\tif(!(S_ISDIR(i->i_mode))) {\n\t\treturn -EBADF;\n\t}\n\n\tblksize = i->sb->s_blocksize;\n\tif(f->offset > i->i_size) {\n\t\tf->offset = i->i_size;\n\t}\n\n\tbase_dirent_len = sizeof(dirent->d_ino) + sizeof(dirent->d_off) + sizeof(dirent->d_reclen);\n\toffset = size = 0;\n\n\twhile(f->offset < i->i_size && count > 0) {\n\t\tif((block = bmap(i, f->offset, FOR_READING)) < 0) {\n\t\t\treturn block;\n\t\t}\n\t\tif(block) {\n\t\t\tif(!(buf = bread(i->dev, block, blksize))) {\n\t\t\t\treturn -EIO;\n\t\t\t}\n\n\t\t\tdoffset = f->offset;\n\t\t\toffset = f->offset & (blksize - 1);\t/* mod blksize */\n\t\t\twhile(offset < blksize) {\n\t\t\t\td = (struct minix_dir_entry *)(buf->data + offset);\n\t\t\t\tif(d->inode) {\n\t\t\t\t\tdirent_len = (base_dirent_len + (strlen(d->name) + 1)) + 3;\n\t\t\t\t\tdirent_len &= ~3;\t/* round up */\n\t\t\t\t\tdirent->d_ino = d->inode;\n\t\t\t\t\tif((size + dirent_len) < count) {\n\t\t\t\t\t\tdirent->d_off = doffset;\n\t\t\t\t\t\tdirent->d_reclen = dirent_len;\n\t\t\t\t\t\tmemcpy_b(dirent->d_name, d->name, strlen(d->name));\n\t\t\t\t\t\tdirent->d_name[strlen(d->name)] = 0;\n\t\t\t\t\t\tdirent = (struct dirent *)((char *)dirent + dirent_len);\n\t\t\t\t\t\tsize += dirent_len;\n\t\t\t\t\t\tcount -= dirent_len;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcount = 0;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tdoffset += i->sb->u.minix.dirsize;\n\t\t\t\toffset += i->sb->u.minix.dirsize;\n\t\t\t}\n\t\t\tbrelse(buf);\n\t\t}\n\t\tf->offset &= ~(blksize - 1);\n\t\tf->offset += offset;\n\t}\n\n\treturn size;\n}\n#endif /* CONFIG_FS_MINIX */\n"
  },
  {
    "path": "fs/minix/file.c",
    "content": "/*\n * fiwix/fs/minix/file.c\n *\n * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/buffer.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/mm.h>\n#include <fiwix/mman.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#ifdef CONFIG_FS_MINIX\nstruct fs_operations minix_file_fsop = {\n\t0,\n\t0,\n\n\tminix_file_open,\n\tminix_file_close,\n\tfile_read,\n\tminix_file_write,\n\tNULL,\t\t\t/* ioctl */\n\tminix_file_llseek,\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tminix_bmap,\n\tNULL,\t\t\t/* lookup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tminix_truncate,\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nint minix_file_open(struct inode *i, struct fd *f)\n{\n\tf->offset = 0;\n\tif(f->flags & O_TRUNC) {\n\t\ti->i_size = 0;\n\t\tminix_truncate(i, 0);\n\t}\n\treturn 0;\n}\n\nint minix_file_close(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\nint minix_file_write(struct inode *i, struct fd *f, const char *buffer, __size_t count)\n{\n\t__blk_t block;\n\t__size_t total_written;\n\tunsigned int boffset, bytes;\n\tint blksize;\n\tstruct buffer *buf;\n\n\tinode_lock(i);\n\n\tblksize = i->sb->s_blocksize;\n\ttotal_written = 0;\n\n\tif(f->flags & O_APPEND) {\n\t\tf->offset = i->i_size;\n\t}\n\n\twhile(total_written < count) {\n\t\tboffset = f->offset & (blksize - 1);\t/* mod blksize */\n\t\tif((block = bmap(i, f->offset, FOR_WRITING)) < 0) {\n\t\t\tinode_unlock(i);\n\t\t\treturn block;\n\t\t}\n\t\tbytes = blksize - boffset;\n\t\tbytes = MIN(bytes, (count - total_written));\n\t\tif(!(buf = bread(i->dev, block, blksize))) {\n\t\t\tinode_unlock(i);\n\t\t\treturn -EIO;\n\t\t}\n\t\tmemcpy_b(buf->data + boffset, buffer + total_written, bytes);\n\t\tupdate_page_cache(i, f->offset, buffer + total_written, bytes);\n\t\tbwrite(buf);\n\t\ttotal_written += bytes;\n\t\tf->offset += bytes;\n\t}\n\n\tif(f->offset > i->i_size) {\n\t\ti->i_size = f->offset;\n\t}\n\ti->i_ctime = CURRENT_TIME;\n\ti->i_mtime = CURRENT_TIME;\n\ti->state |= INODE_DIRTY;\n\t\n\tinode_unlock(i);\n\treturn total_written;\n}\n\n__loff_t minix_file_llseek(struct inode *i, __loff_t offset)\n{\n\treturn offset;\n}\n#endif /* CONFIG_FS_MINIX */\n"
  },
  {
    "path": "fs/minix/inode.c",
    "content": "/*\n * fiwix/fs/minix/inode.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_minix.h>\n#include <fiwix/fs_pipe.h>\n#include <fiwix/statfs.h>\n#include <fiwix/sleep.h>\n#include <fiwix/stat.h>\n#include <fiwix/sched.h>\n#include <fiwix/buffer.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#ifdef CONFIG_FS_MINIX\nint minix_read_inode(struct inode *i)\n{\n\tif(i->sb->u.minix.version == 1) {\n\t\treturn v1_minix_read_inode(i);\n\t}\n\n\treturn v2_minix_read_inode(i);\n}\n\nint minix_write_inode(struct inode *i)\n{\n\tif(i->sb->u.minix.version == 1) {\n\t\treturn v1_minix_write_inode(i);\n\t}\n\n\treturn v2_minix_write_inode(i);\n}\n\nint minix_ialloc(struct inode *i, int mode)\n{\n\tif(i->sb->u.minix.version == 1) {\n\t\treturn v1_minix_ialloc(i, mode);\n\t}\n\n\treturn v2_minix_ialloc(i, mode);\n}\n\nvoid minix_ifree(struct inode *i)\n{\n\tif(i->sb->u.minix.version == 1) {\n\t\treturn v1_minix_ifree(i);\n\t}\n\n\treturn v2_minix_ifree(i);\n}\n\nint minix_bmap(struct inode *i, __off_t offset, int mode)\n{\n\tif(i->sb->u.minix.version == 1) {\n\t\treturn v1_minix_bmap(i, offset, mode);\n\t}\n\n\treturn v2_minix_bmap(i, offset, mode);\n}\n\nint minix_truncate(struct inode *i, __off_t length)\n{\n\tif(i->sb->u.minix.version == 1) {\n\t\treturn v1_minix_truncate(i, length);\n\t}\n\n\treturn v2_minix_truncate(i, length);\n}\n#endif /* CONFIG_FS_MINIX */\n"
  },
  {
    "path": "fs/minix/namei.c",
    "content": "/*\n * fiwix/fs/minix/namei.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_minix.h>\n#include <fiwix/buffer.h>\n#include <fiwix/errno.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/stat.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#ifdef CONFIG_FS_MINIX\n/* finds a new entry to fit 'name' in the directory 'dir' */\nstatic struct buffer *find_first_free_dir_entry(struct inode *dir, struct minix_dir_entry **d_res, char *name)\n{\n\t__blk_t block;\n\tunsigned int blksize;\n\tunsigned int offset, doffset;\n\tstruct buffer *buf;\n\n\tblksize = dir->sb->s_blocksize;\n\toffset = 0;\n\n\twhile(offset < dir->i_size) {\n\t\tif((block = bmap(dir, offset, FOR_READING)) < 0) {\n\t\t\tbreak;\n\t\t}\n\t\tif(block) {\n\t\t\tif(!(buf = bread(dir->dev, block, blksize))) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdoffset = 0;\n\t\t\tdo {\n\t\t\t\t*d_res = (struct minix_dir_entry *)(buf->data + doffset);\n\t\t\t\t/* returns the first empty entry */\n\t\t\t\tif(!(*d_res)->inode || (doffset + offset >= dir->i_size)) {\n\t\t\t\t\t/* the directory grows by directory entry size */\n\t\t\t\t\tif(doffset + offset >= dir->i_size) {\n\t\t\t\t\t\tdir->i_size += dir->sb->u.minix.dirsize;\n\t\t\t\t\t}\n\t\t\t\t\treturn buf;\n\t\t\t\t}\n\t\t\t\tdoffset += dir->sb->u.minix.dirsize;\n\t\t\t} while(doffset < blksize);\n\t\t\tbrelse(buf);\n\t\t\toffset += blksize;\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t*d_res = NULL;\n\treturn NULL;\n}\n\n/* finds an entry in 'dir' based on the 'name' and/or on the inode 'i' */\nstatic struct buffer *find_dir_entry(struct inode *dir, struct inode *i, struct minix_dir_entry **d_res, char *name)\n{\n\t__blk_t block;\n\tunsigned int blksize;\n\tunsigned int offset, doffset;\n\tstruct buffer *buf;\n\n\tblksize = dir->sb->s_blocksize;\n\toffset = 0;\n\n\twhile(offset < dir->i_size) {\n\t\tif((block = bmap(dir, offset, FOR_READING)) < 0) {\n\t\t\tbreak;\n\t\t}\n\t\tif(block) {\n\t\t\tif(!(buf = bread(dir->dev, block, blksize))) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdoffset = 0;\n\t\t\tdo {\n\t\t\t\t*d_res = (struct minix_dir_entry *)(buf->data + doffset);\n\t\t\t\tif(!i) {\n\t\t\t\t\tif((*d_res)->inode) {\n\t\t\t\t\t\t/* returns the first matching name */\n\t\t\t\t\t\tif(!strcmp((*d_res)->name, name)) {\n\t\t\t\t\t\t\treturn buf;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif((*d_res)->inode == i->inode) {\n\t\t\t\t\t\t/* returns the first matching inode */\n\t\t\t\t\t\tif(!name) {\n\t\t\t\t\t\t\treturn buf;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t/* returns the matching inode and name */\n\t\t\t\t\t\tif(!strcmp((*d_res)->name, name)) {\n\t\t\t\t\t\t\treturn buf;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tdoffset += dir->sb->u.minix.dirsize;\n\t\t\t} while(doffset < blksize);\n\t\t\tbrelse(buf);\n\t\t\toffset += blksize;\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t*d_res = NULL;\n\treturn NULL;\n}\n\nstatic struct buffer *add_dir_entry(struct inode *dir, struct minix_dir_entry **d_res)\n{\n\t__blk_t block;\n\tstruct buffer *buf;\n\n\tif(!(buf = find_first_free_dir_entry(dir, d_res, NULL))) {\n\t\tif((block = bmap(dir, dir->i_size, FOR_WRITING)) < 0) {\n\t\t\treturn NULL;\n\t\t}\n\t\tif(!(buf = bread(dir->dev, block, dir->sb->s_blocksize))) {\n\t\t\treturn NULL;\n\t\t}\n\t\t*d_res = (struct minix_dir_entry *)buf->data;\n\t\tdir->i_size += dir->sb->u.minix.dirsize;\n\t}\n\n\treturn buf;\n}\n\nstatic int is_dir_empty(struct inode *dir)\n{\n\t__blk_t block;\n\tunsigned int blksize;\n\tunsigned int offset, doffset;\n\tstruct buffer *buf;\n\tstruct minix_dir_entry *d;\n\n\tblksize = dir->sb->s_blocksize;\n\tdoffset = dir->sb->u.minix.dirsize * 2;\t/* accept only \".\" and \"..\" */\n\toffset = 0;\n\n\twhile(offset < dir->i_size) {\n\t\tif((block = bmap(dir, offset, FOR_READING)) < 0) {\n\t\t\tbreak;\n\t\t}\n\t\tif(block) {\n\t\t\tif(!(buf = bread(dir->dev, block, blksize))) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdo {\n\t\t\t\tif(doffset + offset >= dir->i_size) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\td = (struct minix_dir_entry *)(buf->data + doffset);\n\t\t\t\tif(d->inode) {\n\t\t\t\t\tbrelse(buf);\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t\tdoffset += dir->sb->u.minix.dirsize;\n\t\t\t} while(doffset < blksize);\n\t\t\tbrelse(buf);\n\t\t\toffset += blksize;\n\t\t\tdoffset = 0;\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn 1;\n}\n\nstatic int is_subdir(struct inode *dir_new, struct inode *i_old)\n{\n\t__ino_t inode;\n\tint errno;\n\n\terrno = 0;\n\tdir_new->count++;\n\tfor(;;) {\n\t\tif(dir_new == i_old) {\n\t\t\terrno = 1;\n\t\t\tbreak;\n\t\t}\n\t\tinode = dir_new->inode;\n\t\tif(minix_lookup(\"..\", dir_new, &dir_new)) {\n\t\t\tbreak;\n\t\t}\n\t\tif(dir_new->inode == inode) {\n\t\t\tbreak;\n\t\t}\n\t}\n\tiput(dir_new);\n\treturn errno;\n}\n\nint minix_lookup(const char *name, struct inode *dir, struct inode **i_res)\n{\n\t__blk_t block;\n\tunsigned int blksize;\n\tunsigned int offset, doffset;\n\tstruct buffer *buf;\n\tstruct minix_dir_entry *d;\n\t__ino_t inode;\n\n\tblksize = dir->sb->s_blocksize;\n\tinode = offset = 0;\n\n\twhile(offset < dir->i_size && !inode) {\n\t\tif((block = bmap(dir, offset, FOR_READING)) < 0) {\n\t\t\tiput(dir);\n\t\t\treturn block;\n\t\t}\n\t\tif(block) {\n\t\t\tif(!(buf = bread(dir->dev, block, blksize))) {\n\t\t\t\tiput(dir);\n\t\t\t\treturn -EIO;\n\t\t\t}\n\t\t\tdoffset = 0;\n\t\t\tdo {\n\t\t\t\td = (struct minix_dir_entry *)(buf->data + doffset);\n\t\t\t\tif(d->inode) {\n\t\t\t\t\tif(strlen(d->name) == strlen(name)) {\n\t\t\t\t\t\tif(!(strcmp(d->name, name))) {\n\t\t\t\t\t\t\tinode = d->inode;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tdoffset += dir->sb->u.minix.dirsize;\n\t\t\t} while((doffset < blksize) && (!inode));\n\n\t\t\tbrelse(buf);\n\t\t\tif(inode) {\n\t\t\t\tif(!(*i_res = iget(dir->sb, inode))) {\n\t\t\t\t\tiput(dir);\n\t\t\t\t\treturn -EACCES;\n\t\t\t\t}\n\t\t\t\tiput(dir);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\toffset += blksize;\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t}\n\tiput(dir);\n\treturn -ENOENT;\n}\n\nint minix_rmdir(struct inode *dir, struct inode *i)\n{\n\tstruct buffer *buf;\n\tstruct minix_dir_entry *d;\n\n\tinode_lock(i);\n\n\tif(!is_dir_empty(i)) {\n\t\tinode_unlock(i);\n\t\treturn -ENOTEMPTY;\n\t}\n\n\tinode_lock(dir);\n\n\tif(!(buf = find_dir_entry(dir, i, &d, NULL))) {\n\t\tinode_unlock(i);\n\t\tinode_unlock(dir);\n\t\treturn -ENOENT;\n\t}\n\n\td->inode = 0;\n\ti->i_nlink = 0;\n\tdir->i_nlink--;\n\n\ti->i_ctime = CURRENT_TIME;\n\tdir->i_mtime = CURRENT_TIME;\n\tdir->i_ctime = CURRENT_TIME;\n\n\ti->state |= INODE_DIRTY;\n\tdir->state |= INODE_DIRTY;\n\n\tbwrite(buf);\n\n\tinode_unlock(i);\n\tinode_unlock(dir);\n\treturn 0;\n}\n\nint minix_link(struct inode *i_old, struct inode *dir_new, char *name)\n{\n\tstruct buffer *buf;\n\tstruct minix_dir_entry *d;\n\tint n;\n\n\tinode_lock(i_old);\n\tinode_lock(dir_new);\n\n\tif(!(buf = add_dir_entry(dir_new, &d))) {\n\t\tinode_unlock(i_old);\n\t\tinode_unlock(dir_new);\n\t\treturn -ENOSPC;\n\t}\n\n\td->inode = i_old->inode;\n\tfor(n = 0; n < i_old->sb->u.minix.namelen; n++) {\n\t\td->name[n] = name[n];\n\t\tif(!name[n]) {\n\t\t\tbreak;\n\t\t}\n\t}\n\tfor(; n < i_old->sb->u.minix.namelen; n++) {\n\t\td->name[n] = 0;\n\t}\n\n\ti_old->i_nlink++;\n\ti_old->i_ctime = CURRENT_TIME;\n\tdir_new->i_mtime = CURRENT_TIME;\n\tdir_new->i_ctime = CURRENT_TIME;\n\n\ti_old->state |= INODE_DIRTY;\n\tdir_new->state |= INODE_DIRTY;\n\n\tbwrite(buf);\n\n\tinode_unlock(i_old);\n\tinode_unlock(dir_new);\n\treturn 0;\n}\n\nint minix_unlink(struct inode *dir, struct inode *i, char *name)\n{\n\tstruct buffer *buf;\n\tstruct minix_dir_entry *d;\n\n\tinode_lock(dir);\n\tinode_lock(i);\n\n\tif(!(buf = find_dir_entry(dir, i, &d, name))) {\n\t\tinode_unlock(dir);\n\t\tinode_unlock(i);\n\t\treturn -ENOENT;\n\t}\n\n\td->inode = 0;\n\ti->i_nlink--;\n\n\ti->i_ctime = CURRENT_TIME;\n\tdir->i_mtime = CURRENT_TIME;\n\tdir->i_ctime = CURRENT_TIME;\n\n\ti->state |= INODE_DIRTY;\n\tdir->state |= INODE_DIRTY;\n\n\tbwrite(buf);\n\n\tinode_unlock(dir);\n\tinode_unlock(i);\n\treturn 0;\n}\n\nint minix_symlink(struct inode *dir, char *name, char *oldname)\n{\n\tstruct buffer *buf, *buf_new;\n\tstruct inode *i;\n\tstruct minix_dir_entry *d;\n\tunsigned int blksize;\n\tint n, block;\n\tchar c;\n\n\tinode_lock(dir);\n\n\t/* check again to know if this filename already exists */\n\tif((buf = find_dir_entry(dir, NULL, &d, name))) {\n\t\tbrelse(buf);\n\t\tinode_unlock(dir);\n\t\treturn -EEXIST;\n\t}\n\n\tif(!(i = ialloc(dir->sb, S_IFLNK))) {\n\t\tinode_unlock(dir);\n\t\treturn -ENOSPC;\n\t}\n\n\ti->i_mode = S_IFLNK | (S_IRWXU | S_IRWXG | S_IRWXO);\n\ti->i_uid = current->euid;\n\ti->i_gid = current->egid;\n\ti->i_nlink = 1;\n\ti->dev = dir->dev;\n\ti->count = 1;\n\ti->fsop = &minix_symlink_fsop;\n\ti->state |= INODE_DIRTY;\n\n\tblock = minix_balloc(dir->sb);\n\tif(block < 0) {\n\t\ti->i_nlink = 0;\n\t\tiput(i);\n\t\tinode_unlock(dir);\n\t\treturn -ENOSPC;\n\t}\n\n\tif(i->sb->u.minix.version == 1) {\n\t\ti->u.minix.u.i1_zone[0] = block;\n\t} else {\n\t\ti->u.minix.u.i2_zone[0] = block;\n\t}\n\tblksize = dir->sb->s_blocksize;\n\tif(!(buf_new = bread(dir->dev, block, blksize))) {\n\t\tminix_bfree(dir->sb, block);\n\t\ti->i_nlink = 0;\n\t\tiput(i);\n\t\tinode_unlock(dir);\n\t\treturn -EIO;\n\t}\n\n\tif(!(buf = add_dir_entry(dir, &d))) {\n\t\tminix_bfree(dir->sb, block);\n\t\ti->i_nlink = 0;\n\t\tiput(i);\n\t\tinode_unlock(dir);\n\t\treturn -ENOSPC;\n\t}\n\n\td->inode = i->inode;\n\tfor(n = 0; n < i->sb->u.minix.namelen; n++) {\n\t\td->name[n] = name[n];\n\t\tif(!name[n]) {\n\t\t\tbreak;\n\t\t}\n\t}\n\tfor(; n < i->sb->u.minix.namelen; n++) {\n\t\td->name[n] = 0;\n\t}\n\n\tfor(n = 0; n < NAME_MAX; n++) {\n\t\tif((c = oldname[n])) {\n\t\t\tbuf_new->data[n] = c;\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\tbuf_new->data[n] = 0;\n\ti->i_size = n;\n\n\tdir->i_mtime = CURRENT_TIME;\n\tdir->i_ctime = CURRENT_TIME;\n\tdir->state |= INODE_DIRTY;\n\n\tbwrite(buf);\n\tbwrite(buf_new);\n\tiput(i);\n\tinode_unlock(dir);\n\treturn 0;\n}\n\nint minix_mkdir(struct inode *dir, char *name, __mode_t mode)\n{\n\tstruct buffer *buf, *buf_new;\n\tstruct inode *i;\n\tstruct minix_dir_entry *d, *d_new;\n\tunsigned int blksize;\n\tint n, block;\n\n\tif(strlen(name) > dir->sb->u.minix.namelen) {\n\t\treturn -ENAMETOOLONG;\n\t}\n\n\tinode_lock(dir);\n\n\t/* check again to know if this filename already exists */\n\tif((buf = find_dir_entry(dir, NULL, &d, name))) {\n\t\tbrelse(buf);\n\t\tinode_unlock(dir);\n\t\treturn -EEXIST;\n\t}\n\n\tif(!(i = ialloc(dir->sb, S_IFDIR))) {\n\t\tinode_unlock(dir);\n\t\treturn -ENOSPC;\n\t}\n\n\ti->i_mode = ((mode & (S_IRWXU | S_IRWXG | S_IRWXO)) & ~current->umask);\n\ti->i_mode |= S_IFDIR;\n\ti->i_uid = current->euid;\n\ti->i_gid = current->egid;\n\ti->i_nlink = 1;\n\ti->dev = dir->dev;\n\ti->count = 1;\n\ti->fsop = &minix_dir_fsop;\n\ti->state |= INODE_DIRTY;\n\n\tif((block = bmap(i, 0, FOR_WRITING)) < 0) {\n\t\ti->i_nlink = 0;\n\t\tiput(i);\n\t\tinode_unlock(dir);\n\t\treturn -ENOSPC;\n\t}\n\n\tblksize = dir->sb->s_blocksize;\n\tif(!(buf_new = bread(i->dev, block, blksize))) {\n\t\tminix_bfree(dir->sb, block);\n\t\ti->i_nlink = 0;\n\t\tiput(i);\n\t\tinode_unlock(dir);\n\t\treturn -EIO;\n\t}\n\n\tif(!(buf = add_dir_entry(dir, &d))) {\n\t\tminix_bfree(dir->sb, block);\n\t\ti->i_nlink = 0;\n\t\tiput(i);\n\t\tinode_unlock(dir);\n\t\treturn -ENOSPC;\n\t}\n\n\td->inode = i->inode;\n\tfor(n = 0; n < i->sb->u.minix.namelen; n++) {\n\t\td->name[n] = name[n];\n\t\tif(!name[n] || name[n] == '/') {\n\t\t\tbreak;\n\t\t}\n\t}\n\tfor(; n < i->sb->u.minix.namelen; n++) {\n\t\td->name[n] = 0;\n\t}\n\n\td_new = (struct minix_dir_entry *)buf_new->data;\n\td_new->inode = i->inode;\n\td_new->name[0] = '.';\n\td_new->name[1] = 0;\n\ti->i_size += i->sb->u.minix.dirsize;\n\ti->i_nlink++;\n\td_new = (struct minix_dir_entry *)(buf_new->data + i->sb->u.minix.dirsize);\n\td_new->inode = dir->inode;\n\td_new->name[0] = '.';\n\td_new->name[1] = '.';\n\td_new->name[2] = 0;\n\ti->i_size += i->sb->u.minix.dirsize;\n\n\tdir->i_mtime = CURRENT_TIME;\n\tdir->i_ctime = CURRENT_TIME;\n\tdir->i_nlink++;\n\tdir->state |= INODE_DIRTY;\n\n\tbwrite(buf);\n\tbwrite(buf_new);\n\tiput(i);\n\tinode_unlock(dir);\n\treturn 0;\n}\n\nint minix_mknod(struct inode *dir, char *name, __mode_t mode, __dev_t dev)\n{\n\tstruct buffer *buf;\n\tstruct inode *i;\n\tstruct minix_dir_entry *d;\n\tint n;\n\n\tinode_lock(dir);\n\n\t/* check again to know if this filename already exists */\n\tif((buf = find_dir_entry(dir, NULL, &d, name))) {\n\t\tbrelse(buf);\n\t\tinode_unlock(dir);\n\t\treturn -EEXIST;\n\t}\n\n\tif(!(i = ialloc(dir->sb, mode & S_IFMT))) {\n\t\tinode_unlock(dir);\n\t\treturn -ENOSPC;\n\t}\n\n\tif(!(buf = add_dir_entry(dir, &d))) {\n\t\ti->i_nlink = 0;\n\t\tiput(i);\n\t\tinode_unlock(dir);\n\t\treturn -ENOSPC;\n\t}\n\n\td->inode = i->inode;\n\tfor(n = 0; n < i->sb->u.minix.namelen; n++) {\n\t\td->name[n] = name[n];\n\t\tif(!name[n]) {\n\t\t\tbreak;\n\t\t}\n\t}\n\tfor(; n < i->sb->u.minix.namelen; n++) {\n\t\td->name[n] = 0;\n\t}\n\n\ti->i_mode = (mode & ~current->umask) & ~S_IFMT;\n\ti->i_uid = current->euid;\n\ti->i_gid = current->egid;\n\ti->i_nlink = 1;\n\ti->dev = dir->dev;\n\ti->count = 1;\n\ti->state |= INODE_DIRTY;\n\n\tswitch(mode & S_IFMT) {\n\t\tcase S_IFCHR:\n\t\t\ti->fsop = &def_chr_fsop;\n\t\t\ti->rdev = dev;\n\t\t\ti->i_mode |= S_IFCHR;\n\t\t\tbreak;\n\t\tcase S_IFBLK:\n\t\t\ti->fsop = &def_blk_fsop;\n\t\t\ti->rdev = dev;\n\t\t\ti->i_mode |= S_IFBLK;\n\t\t\tbreak;\n\t\tcase S_IFIFO:\n\t\t\ti->fsop = &pipefs_fsop;\n\t\t\ti->i_mode |= S_IFIFO;\n\t\t\t/* it's a union so we need to clear pipefs_i */\n\t\t\tmemset_b(&i->u.pipefs, 0, sizeof(struct pipefs_inode));\n\t\t\tbreak;\n#ifdef CONFIG_NET\n\t\tcase S_IFSOCK:\n\t\t\ti->fsop = &sockfs_fsop;\n\t\t\ti->i_mode |= S_IFSOCK;\n\t\t\t/* it's a union so we need to clear sockfs_inode */\n\t\t\tmemset_b(&i->u.sockfs, 0, sizeof(struct sockfs_inode));\n\t\t\tbreak;\n#endif /* CONFIG_NET */\n\t}\n\n\tdir->i_mtime = CURRENT_TIME;\n\tdir->i_ctime = CURRENT_TIME;\n\tdir->state |= INODE_DIRTY;\n\n\tbwrite(buf);\n\tiput(i);\n\tinode_unlock(dir);\n\treturn 0;\n}\n\nint minix_create(struct inode *dir, char *name, int flags, __mode_t mode, struct inode **i_res)\n{\n\tstruct buffer *buf;\n\tstruct inode *i;\n\tstruct minix_dir_entry *d;\n\tint n;\n\n\tif(IS_RDONLY_FS(dir)) {\n\t\treturn -EROFS;\n\t}\n\n\tinode_lock(dir);\n\n\tif(flags & O_CREAT) {\n\t\t/* check again to know if this filename already exists */\n\t\tif((buf = find_dir_entry(dir, NULL, &d, name))) {\n\t\t\tbrelse(buf);\n\t\t\tinode_unlock(dir);\n\t\t\treturn -EEXIST;\n\t\t}\n\t}\n\n\tif(!(i = ialloc(dir->sb, S_IFREG))) {\n\t\tinode_unlock(dir);\n\t\treturn -ENOSPC;\n\t}\n\n\tif(!(buf = add_dir_entry(dir, &d))) {\n\t\ti->i_nlink = 0;\n\t\tiput(i);\n\t\tinode_unlock(dir);\n\t\treturn -ENOSPC;\n\t}\n\n\td->inode = i->inode;\n\tfor(n = 0; n < i->sb->u.minix.namelen; n++) {\n\t\td->name[n] = name[n];\n\t\tif(!name[n]) {\n\t\t\tbreak;\n\t\t}\n\t}\n\tfor(; n < i->sb->u.minix.namelen; n++) {\n\t\td->name[n] = 0;\n\t}\n\n\ti->i_mode = (mode & ~current->umask) & ~S_IFMT;\n\ti->i_mode |= S_IFREG;\n\ti->i_uid = current->euid;\n\ti->i_gid = current->egid;\n\ti->i_nlink = 1;\n\ti->dev = dir->dev;\n\ti->fsop = &minix_file_fsop;\n\ti->count = 1;\n\ti->state |= INODE_DIRTY;\n\n\tdir->i_mtime = CURRENT_TIME;\n\tdir->i_ctime = CURRENT_TIME;\n\tdir->state |= INODE_DIRTY;\n\n\t*i_res = i;\n\tbwrite(buf);\n\tinode_unlock(dir);\n\treturn 0;\n}\n\nint minix_rename(struct inode *i_old, struct inode *dir_old, struct inode *i_new, struct inode *dir_new, char *oldpath, char *newpath)\n{\n\tstruct buffer *buf_old, *buf_new;\n\tstruct minix_dir_entry *d_old, *d_new;\n\tint errno;\n\n\terrno = 0;\n\n\tif(is_subdir(dir_new, i_old)) {\n\t\treturn -EINVAL;\n\t}\n\n\tinode_lock(i_old);\n\tinode_lock(dir_old);\n\tif(dir_old != dir_new) {\n\t\tinode_lock(dir_new);\n\t}\n\n\tif(!(buf_old = find_dir_entry(dir_old, i_old, &d_old, oldpath))) {\n\t\terrno = -ENOENT;\n\t\tgoto end;\n\t}\n\tif(dir_old == dir_new) {\n\t\t/* free that buffer now to not block buf_new */\n\t\tbrelse(buf_old);\n\t\tbuf_old = NULL;\n\t}\n\n\tif(i_new) {\n\t\tif(S_ISDIR(i_old->i_mode)) {\n\t\t\tif(!is_dir_empty(i_new)) {\n\t\t\t\tif(buf_old) {\n\t\t\t\t\tbrelse(buf_old);\n\t\t\t\t}\n\t\t\t\terrno = -ENOTEMPTY;\n\t\t\t\tgoto end;\n\t\t\t}\n\t\t}\n\t\tif(!(buf_new = find_dir_entry(dir_new, i_new, &d_new, newpath))) {\n\t\t\tif(buf_old) {\n\t\t\t\tbrelse(buf_old);\n\t\t\t}\n\t\t\terrno = -ENOENT;\n\t\t\tgoto end;\n\t\t}\n\t} else {\n\t\tif(!(buf_new = add_dir_entry(dir_new, &d_new))) {\n\t\t\tif(buf_old) {\n\t\t\t\tbrelse(buf_old);\n\t\t\t}\n\t\t\terrno = -ENOSPC;\n\t\t\tgoto end;\n\t\t}\n\t\tif(S_ISDIR(i_old->i_mode)) {\n\t\t\tdir_old->i_nlink--;\n\t\t\tdir_new->i_nlink++;\n\t\t}\n\t}\n\tif(i_new) {\n\t\ti_new->i_nlink--;\n\t} else {\n\t\ti_new = i_old;\n\t\tstrcpy(d_new->name, newpath);\n\t}\n\n\td_new->inode = i_old->inode;\n\tdir_new->i_mtime = CURRENT_TIME;\n\tdir_new->i_ctime = CURRENT_TIME;\n\ti_new->state |= INODE_DIRTY;\n\tdir_new->state |= INODE_DIRTY;\n\n\tdir_old->i_mtime = CURRENT_TIME;\n\tdir_old->i_ctime = CURRENT_TIME;\n\ti_old->state |= INODE_DIRTY;\n\tdir_old->state |= INODE_DIRTY;\n\tbwrite(buf_new);\n\n\tif(!buf_old) {\n\t\tif(!(buf_old = find_dir_entry(dir_old, i_old, &d_old, oldpath))) {\n\t\t\terrno = -ENOENT;\n\t\t\tgoto end;\n\t\t}\n\t}\n\td_old->inode = 0;\n\tbwrite(buf_old);\n\n\t/* update the parent directory */\n\tif(S_ISDIR(i_old->i_mode)) {\n\t\tbuf_new = find_dir_entry(i_old, dir_old, &d_new, \"..\");\n\t\tif(buf_new) {\n\t\t\td_new->inode = dir_new->inode;\n\t\t\tbwrite(buf_new);\n\t\t}\n\t}\n\nend:\n\tinode_unlock(i_old);\n\tinode_unlock(dir_old);\n\tinode_unlock(dir_new);\n\treturn errno;\n}\n#endif /* CONFIG_FS_MINIX */\n"
  },
  {
    "path": "fs/minix/super.c",
    "content": "/*\n * fiwix/fs/minix/super.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_minix.h>\n#include <fiwix/buffer.h>\n#include <fiwix/sched.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#ifdef CONFIG_FS_MINIX\nstruct fs_operations minix_fsop = {\n\tFSOP_REQUIRES_DEV,\n\t0,\n\n\tNULL,\t\t\t/* open */\n\tNULL,\t\t\t/* close */\n\tNULL,\t\t\t/* read */\n\tNULL,\t\t\t/* write */\n\tNULL,\t\t\t/* ioctl */\n\tNULL,\t\t\t/* llseek */\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lookup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tminix_read_inode,\n\tminix_write_inode,\n\tminix_ialloc,\n\tminix_ifree,\n\tminix_statfs,\n\tminix_read_superblock,\n\tminix_remount_fs,\n\tminix_write_superblock,\n\tminix_release_superblock\n};\n\nstatic void check_superblock(struct minix_super_block *sb)\n{\n\tif(!(sb->s_state & MINIX_VALID_FS)) {\n\t\tprintk(\"WARNING: filesystem not checked, fsck recommended.\\n\");\n\t}\n\tif(sb->s_state & MINIX_ERROR_FS) {\n\t\tprintk(\"WARNING: filesystem contains errors, fsck recommended.\\n\");\n\t}\n}\n\nvoid minix_statfs(struct superblock *sb, struct statfs *statfsbuf)\n{\n\tstatfsbuf->f_type = sb->u.minix.sb.s_magic;\n\tstatfsbuf->f_bsize = sb->s_blocksize;\n\tstatfsbuf->f_blocks = sb->u.minix.nzones << sb->u.minix.sb.s_log_zone_size;\n\tstatfsbuf->f_bfree = sb->u.minix.nzones - minix_count_free_blocks(sb);\n\tstatfsbuf->f_bavail = statfsbuf->f_bfree;\n\n\tstatfsbuf->f_files = sb->u.minix.sb.s_ninodes;\n\tstatfsbuf->f_ffree = sb->u.minix.sb.s_ninodes - minix_count_free_inodes(sb);\n\t/* statfsbuf->f_fsid = ? */\n\tstatfsbuf->f_namelen = sb->u.minix.namelen;\n}\n\nint minix_read_superblock(__dev_t dev, struct superblock *sb)\n{\n\tstruct buffer *buf;\n\tint maps;\n\n\tsuperblock_lock(sb);\n\tif(!(buf = bread(dev, SUPERBLOCK, BLKSIZE_1K))) {\n\t\tprintk(\"WARNING: %s(): I/O error on device %d,%d.\\n\", __FUNCTION__, MAJOR(dev), MINOR(dev));\n\t\tsuperblock_unlock(sb);\n\t\treturn -EIO;\n\t}\n\tmemcpy_b(&sb->u.minix.sb, buf->data, sizeof(struct minix_super_block));\n\n\tswitch(sb->u.minix.sb.s_magic) {\n\t\tcase MINIX_SUPER_MAGIC:\n\t\t\tsb->u.minix.namelen = 14;\n\t\t\tsb->u.minix.dirsize = sizeof(__u16) + sb->u.minix.namelen;\n\t\t\tsb->u.minix.version = 1;\n\t\t\tsb->u.minix.nzones = sb->u.minix.sb.s_nzones;\n\t\t\tprintk(\"minix v1 (14 char names) filesystem detected on device %d,%d.\\n\", MAJOR(dev), MINOR(dev));\n\t\t\tbreak;\n\t\tcase MINIX_SUPER_MAGIC2:\n\t\t\tsb->u.minix.namelen = 30;\n\t\t\tsb->u.minix.dirsize = sizeof(__u16) + sb->u.minix.namelen;\n\t\t\tsb->u.minix.version = 1;\n\t\t\tsb->u.minix.nzones = sb->u.minix.sb.s_nzones;\n\t\t\tprintk(\"minix v1 (30 char names) filesystem detected on device %d,%d.\\n\", MAJOR(dev), MINOR(dev));\n\t\t\tbreak;\n\t\tcase MINIX2_SUPER_MAGIC:\n\t\t\tsb->u.minix.namelen = 14;\n\t\t\tsb->u.minix.dirsize = sizeof(__u16) + sb->u.minix.namelen;\n\t\t\tsb->u.minix.version = 2;\n\t\t\tsb->u.minix.nzones = sb->u.minix.sb.s_zones;\n\t\t\tprintk(\"minix v2 (14 char names) filesystem detected on device %d,%d.\\n\", MAJOR(dev), MINOR(dev));\n\t\t\tbreak;\n\t\tcase MINIX2_SUPER_MAGIC2:\n\t\t\tsb->u.minix.namelen = 30;\n\t\t\tsb->u.minix.dirsize = sizeof(__u16) + sb->u.minix.namelen;\n\t\t\tsb->u.minix.version = 2;\n\t\t\tsb->u.minix.nzones = sb->u.minix.sb.s_zones;\n\t\t\tprintk(\"minix v2 (30 char names) filesystem detected on device %d,%d.\\n\", MAJOR(dev), MINOR(dev));\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tprintk(\"ERROR: %s(): invalid filesystem type or bad superblock on device %d,%d.\\n\", __FUNCTION__, MAJOR(dev), MINOR(dev));\n\t\t\tsuperblock_unlock(sb);\n\t\t\tbrelse(buf);\n\t\t\treturn -EINVAL;\n\t}\n\n\tsb->dev = dev;\n\tsb->fsop = &minix_fsop;\n\tsb->s_blocksize = BLKSIZE_1K << sb->u.minix.sb.s_log_zone_size;\n\n\tif(sb->s_blocksize != BLKSIZE_1K) {\n\t\tprintk(\"ERROR: %s(): block sizes > %d not supported in this filesystem.\\n\", __FUNCTION__, BLKSIZE_1K);\n\t\tsuperblock_unlock(sb);\n\t\tbrelse(buf);\n\t\treturn -EINVAL;\n\t}\n\n\t/*\n\tprintk(\"s_ninodes       = %d\\n\", sb->u.minix.sb.s_ninodes);\n\tprintk(\"s_nzones        = %d (nzones = %d)\\n\", sb->u.minix.sb.s_nzones, sb->u.minix.nzones);\n\tprintk(\"s_imap_blocks   = %d\\n\", sb->u.minix.sb.s_imap_blocks);\n\tprintk(\"s_zmap_blocks   = %d\\n\", sb->u.minix.sb.s_zmap_blocks);\n\tprintk(\"s_firstdatazone = %d\\n\", sb->u.minix.sb.s_firstdatazone);\n\tprintk(\"s_log_zone_size = %d\\n\", sb->u.minix.sb.s_log_zone_size);\n\tprintk(\"s_max_size      = %d\\n\", sb->u.minix.sb.s_max_size);\n\tprintk(\"s_magic         = %x\\n\", sb->u.minix.sb.s_magic);\n\tprintk(\"s_state         = %d\\n\", sb->u.minix.sb.s_state);\n\tprintk(\"s_zones         = %d\\n\", sb->u.minix.sb.s_zones);\n\t*/\n\n\t/* Minix fs size is limited to: # of bitmaps * 8192 * 1024 */\n\tif(sb->u.minix.version == 1) {\n\t\tmaps = V1_MAX_BITMAP_BLOCKS;\t/* 64MB limit */\n\t}\n\tif(sb->u.minix.version == 2) {\n\t\tmaps = V2_MAX_BITMAP_BLOCKS;\t/* 1GB limit */\n\t}\n\n\tif(sb->u.minix.sb.s_imap_blocks > maps) {\n\t\tprintk(\"ERROR: %s(): number of imap blocks (%d) is greater than %d!\\n\", __FUNCTION__, sb->u.minix.sb.s_imap_blocks, maps);\n\t\tsuperblock_unlock(sb);\n\t\tbrelse(buf);\n\t\treturn -EINVAL;\n\t}\n\tif(sb->u.minix.sb.s_zmap_blocks > maps) {\n\t\tprintk(\"ERROR: %s(): number of zmap blocks (%d) is greater than %d!\\n\", __FUNCTION__, sb->u.minix.sb.s_zmap_blocks, maps);\n\t\tsuperblock_unlock(sb);\n\t\tbrelse(buf);\n\t\treturn -EINVAL;\n\t}\n\n\tsuperblock_unlock(sb);\n\n\tif(!(sb->root = iget(sb, MINIX_ROOT_INO))) {\n\t\tprintk(\"ERROR: %s(): unable to get root inode.\\n\", __FUNCTION__);\n\t\tbrelse(buf);\n\t\treturn -EINVAL;\n\t}\n\n\tcheck_superblock(&sb->u.minix.sb);\n\n\tif(!(sb->flags & MS_RDONLY)) {\n\t\tsb->u.minix.sb.s_state &= ~MINIX_VALID_FS;\n\t\tmemcpy_b(buf->data, &sb->u.minix.sb, sizeof(struct minix_super_block));\n\t\tbwrite(buf);\n\t} else {\n\t\tbrelse(buf);\n\t}\n\n\treturn 0;\n}\n\nint minix_remount_fs(struct superblock *sb, int flags)\n{\n\tstruct buffer *buf;\n\tstruct minix_super_block *minixsb;\n\n\tif((flags & MS_RDONLY) == (sb->flags & MS_RDONLY)) {\n\t\treturn 0;\n\t}\n\n\tsuperblock_lock(sb);\n\tif(!(buf = bread(sb->dev, SUPERBLOCK, BLKSIZE_1K))) {\n\t\tsuperblock_unlock(sb);\n\t\treturn -EIO;\n\t}\n\tminixsb = (struct minix_super_block *)buf->data;\n\n\tif(flags & MS_RDONLY) {\n\t\t/* switching from RW to RO */\n\t\tsb->u.minix.sb.s_state |= MINIX_VALID_FS;\n\t\tminixsb->s_state |= MINIX_VALID_FS;\n\t} else {\n\t\t/* switching from RO to RW */\n\t\tcheck_superblock(minixsb);\n\t\tmemcpy_b(&sb->u.minix.sb, minixsb, sizeof(struct minix_super_block));\n\t\tsb->u.minix.sb.s_state &= ~MINIX_VALID_FS;\n\t\tminixsb->s_state &= ~MINIX_VALID_FS;\n\t}\n\n\tsb->state = SUPERBLOCK_DIRTY;\n\tsuperblock_unlock(sb);\n\tbwrite(buf);\n\treturn 0;\n}\n\nint minix_write_superblock(struct superblock *sb)\n{\n\tstruct buffer *buf;\n\n\tsuperblock_lock(sb);\n\tif(!(buf = bread(sb->dev, SUPERBLOCK, BLKSIZE_1K))) {\n\t\tsuperblock_unlock(sb);\n\t\treturn -EIO;\n\t}\n\n\tmemcpy_b(buf->data, &sb->u.minix.sb, sizeof(struct minix_super_block));\n\tsb->state &= ~SUPERBLOCK_DIRTY;\n\tsuperblock_unlock(sb);\n\tbwrite(buf);\n\treturn 0;\n}\n\nvoid minix_release_superblock(struct superblock *sb)\n{\n\tif(sb->flags & MS_RDONLY) {\n\t\treturn;\n\t}\n\n\tsuperblock_lock(sb);\n\n\tsb->u.minix.sb.s_state |= MINIX_VALID_FS;\n\tsb->state = SUPERBLOCK_DIRTY;\n\n\tsuperblock_unlock(sb);\n}\n\nint minix_init(void)\n{\n\treturn register_filesystem(\"minix\", &minix_fsop);\n}\n#endif /* CONFIG_FS_MINIX */\n"
  },
  {
    "path": "fs/minix/symlink.c",
    "content": "/*\n * fiwix/fs/minix/symlink.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/buffer.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/stat.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#ifdef CONFIG_FS_MINIX\nstruct fs_operations minix_symlink_fsop = {\n\t0,\n\t0,\n\n\tNULL,\t\t\t/* open */\n\tNULL,\t\t\t/* close */\n\tNULL,\t\t\t/* read */\n\tNULL,\t\t\t/* write */\n\tNULL,\t\t\t/* ioctl */\n\tNULL,\t\t\t/* llseek */\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tminix_readlink,\n\tminix_followlink,\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lookup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nint minix_readlink(struct inode *i, char *buffer, __size_t count)\n{\n\t__u32 blksize;\n\tstruct buffer *buf;\n\n\tif(!S_ISLNK(i->i_mode)) {\n\t\tprintk(\"%s(): Oops, inode '%d' is not a symlink (!?).\\n\", __FUNCTION__, i->inode);\n\t\treturn 0;\n\t}\n\n\tinode_lock(i);\n\tblksize = i->sb->s_blocksize;\n\tcount = MIN(count, i->i_size);\n\tif(!count) {\n\t\tinode_unlock(i);\n\t\treturn 0;\n\t}\n\tcount = MIN(count, blksize);\n\tif(i->sb->u.minix.version == 1) {\n\t\tif(!(buf = bread(i->dev, i->u.minix.u.i1_zone[0], blksize))) {\n\t\t\tinode_unlock(i);\n\t\t\treturn -EIO;\n\t\t}\n\t} else {\n\t\tif(!(buf = bread(i->dev, i->u.minix.u.i2_zone[0], blksize))) {\n\t\t\tinode_unlock(i);\n\t\t\treturn -EIO;\n\t\t}\n\t}\n\tmemcpy_b(buffer, buf->data, count);\n\tbrelse(buf);\n\tbuffer[count] = 0;\n\tinode_unlock(i);\n\treturn count;\n}\n\nint minix_followlink(struct inode *dir, struct inode *i, struct inode **i_res)\n{\n\tstruct buffer *buf;\n\tchar *name;\n\t__ino_t errno;\n\n\tif(!i) {\n\t\treturn -ENOENT;\n\t}\n\n\tif(!S_ISLNK(i->i_mode)) {\n\t\tprintk(\"%s(): Oops, inode '%d' is not a symlink (!?).\\n\", __FUNCTION__, i->inode);\n\t\treturn 0;\n\t}\n\n\tif(current->loopcnt > MAX_SYMLINKS) {\n\t\tiput(i);\n\t\tprintk(\"%s(): too many nested symbolic links!\\n\", __FUNCTION__);\n\t\treturn -ELOOP;\n\t}\n\n\tinode_lock(i);\n\tif(i->sb->u.minix.version == 1) {\n\t\tif(!(buf = bread(i->dev, i->u.minix.u.i1_zone[0], i->sb->s_blocksize))) {\n\t\t\tinode_unlock(i);\n\t\t\treturn -EIO;\n\t\t}\n\t} else {\n\t\tif(!(buf = bread(i->dev, i->u.minix.u.i2_zone[0], i->sb->s_blocksize))) {\n\t\t\tinode_unlock(i);\n\t\t\treturn -EIO;\n\t\t}\n\t}\n\tname = buf->data;\n\tinode_unlock(i);\n\n\tcurrent->loopcnt++;\n\tiput(i);\n\tbrelse(buf);\n\terrno = parse_namei(name, dir, i_res, NULL, FOLLOW_LINKS);\n\tcurrent->loopcnt--;\n\treturn errno;\n}\n#endif /* CONFIG_FS_MINIX */\n"
  },
  {
    "path": "fs/minix/v1_inode.c",
    "content": "/*\n * fiwix/fs/minix/v1_inode.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_minix.h>\n#include <fiwix/fs_pipe.h>\n#include <fiwix/statfs.h>\n#include <fiwix/sleep.h>\n#include <fiwix/stat.h>\n#include <fiwix/sched.h>\n#include <fiwix/buffer.h>\n#include <fiwix/mm.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#ifdef CONFIG_FS_MINIX\n#define BLOCKS_PER_IND_BLOCK(sb)\t(sb->s_blocksize / sizeof(__u16))\n#define BLOCKS_PER_DIND_BLOCK(sb)\t(BLOCKS_PER_IND_BLOCK(sb) * BLOCKS_PER_IND_BLOCK(sb))\n\n#define MINIX_INODES_PER_BLOCK(sb)\t(sb->s_blocksize / sizeof(struct minix_inode))\n\n#define MINIX_NDIR_BLOCKS\t\t7\n#define MINIX_IND_BLOCK\t\t\tMINIX_NDIR_BLOCKS\n#define MINIX_DIND_BLOCK\t\t(MINIX_NDIR_BLOCKS + 1)\n\nstatic int free_zone(struct inode *i, int block, int offset)\n{\n\tint n;\n\tstruct buffer *buf;\n\t__u16 *zone;\n\n\tif(!(buf = bread(i->dev, block, i->sb->s_blocksize))) {\n\t\tprintk(\"WARNING: %s(): error reading block %d.\\n\", __FUNCTION__, block);\n\t\treturn -EIO;\n\t}\n\tzone = (__u16 *)buf->data;\n\tfor(n = offset; n < BLOCKS_PER_IND_BLOCK(i->sb); n++) {\n\t\tif(zone[n]) {\n\t\t\tminix_bfree(i->sb, zone[n]);\n\t\t\tzone[n] = 0;\n\t\t}\n\t}\n\tbwrite(buf);\n\treturn 0;\n}\n\nstatic int free_indblock(struct inode *i, int block, int offset)\n{\n\tint n, retval;\n\tstruct buffer *buf;\n\t__u16 *zone;\n\t__blk_t dblock;\n\n\tif(!(buf = bread(i->dev, block, i->sb->s_blocksize))) {\n\t\tprintk(\"%s(): error reading doubly indirect block %d.\\n\", __FUNCTION__, block);\n\t\treturn -EIO;\n\t}\n\tzone = (__u16 *)buf->data;\n\tdblock = offset % BLOCKS_PER_IND_BLOCK(i->sb);\n\tfor(n = offset / BLOCKS_PER_IND_BLOCK(i->sb); n < BLOCKS_PER_IND_BLOCK(i->sb); n++) {\n\t\tif(zone[n]) {\n\t\t\tif((retval = free_zone(i, zone[n], dblock)) < 0) {\n\t\t\t\tbrelse(buf);\n\t\t\t\treturn retval;\n\t\t\t}\n\t\t\tif(!dblock) {\n\t\t\t\tminix_bfree(i->sb, zone[n]);\n\t\t\t\tzone[n] = 0;\n\t\t\t}\n\t\t}\n\t\tdblock = 0;\n\t}\n\tbwrite(buf);\n\treturn 0;\n}\n\nint v1_minix_read_inode(struct inode *i)\n{\n\t__ino_t block;\n\tshort int offset;\n\tstruct minix_inode *ii;\n\tstruct buffer *buf;\n\tint errno;\n\n\tblock = 1 + SUPERBLOCK + i->sb->u.minix.sb.s_imap_blocks + i->sb->u.minix.sb.s_zmap_blocks + (i->inode - 1) / MINIX_INODES_PER_BLOCK(i->sb);\n\n\tif(!(buf = bread(i->dev, block, i->sb->s_blocksize))) {\n\t\treturn -EIO;\n\t}\n\toffset = (i->inode - 1) % MINIX_INODES_PER_BLOCK(i->sb);\n\tii = ((struct minix_inode *)buf->data) + offset;\n\n\ti->i_mode = ii->i_mode;\n\ti->i_uid = ii->i_uid;\n\ti->i_size = ii->i_size;\n\ti->i_atime = ii->i_time;\n\ti->i_ctime = ii->i_time;\n\ti->i_mtime = ii->i_time;\n\ti->i_gid = ii->i_gid;\n\ti->i_nlink = ii->i_nlinks;\n\tmemcpy_b(i->u.minix.u.i1_zone, ii->i_zone, sizeof(ii->i_zone));\n\ti->count = 1;\n\n\terrno = 0;\n\tswitch(i->i_mode & S_IFMT) {\n\t\tcase S_IFCHR:\n\t\t\ti->fsop = &def_chr_fsop;\n\t\t\ti->rdev = ii->i_zone[0];\n\t\t\tbreak;\n\t\tcase S_IFBLK:\n\t\t\ti->fsop = &def_blk_fsop;\n\t\t\ti->rdev = ii->i_zone[0];\n\t\t\tbreak;\n\t\tcase S_IFIFO:\n\t\t\ti->fsop = &pipefs_fsop;\n\t\t\t/* it's a union so we need to clear pipefs_i */\n\t\t\tmemset_b(&i->u.pipefs, 0, sizeof(struct pipefs_inode));\n\t\t\tbreak;\n\t\tcase S_IFDIR:\n\t\t\ti->fsop = &minix_dir_fsop;\n\t\t\tbreak;\n\t\tcase S_IFREG:\n\t\t\ti->fsop = &minix_file_fsop;\n\t\t\tbreak;\n\t\tcase S_IFLNK:\n\t\t\ti->fsop = &minix_symlink_fsop;\n\t\t\tbreak;\n\t\tcase S_IFSOCK:\n#ifdef CONFIG_NET\n\t\t\ti->fsop = &sockfs_fsop;\n\t\t\t/* it's a union so we need to clear sockfs_inode */\n\t\t\tmemset_b(&i->u.sockfs, 0, sizeof(struct sockfs_inode));\n#else\n\t\t\ti->fsop = NULL;\n#endif /* CONFIG_NET */\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tprintk(\"WARNING: %s(): invalid inode (%d) mode %o.\\n\", __FUNCTION__, i->inode, i->i_mode);\n\t\t\terrno = -ENOENT;\n\t\t\tbreak;\n\t}\n\n\tbrelse(buf);\n\treturn errno;\n}\n\nint v1_minix_write_inode(struct inode *i)\n{\n\t__ino_t block;\n\tshort int offset;\n\tstruct minix_inode *ii;\n\tstruct buffer *buf;\n\n\tblock = 1 + SUPERBLOCK + i->sb->u.minix.sb.s_imap_blocks + i->sb->u.minix.sb.s_zmap_blocks + (i->inode - 1) / MINIX_INODES_PER_BLOCK(i->sb);\n\n\tif(!(buf = bread(i->dev, block, i->sb->s_blocksize))) {\n\t\treturn -EIO;\n\t}\n\toffset = (i->inode - 1) % MINIX_INODES_PER_BLOCK(i->sb);\n\tii = ((struct minix_inode *)buf->data) + offset;\n\n\tii->i_mode = i->i_mode;\n\tii->i_uid = i->i_uid;\n\tii->i_size = i->i_size;\n\tii->i_time = i->i_mtime;\n\tii->i_gid = i->i_gid;\n\tii->i_nlinks = i->i_nlink;\n\tif(S_ISCHR(i->i_mode) || S_ISBLK(i->i_mode)) {\n\t\tii->i_zone[0] = i->rdev;\n\t} else {\n\t\tmemcpy_b(ii->i_zone, i->u.minix.u.i1_zone, sizeof(i->u.minix.u.i1_zone));\n\t}\n\ti->state &= ~INODE_DIRTY;\n\tbwrite(buf);\n\treturn 0;\n}\n\nint v1_minix_ialloc(struct inode *i, int mode)\n{\n\t__blk_t offset;\n\tint inode, errno;\n\tstruct superblock *sb;\n\n\tsb = i->sb;\n\tsuperblock_lock(sb);\n\n\toffset = 1 + SUPERBLOCK;\n\n\tif(!(inode = minix_find_first_zero(sb, offset, sb->u.minix.sb.s_ninodes, offset + sb->u.minix.sb.s_imap_blocks))) {\n\t\tsuperblock_unlock(sb);\n\t\treturn -ENOSPC;\n\t}\n\n\terrno = minix_change_bit(SET_BIT, sb, offset, inode);\n\n\tif(errno) {\n\t\tif(errno < 0) {\n\t\t\tprintk(\"WARNING: %s(): unable to set inode %d.\\n\", __FUNCTION__, inode);\n\t\t\tsuperblock_unlock(sb);\n\t\t\treturn errno;\n\t\t} else {\n\t\t\tprintk(\"WARNING: %s(): inode %d is already marked as used!\\n\", __FUNCTION__, inode);\n\t\t}\n\t}\n\n\ti->inode = inode;\n\ti->i_atime = CURRENT_TIME;\n\ti->i_mtime = CURRENT_TIME;\n\ti->i_ctime = CURRENT_TIME;\n\tsuperblock_unlock(sb);\n\treturn 0;\n}\n\nvoid v1_minix_ifree(struct inode *i)\n{\n\tint errno;\n\tstruct superblock *sb;\n\n\tinvalidate_inode_pages(i);\n\tminix_truncate(i, 0);\n\n\tsb = i->sb;\n\tsuperblock_lock(sb);\n\n\terrno = minix_change_bit(CLEAR_BIT, i->sb, 1 + SUPERBLOCK, i->inode);\n\n\tif(errno) {\n\t\tif(errno < 0) {\n\t\t\tprintk(\"WARNING: %s(): unable to clear inode %d.\\n\", __FUNCTION__, i->inode);\n\t\t} else {\n\t\t\tprintk(\"WARNING: %s(): inode %d is already marked as free!\\n\", __FUNCTION__, i->inode);\n\t\t}\n\t}\n\n\ti->i_size = 0;\n\ti->i_mtime = CURRENT_TIME;\n\ti->i_ctime = CURRENT_TIME;\n\ti->state |= INODE_DIRTY;\n\tsuperblock_unlock(sb);\n}\n\nint v1_minix_bmap(struct inode *i, __off_t offset, int mode)\n{\n\tunsigned char level;\n\t__u16 *indblock, *dindblock;\n\t__blk_t block, iblock, dblock, newblock;\n\tint blksize;\n\tstruct buffer *buf, *buf2, *buf3;\n\n\tblksize = i->sb->s_blocksize;\n\tblock = offset / blksize;\n\tlevel = 0;\n\n\tif(block < MINIX_NDIR_BLOCKS) {\n\t\tlevel = MINIX_NDIR_BLOCKS - 1;\n\t} else {\n\t\tif(block < (BLOCKS_PER_IND_BLOCK(i->sb) + MINIX_NDIR_BLOCKS)) {\n\t\t\tlevel = MINIX_IND_BLOCK;\n\t\t} else {\n\t\t\tlevel = MINIX_DIND_BLOCK;\n\t\t}\n\t\tblock -= MINIX_NDIR_BLOCKS;\n\t}\n\n\tif(level < MINIX_NDIR_BLOCKS) {\n\t\tif(!i->u.minix.u.i1_zone[block] && mode == FOR_WRITING) {\n\t\t\tif((newblock = minix_balloc(i->sb)) < 0) {\n\t\t\t\treturn -ENOSPC;\n\t\t\t}\n\t\t\t/* initialize the new block */\n\t\t\tif(!(buf = bread(i->dev, newblock, blksize))) {\n\t\t\t\tminix_bfree(i->sb, newblock);\n\t\t\t\treturn -EIO;\n\t\t\t}\n\t\t\tmemset_b(buf->data, 0, blksize);\n\t\t\tbwrite(buf);\n\t\t\ti->u.minix.u.i1_zone[block] = newblock;\n\t\t}\n\t\treturn i->u.minix.u.i1_zone[block];\n\t}\n\n\tif(!i->u.minix.u.i1_zone[level]) {\n\t\tif(mode == FOR_WRITING) {\n\t\t\tif((newblock = minix_balloc(i->sb)) < 0) {\n\t\t\t\treturn -ENOSPC;\n\t\t\t}\n\t\t\t/* initialize the new block */\n\t\t\tif(!(buf = bread(i->dev, newblock, blksize))) {\n\t\t\t\tminix_bfree(i->sb, newblock);\n\t\t\t\treturn -EIO;\n\t\t\t}\n\t\t\tmemset_b(buf->data, 0, blksize);\n\t\t\tbwrite(buf);\n\t\t\ti->u.minix.u.i1_zone[level] = newblock;\n\t\t} else {\n\t\t\treturn 0;\n\t\t}\n\t}\n\tif(!(buf = bread(i->dev, i->u.minix.u.i1_zone[level], blksize))) {\n\t\treturn -EIO;\n\t}\n\tindblock = (__u16 *)buf->data;\n\tdblock = block - BLOCKS_PER_IND_BLOCK(i->sb);\n\n\tif(level == MINIX_DIND_BLOCK) {\n\t\tblock = dblock / BLOCKS_PER_IND_BLOCK(i->sb);\n\t}\n\n\tif(!indblock[block]) {\n\t\tif(mode == FOR_WRITING) {\n\t\t\tif((newblock = minix_balloc(i->sb)) < 0) {\n\t\t\t\tbrelse(buf);\n\t\t\t\treturn -ENOSPC;\n\t\t\t}\n\t\t\t/* initialize the new block */\n\t\t\tif(!(buf2 = bread(i->dev, newblock, blksize))) {\n\t\t\t\tminix_bfree(i->sb, newblock);\n\t\t\t\tbrelse(buf);\n\t\t\t\treturn -EIO;\n\t\t\t}\n\t\t\tmemset_b(buf2->data, 0, blksize);\n\t\t\tbwrite(buf2);\n\t\t\tindblock[block] = newblock;\n\t\t\tif(level == MINIX_IND_BLOCK) {\n\t\t\t\tbwrite(buf);\n\t\t\t\treturn newblock;\n\t\t\t}\n\t\t\tbuf->flags |= (BUFFER_DIRTY | BUFFER_VALID);\n\t\t} else {\n\t\t\tbrelse(buf);\n\t\t\treturn 0;\n\t\t}\n\t}\n\tif(level == MINIX_IND_BLOCK) {\n\t\tnewblock = indblock[block];\n\t\tbrelse(buf);\n\t\treturn newblock;\n\t}\n\n\tiblock = block;\n\tif(!(buf2 = bread(i->dev, indblock[iblock], blksize))) {\n\t\tprintk(\"%s(): returning -EIO\\n\", __FUNCTION__);\n\t\tbrelse(buf);\n\t\treturn -EIO;\n\t}\n\tdindblock = (__u16 *)buf2->data;\n\tblock = dindblock[dblock - (iblock * BLOCKS_PER_IND_BLOCK(i->sb))];\n\tif(!block && mode == FOR_WRITING) {\n\t\tif((newblock = minix_balloc(i->sb)) < 0) {\n\t\t\tbrelse(buf);\n\t\t\tbrelse(buf2);\n\t\t\treturn -ENOSPC;\n\t\t}\n\t\t/* initialize the new block */\n\t\tif(!(buf3 = bread(i->dev, newblock, blksize))) {\n\t\t\tminix_bfree(i->sb, newblock);\n\t\t\tbrelse(buf);\n\t\t\tbrelse(buf2);\n\t\t\treturn -EIO;\n\t\t}\n\t\tmemset_b(buf3->data, 0, blksize);\n\t\tbwrite(buf3);\n\t\tdindblock[dblock - (iblock * BLOCKS_PER_IND_BLOCK(i->sb))] = newblock;\n\t\tbuf2->flags |= (BUFFER_DIRTY | BUFFER_VALID);\n\t\tblock = newblock;\n\t}\n\tbrelse(buf);\n\tbrelse(buf2);\n\treturn block;\n}\n\nint v1_minix_truncate(struct inode *i, __off_t length)\n{\n\t__blk_t block;\n\tint n, retval;\n\n\tblock = length / i->sb->s_blocksize;\n\n\tif(!S_ISDIR(i->i_mode) && !S_ISREG(i->i_mode) && !S_ISLNK(i->i_mode)) {\n\t\treturn -EINVAL;\n\t}\n\n\tif(block < MINIX_NDIR_BLOCKS) {\n\t\tfor(n = block; n < MINIX_NDIR_BLOCKS; n++) {\n\t\t\tif(i->u.minix.u.i1_zone[n]) {\n\t\t\t\tminix_bfree(i->sb, i->u.minix.u.i1_zone[n]);\n\t\t\t\ti->u.minix.u.i1_zone[n] = 0;\n\t\t\t}\n\t\t}\n\t\tblock = 0;\n\t}\n\n\tif(!block || block < (BLOCKS_PER_IND_BLOCK(i->sb) + MINIX_NDIR_BLOCKS)) {\n\t\tif(block) {\n\t\t\tblock -= MINIX_NDIR_BLOCKS;\n\t\t}\n\t\tif(i->u.minix.u.i1_zone[MINIX_IND_BLOCK]) {\n\t\t\tif((retval = free_zone(i, i->u.minix.u.i1_zone[MINIX_IND_BLOCK], block)) < 0) {\n\t\t\t\treturn retval;\n\t\t\t}\n\t\t\tif(!block) {\n\t\t\t\tminix_bfree(i->sb, i->u.minix.u.i1_zone[MINIX_IND_BLOCK]);\n\t\t\t\ti->u.minix.u.i1_zone[MINIX_IND_BLOCK] = 0;\n\t\t\t}\n\t\t}\n\t\tblock = 0;\n\t}\n\n\tif(!block || block < (BLOCKS_PER_DIND_BLOCK(i->sb) + BLOCKS_PER_IND_BLOCK(i->sb) + MINIX_NDIR_BLOCKS)) {\n\t\tif(block) {\n\t\t\tblock -= MINIX_NDIR_BLOCKS;\n\t\t\tblock -= BLOCKS_PER_IND_BLOCK(i->sb);\n\t\t}\n\t\tif(i->u.minix.u.i1_zone[MINIX_DIND_BLOCK]) {\n\t\t\tif((retval = free_indblock(i, i->u.minix.u.i1_zone[MINIX_DIND_BLOCK], block)) < 0) {\n\t\t\t\treturn retval;\n\t\t\t}\n\t\t\tif(!block) {\n\t\t\t\tminix_bfree(i->sb, i->u.minix.u.i1_zone[MINIX_DIND_BLOCK]);\n\t\t\t\ti->u.minix.u.i1_zone[MINIX_DIND_BLOCK] = 0;\n\t\t\t}\n\t\t}\n\t\tblock = 0;\n\t}\n\n\ti->i_mtime = CURRENT_TIME;\n\ti->i_ctime = CURRENT_TIME;\n\ti->i_size = length;\n\ti->state |= INODE_DIRTY;\n\n\treturn 0;\n}\n#endif /* CONFIG_FS_MINIX */\n"
  },
  {
    "path": "fs/minix/v2_inode.c",
    "content": "/*\n * fiwix/fs/minix/v2_inode.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_minix.h>\n#include <fiwix/fs_pipe.h>\n#include <fiwix/statfs.h>\n#include <fiwix/sleep.h>\n#include <fiwix/stat.h>\n#include <fiwix/sched.h>\n#include <fiwix/buffer.h>\n#include <fiwix/mm.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#ifdef CONFIG_FS_MINIX\n#define BLOCKS_PER_IND_BLOCK(sb)\t(sb->s_blocksize / sizeof(__u32))\n#define BLOCKS_PER_DIND_BLOCK(sb)\t(BLOCKS_PER_IND_BLOCK(sb) * BLOCKS_PER_IND_BLOCK(sb))\n#define BLOCKS_PER_TIND_BLOCK(sb)\t(BLOCKS_PER_IND_BLOCK(sb) * BLOCKS_PER_IND_BLOCK(sb) * BLOCKS_PER_IND_BLOCK(sb))\n\n#define MINIX2_INODES_PER_BLOCK(sb)\t(sb->s_blocksize / sizeof(struct minix2_inode))\n\n#define MINIX_NDIR_BLOCKS\t\t7\n#define MINIX_IND_BLOCK\t\t\tMINIX_NDIR_BLOCKS\n#define MINIX_DIND_BLOCK\t\t(MINIX_NDIR_BLOCKS + 1)\n#define MINIX_TIND_BLOCK\t\t(MINIX_NDIR_BLOCKS + 2)\n\nstatic int free_zone(struct inode *i, int block, int offset)\n{\n\tint n;\n\tstruct buffer *buf;\n\t__u32 *zone;\n\n\tif(!(buf = bread(i->dev, block, i->sb->s_blocksize))) {\n\t\tprintk(\"WARNING: %s(): error reading block %d.\\n\", __FUNCTION__, block);\n\t\treturn -EIO;\n\t}\n\tzone = (__u32 *)buf->data;\n\tfor(n = offset; n < BLOCKS_PER_IND_BLOCK(i->sb); n++) {\n\t\tif(zone[n]) {\n\t\t\tminix_bfree(i->sb, zone[n]);\n\t\t\tzone[n] = 0;\n\t\t}\n\t}\n\tbwrite(buf);\n\treturn 0;\n}\n\nstatic int free_indblock(struct inode *i, int block, int offset)\n{\n\tint n, retval;\n\tstruct buffer *buf;\n\t__u32 *zone;\n\t__blk_t dblock;\n\n\tif(!(buf = bread(i->dev, block, i->sb->s_blocksize))) {\n\t\tprintk(\"%s(): error reading doubly indirect block %d.\\n\", __FUNCTION__, block);\n\t\treturn -EIO;\n\t}\n\tzone = (__u32 *)buf->data;\n\tdblock = offset % BLOCKS_PER_IND_BLOCK(i->sb);\n\tfor(n = offset / BLOCKS_PER_IND_BLOCK(i->sb); n < BLOCKS_PER_IND_BLOCK(i->sb); n++) {\n\t\tif(zone[n]) {\n\t\t\tif((retval = free_zone(i, zone[n], dblock)) < 0) {\n\t\t\t\tbrelse(buf);\n\t\t\t\treturn retval;\n\t\t\t}\n\t\t\tif(!dblock) {\n\t\t\t\tminix_bfree(i->sb, zone[n]);\n\t\t\t\tzone[n] = 0;\n\t\t\t}\n\t\t}\n\t\tdblock = 0;\n\t}\n\tbwrite(buf);\n\treturn 0;\n}\n\nint v2_minix_read_inode(struct inode *i)\n{\n\t__ino_t block;\n\tshort int offset;\n\tstruct minix2_inode *ii;\n\tstruct buffer *buf;\n\tint errno;\n\n\tblock = 1 + SUPERBLOCK + i->sb->u.minix.sb.s_imap_blocks + i->sb->u.minix.sb.s_zmap_blocks + (i->inode - 1) / MINIX2_INODES_PER_BLOCK(i->sb);\n\n\tif(!(buf = bread(i->dev, block, i->sb->s_blocksize))) {\n\t\treturn -EIO;\n\t}\n\toffset = (i->inode - 1) % MINIX2_INODES_PER_BLOCK(i->sb);\n\tii = ((struct minix2_inode *)buf->data) + offset;\n\n\ti->i_mode = ii->i_mode;\n\ti->i_nlink = ii->i_nlink;\n\ti->i_uid = ii->i_uid;\n\ti->i_gid = ii->i_gid;\n\ti->i_size = ii->i_size;\n\ti->i_atime = ii->i_atime;\n\ti->i_mtime = ii->i_mtime;\n\ti->i_ctime = ii->i_ctime;\n\tmemcpy_b(i->u.minix.u.i2_zone, ii->i_zone, sizeof(ii->i_zone));\n\ti->count = 1;\n\n\terrno = 0;\n\tswitch(i->i_mode & S_IFMT) {\n\t\tcase S_IFCHR:\n\t\t\ti->fsop = &def_chr_fsop;\n\t\t\ti->rdev = ii->i_zone[0];\n\t\t\tbreak;\n\t\tcase S_IFBLK:\n\t\t\ti->fsop = &def_blk_fsop;\n\t\t\ti->rdev = ii->i_zone[0];\n\t\t\tbreak;\n\t\tcase S_IFIFO:\n\t\t\ti->fsop = &pipefs_fsop;\n\t\t\t/* it's a union so we need to clear pipefs_i */\n\t\t\tmemset_b(&i->u.pipefs, 0, sizeof(struct pipefs_inode));\n\t\t\tbreak;\n\t\tcase S_IFDIR:\n\t\t\ti->fsop = &minix_dir_fsop;\n\t\t\tbreak;\n\t\tcase S_IFREG:\n\t\t\ti->fsop = &minix_file_fsop;\n\t\t\tbreak;\n\t\tcase S_IFLNK:\n\t\t\ti->fsop = &minix_symlink_fsop;\n\t\t\tbreak;\n\t\tcase S_IFSOCK:\n#ifdef CONFIG_NET\n\t\t\ti->fsop = &sockfs_fsop;\n\t\t\t/* it's a union so we need to clear sockfs_inode */\n\t\t\tmemset_b(&i->u.sockfs, 0, sizeof(struct sockfs_inode));\n#else\n\t\t\ti->fsop = NULL;\n#endif /* CONFIG_NET */\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tprintk(\"WARNING: %s(): invalid inode (%d) mode %o.\\n\", __FUNCTION__, i->inode, i->i_mode);\n\t\t\terrno = -ENOENT;\n\t\t\tbreak;\n\t}\n\n\tbrelse(buf);\n\treturn errno;\n}\n\nint v2_minix_write_inode(struct inode *i)\n{\n\t__ino_t block;\n\tshort int offset;\n\tstruct minix2_inode *ii;\n\tstruct buffer *buf;\n\n\tblock = 1 + SUPERBLOCK + i->sb->u.minix.sb.s_imap_blocks + i->sb->u.minix.sb.s_zmap_blocks + (i->inode - 1) / MINIX2_INODES_PER_BLOCK(i->sb);\n\n\tif(!(buf = bread(i->dev, block, i->sb->s_blocksize))) {\n\t\treturn -EIO;\n\t}\n\toffset = (i->inode - 1) % MINIX2_INODES_PER_BLOCK(i->sb);\n\tii = ((struct minix2_inode *)buf->data) + offset;\n\n\tii->i_mode = i->i_mode;\n\tii->i_nlink = i->i_nlink;\n\tii->i_uid = i->i_uid;\n\tii->i_gid = i->i_gid;\n\tii->i_size = i->i_size;\n\tii->i_atime = i->i_atime;\n\tii->i_mtime = i->i_mtime;\n\tii->i_ctime = i->i_ctime;\n\tif(S_ISCHR(i->i_mode) || S_ISBLK(i->i_mode)) {\n\t\tii->i_zone[0] = i->rdev;\n\t} else {\n\t\tmemcpy_b(ii->i_zone, i->u.minix.u.i2_zone, sizeof(i->u.minix.u.i2_zone));\n\t}\n\ti->state &= ~INODE_DIRTY;\n\tbwrite(buf);\n\treturn 0;\n}\n\nint v2_minix_ialloc(struct inode *i, int mode)\n{\n\t__blk_t offset;\n\tint inode, errno;\n\tstruct superblock *sb;\n\n\tsb = i->sb;\n\tsuperblock_lock(sb);\n\n\toffset = 1 + SUPERBLOCK;\n\n\tif(!(inode = minix_find_first_zero(sb, offset, sb->u.minix.sb.s_ninodes, offset + sb->u.minix.sb.s_imap_blocks))) {\n\t\tsuperblock_unlock(sb);\n\t\treturn -ENOSPC;\n\t}\n\n\terrno = minix_change_bit(SET_BIT, sb, offset, inode);\n\n\tif(errno) {\n\t\tif(errno < 0) {\n\t\t\tprintk(\"WARNING: %s(): unable to set inode %d.\\n\", __FUNCTION__, inode);\n\t\t\tsuperblock_unlock(sb);\n\t\t\treturn errno;\n\t\t} else {\n\t\t\tprintk(\"WARNING: %s(): inode %d is already marked as used!\\n\", __FUNCTION__, inode);\n\t\t}\n\t}\n\n\ti->inode = inode;\n\ti->i_atime = CURRENT_TIME;\n\ti->i_mtime = CURRENT_TIME;\n\ti->i_ctime = CURRENT_TIME;\n\tsuperblock_unlock(sb);\n\treturn 0;\n}\n\nvoid v2_minix_ifree(struct inode *i)\n{\n\tint errno;\n\tstruct superblock *sb;\n\n\tinvalidate_inode_pages(i);\n\tminix_truncate(i, 0);\n\n\tsb = i->sb;\n\tsuperblock_lock(sb);\n\n\terrno = minix_change_bit(CLEAR_BIT, i->sb, 1 + SUPERBLOCK, i->inode);\n\n\tif(errno) {\n\t\tif(errno < 0) {\n\t\t\tprintk(\"WARNING: %s(): unable to clear inode %d.\\n\", __FUNCTION__, i->inode);\n\t\t} else {\n\t\t\tprintk(\"WARNING: %s(): inode %d is already marked as free!\\n\", __FUNCTION__, i->inode);\n\t\t}\n\t}\n\n\ti->i_size = 0;\n\ti->i_mtime = CURRENT_TIME;\n\ti->i_ctime = CURRENT_TIME;\n\ti->state |= INODE_DIRTY;\n\tsuperblock_unlock(sb);\n}\n\nint v2_minix_bmap(struct inode *i, __off_t offset, int mode)\n{\n\tunsigned char level;\n\t__u32 *indblock, *dindblock, *tindblock;\n\t__blk_t block, iblock, dblock, tblock, newblock;\n\tint blksize;\n\tstruct buffer *buf, *buf2, *buf3, *buf4;\n\n\tblksize = i->sb->s_blocksize;\n\tblock = offset / blksize;\n\tlevel = 0;\n\tbuf3 = NULL;\t/* makes GCC happy */\n\n\tif(block < MINIX_NDIR_BLOCKS) {\n\t\tlevel = MINIX_NDIR_BLOCKS - 1;\n\t} else {\n\t\tif(block < (BLOCKS_PER_IND_BLOCK(i->sb) + MINIX_NDIR_BLOCKS)) {\n\t\t\tlevel = MINIX_IND_BLOCK;\n\t\t} else if(block < ((BLOCKS_PER_IND_BLOCK(i->sb) * BLOCKS_PER_IND_BLOCK(i->sb)) + BLOCKS_PER_IND_BLOCK(i->sb) + MINIX_NDIR_BLOCKS)) {\n\t\t\tlevel = MINIX_DIND_BLOCK;\n\t\t} else {\n\t\t\tlevel = MINIX_TIND_BLOCK;\n\t\t}\n\t\tblock -= MINIX_NDIR_BLOCKS;\n\t}\n\n\tif(level < MINIX_NDIR_BLOCKS) {\n\t\tif(!i->u.minix.u.i2_zone[block] && mode == FOR_WRITING) {\n\t\t\tif((newblock = minix_balloc(i->sb)) < 0) {\n\t\t\t\treturn -ENOSPC;\n\t\t\t}\n\t\t\t/* initialize the new block */\n\t\t\tif(!(buf = bread(i->dev, newblock, blksize))) {\n\t\t\t\tminix_bfree(i->sb, newblock);\n\t\t\t\treturn -EIO;\n\t\t\t}\n\t\t\tmemset_b(buf->data, 0, blksize);\n\t\t\tbwrite(buf);\n\t\t\ti->u.minix.u.i2_zone[block] = newblock;\n\t\t}\n\t\treturn i->u.minix.u.i2_zone[block];\n\t}\n\n\tif(!i->u.minix.u.i2_zone[level]) {\n\t\tif(mode == FOR_WRITING) {\n\t\t\tif((newblock = minix_balloc(i->sb)) < 0) {\n\t\t\t\treturn -ENOSPC;\n\t\t\t}\n\t\t\t/* initialize the new block */\n\t\t\tif(!(buf = bread(i->dev, newblock, blksize))) {\n\t\t\t\tminix_bfree(i->sb, newblock);\n\t\t\t\treturn -EIO;\n\t\t\t}\n\t\t\tmemset_b(buf->data, 0, blksize);\n\t\t\tbwrite(buf);\n\t\t\ti->u.minix.u.i2_zone[level] = newblock;\n\t\t} else {\n\t\t\treturn 0;\n\t\t}\n\t}\n\tif(!(buf = bread(i->dev, i->u.minix.u.i2_zone[level], blksize))) {\n\t\treturn -EIO;\n\t}\n\tindblock = (__u32 *)buf->data;\n\tdblock = block - BLOCKS_PER_IND_BLOCK(i->sb);\n\ttblock = block - (BLOCKS_PER_IND_BLOCK(i->sb) * BLOCKS_PER_IND_BLOCK(i->sb)) - BLOCKS_PER_IND_BLOCK(i->sb);\n\n\tif(level == MINIX_DIND_BLOCK) {\n\t\tblock = dblock / BLOCKS_PER_IND_BLOCK(i->sb);\n\t}\n\tif(level == MINIX_TIND_BLOCK) {\n\t\tblock = tblock / (BLOCKS_PER_IND_BLOCK(i->sb) * BLOCKS_PER_IND_BLOCK(i->sb));\n\t}\n\n\tif(!indblock[block]) {\n\t\tif(mode == FOR_WRITING) {\n\t\t\tif((newblock = minix_balloc(i->sb)) < 0) {\n\t\t\t\tbrelse(buf);\n\t\t\t\treturn -ENOSPC;\n\t\t\t}\n\t\t\t/* initialize the new block */\n\t\t\tif(!(buf2 = bread(i->dev, newblock, blksize))) {\n\t\t\t\tminix_bfree(i->sb, newblock);\n\t\t\t\tbrelse(buf);\n\t\t\t\treturn -EIO;\n\t\t\t}\n\t\t\tmemset_b(buf2->data, 0, blksize);\n\t\t\tbwrite(buf2);\n\t\t\tindblock[block] = newblock;\n\t\t\tif(level == MINIX_IND_BLOCK) {\n\t\t\t\tbwrite(buf);\n\t\t\t\treturn newblock;\n\t\t\t}\n\t\t\tbuf->flags |= (BUFFER_DIRTY | BUFFER_VALID);\n\t\t} else {\n\t\t\tbrelse(buf);\n\t\t\treturn 0;\n\t\t}\n\t}\n\tif(level == MINIX_IND_BLOCK) {\n\t\tnewblock = indblock[block];\n\t\tbrelse(buf);\n\t\treturn newblock;\n\t}\n\n\tif(level == MINIX_TIND_BLOCK) {\n\t\tif(!(buf3 = bread(i->dev, indblock[block], blksize))) {\n\t\t\tprintk(\"%s(): returning -EIO\\n\", __FUNCTION__);\n\t\t\tbrelse(buf);\n\t\t\treturn -EIO;\n\t\t}\n\t\ttindblock = (__u32 *)buf3->data;\n\t\ttblock -= BLOCKS_PER_DIND_BLOCK(i->sb) * block;\n\t\tblock = tindblock[tblock / BLOCKS_PER_IND_BLOCK(i->sb)];\n\t\tif(!block) {\n\t\t\tif(mode == FOR_WRITING) {\n\t\t\t\tif((newblock = minix_balloc(i->sb)) < 0) {\n\t\t\t\t\tbrelse(buf);\n\t\t\t\t\tbrelse(buf3);\n\t\t\t\t\treturn -ENOSPC;\n\t\t\t\t}\n\t\t\t\t/* initialize the new block */\n\t\t\t\tif(!(buf4 = bread(i->dev, newblock, blksize))) {\n\t\t\t\t\tminix_bfree(i->sb, newblock);\n\t\t\t\t\tbrelse(buf);\n\t\t\t\t\tbrelse(buf3);\n\t\t\t\t\treturn -EIO;\n\t\t\t\t}\n\t\t\t\tmemset_b(buf4->data, 0, blksize);\n\t\t\t\tbwrite(buf4);\n\t\t\t\ttindblock[tblock / BLOCKS_PER_IND_BLOCK(i->sb)] = newblock;\n\t\t\t\tbuf3->flags |= (BUFFER_DIRTY | BUFFER_VALID);\n\t\t\t\tblock = newblock;\n\t\t\t} else {\n\t\t\t\tbrelse(buf);\n\t\t\t\tbrelse(buf3);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t\tdblock = tblock;\n\t\tiblock = tblock / BLOCKS_PER_IND_BLOCK(i->sb);\n\t\tif(!(buf2 = bread(i->dev, block, blksize))) {\n\t\t\tprintk(\"%s(): returning -EIO\\n\", __FUNCTION__);\n\t\t\tbrelse(buf);\n\t\t\tbrelse(buf3);\n\t\t\treturn -EIO;\n\t\t}\n\t} else {\n\t\tiblock = block;\n\t\tif(!(buf2 = bread(i->dev, indblock[iblock], blksize))) {\n\t\t\tprintk(\"%s(): returning -EIO\\n\", __FUNCTION__);\n\t\t\tbrelse(buf);\n\t\t\treturn -EIO;\n\t\t}\n\t}\n\n\tdindblock = (__u32 *)buf2->data;\n\tblock = dindblock[dblock - (iblock * BLOCKS_PER_IND_BLOCK(i->sb))];\n\tif(!block && mode == FOR_WRITING) {\n\t\tif((newblock = minix_balloc(i->sb)) < 0) {\n\t\t\tbrelse(buf);\n\t\t\tif(level == MINIX_TIND_BLOCK) {\n\t\t\t\tbrelse(buf3);\n\t\t\t}\n\t\t\tbrelse(buf2);\n\t\t\treturn -ENOSPC;\n\t\t}\n\t\t/* initialize the new block */\n\t\tif(!(buf4 = bread(i->dev, newblock, blksize))) {\n\t\t\tminix_bfree(i->sb, newblock);\n\t\t\tbrelse(buf);\n\t\t\tif(level == MINIX_TIND_BLOCK) {\n\t\t\t\tbrelse(buf3);\n\t\t\t}\n\t\t\tbrelse(buf2);\n\t\t\treturn -EIO;\n\t\t}\n\t\tmemset_b(buf4->data, 0, blksize);\n\t\tbwrite(buf4);\n\t\tdindblock[dblock - (iblock * BLOCKS_PER_IND_BLOCK(i->sb))] = newblock;\n\t\tbuf2->flags |= (BUFFER_DIRTY | BUFFER_VALID);\n\t\tblock = newblock;\n\t}\n\tbrelse(buf);\n\tif(level == MINIX_TIND_BLOCK) {\n\t\tbrelse(buf3);\n\t}\n\tbrelse(buf2);\n\treturn block;\n}\n\nint v2_minix_truncate(struct inode *i, __off_t length)\n{\n\t__blk_t block, indblock, *dindblock;\n\tstruct buffer *buf;\n\tint n, retval;\n\n\tblock = length / i->sb->s_blocksize;\n\n\tif(!S_ISDIR(i->i_mode) && !S_ISREG(i->i_mode) && !S_ISLNK(i->i_mode)) {\n\t\treturn -EINVAL;\n\t}\n\n\tif(block < MINIX_NDIR_BLOCKS) {\n\t\tfor(n = block; n < MINIX_NDIR_BLOCKS; n++) {\n\t\t\tif(i->u.minix.u.i2_zone[n]) {\n\t\t\t\tminix_bfree(i->sb, i->u.minix.u.i2_zone[n]);\n\t\t\t\ti->u.minix.u.i2_zone[n] = 0;\n\t\t\t}\n\t\t}\n\t\tblock = 0;\n\t}\n\n\tif(!block || block < (BLOCKS_PER_IND_BLOCK(i->sb) + MINIX_NDIR_BLOCKS)) {\n\t\tif(block) {\n\t\t\tblock -= MINIX_NDIR_BLOCKS;\n\t\t}\n\t\tif(i->u.minix.u.i2_zone[MINIX_IND_BLOCK]) {\n\t\t\tif((retval = free_zone(i, i->u.minix.u.i2_zone[MINIX_IND_BLOCK], block)) < 0) {\n\t\t\t\treturn retval;\n\t\t\t}\n\t\t\tif(!block) {\n\t\t\t\tminix_bfree(i->sb, i->u.minix.u.i2_zone[MINIX_IND_BLOCK]);\n\t\t\t\ti->u.minix.u.i2_zone[MINIX_IND_BLOCK] = 0;\n\t\t\t}\n\t\t}\n\t\tblock = 0;\n\t}\n\n\tif(!block || block < (BLOCKS_PER_DIND_BLOCK(i->sb) + BLOCKS_PER_IND_BLOCK(i->sb) + MINIX_NDIR_BLOCKS)) {\n\t\tif(block) {\n\t\t\tblock -= MINIX_NDIR_BLOCKS;\n\t\t\tblock -= BLOCKS_PER_IND_BLOCK(i->sb);\n\t\t}\n\t\tif(i->u.minix.u.i2_zone[MINIX_DIND_BLOCK]) {\n\t\t\tif((retval = free_indblock(i, i->u.minix.u.i2_zone[MINIX_DIND_BLOCK], block)) < 0) {\n\t\t\t\treturn retval;\n\t\t\t}\n\t\t\tif(!block) {\n\t\t\t\tminix_bfree(i->sb, i->u.minix.u.i2_zone[MINIX_DIND_BLOCK]);\n\t\t\t\ti->u.minix.u.i2_zone[MINIX_DIND_BLOCK] = 0;\n\t\t\t}\n\t\t}\n\t\tblock = 0;\n\t}\n\n\tif(!block || block < (BLOCKS_PER_TIND_BLOCK(i->sb) + BLOCKS_PER_DIND_BLOCK(i->sb) + BLOCKS_PER_IND_BLOCK(i->sb) + EXT2_NDIR_BLOCKS)) {\n\t\tif(block) {\n\t\t\tblock -= MINIX_NDIR_BLOCKS;\n\t\t\tblock -= BLOCKS_PER_IND_BLOCK(i->sb);\n\t\t\tblock -= BLOCKS_PER_DIND_BLOCK(i->sb);\n\t\t}\n\t\tif(i->u.minix.u.i2_zone[MINIX_TIND_BLOCK]) {\n\t\t\tif(!(buf = bread(i->dev, i->u.minix.u.i2_zone[MINIX_TIND_BLOCK], i->sb->s_blocksize))) {\n\t\t\t\tprintk(\"%s(): error reading the triply indirect block (%d).\\n\", __FUNCTION__, i->u.minix.u.i2_zone[MINIX_TIND_BLOCK]);\n\t\t\t\treturn -EIO;\n\t\t\t}\n\t\t\tdindblock = (__blk_t *)buf->data;\n\t\t\tindblock = block % BLOCKS_PER_IND_BLOCK(i->sb);\n\t\t\tfor(n = block / BLOCKS_PER_IND_BLOCK(i->sb); n < BLOCKS_PER_IND_BLOCK(i->sb); n++) {\n\t\t\t\tif(dindblock[n]) {\n\t\t\t\t\tif((retval = free_indblock(i, dindblock[n], indblock)) < 0) {\n\t\t\t\t\t\tbrelse(buf);\n\t\t\t\t\t\treturn retval;\n\t\t\t\t\t}\n\t\t\t\t\tif(!indblock) {\n\t\t\t\t\t\tminix_bfree(i->sb, dindblock[n]);\n\t\t\t\t\t\tdindblock[n] = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tindblock = 0;\n\t\t\t}\n\t\t\tbwrite(buf);\n\t\t\tif(!block) {\n\t\t\t\tminix_bfree(i->sb, i->u.minix.u.i2_zone[MINIX_TIND_BLOCK]);\n\t\t\t\ti->u.minix.u.i2_zone[MINIX_TIND_BLOCK] = 0;\n\t\t\t}\n\t\t}\n\t}\n\n\ti->i_mtime = CURRENT_TIME;\n\ti->i_ctime = CURRENT_TIME;\n\ti->i_size = length;\n\ti->state |= INODE_DIRTY;\n\n\treturn 0;\n}\n#endif /* CONFIG_FS_MINIX */\n"
  },
  {
    "path": "fs/namei.c",
    "content": "/*\n * fiwix/fs/namei.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/sleep.h>\n#include <fiwix/sched.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/stat.h>\n#include <fiwix/mm.h>\n#include <fiwix/mman.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstatic int do_namei(char *path, struct inode *dir, struct inode **i_res, struct inode **d_res, int follow_links)\n{\n\tchar *name, *ptr_name;\n\tstruct inode *i;\n\tstruct superblock *sb;\n\n\tint errno;\n\n\t*i_res = dir;\n\tfor(;;) {\n\t\twhile(*path == '/') {\n\t\t\tpath++;\n\t\t}\n\t\tif(*path == '\\0') {\n\t\t\treturn 0;\n\t\t}\n\n\t\t/* extracts the next component of the path */\n\t\tif(!(name = (char *)kmalloc(NAME_MAX + 1))) {\n\t\t\treturn -ENOMEM;\n\t\t}\n\t\tptr_name = name;\n\t\twhile(*path != '\\0' && *path != '/') {\n\t\t\tif(ptr_name > (name + NAME_MAX)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t*ptr_name++ = *path++;\n\t\t}\n\t\t*ptr_name = 0;\n\n\t\t/*\n\t\t * If the inode is the root of a file system, then return the\n\t\t * inode on which the file system was mounted.\n\t\t */\n\t\tif(name[0] == '.' && name[1] == '.' && name[2] == '\\0') {\n\t\t\tif(dir == dir->sb->root) {\n\t\t\t\tsb = dir->sb;\n\t\t\t\tiput(dir);\n\t\t\t\tdir = sb->dir;\n\t\t\t\tdir->count++;\n\t\t\t}\n\t\t}\n\n\t\tif((errno = check_permission(TO_EXEC, dir))) {\n\t\t\tbreak;\n\t\t}\n\n\t\tdir->count++;\n\t\tif((errno = dir->fsop->lookup(name, dir, &i))) {\n\t\t\tbreak;\n\t\t}\n\n\t\tkfree((unsigned int)name);\n\t\tif(*path == '/') {\n\t\t\tif(!S_ISDIR(i->i_mode) && !S_ISLNK(i->i_mode)) {\n\t\t\t\tiput(dir);\n\t\t\t\tiput(i);\n\t\t\t\treturn -ENOTDIR;\n\t\t\t}\n\t\t\tif(S_ISLNK(i->i_mode)) {\n\t\t\t\tif(i->fsop->followlink) {\n\t\t\t\t\tif((errno = i->fsop->followlink(dir, i, &i))) {\n\t\t\t\t\t\tiput(dir);\n\t\t\t\t\t\treturn errno;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tif(i->fsop->followlink && follow_links) {\n\t\t\t\tif((errno = i->fsop->followlink(dir, i, &i))) {\n\t\t\t\t\tiput(dir);\n\t\t\t\t\treturn errno;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif(d_res) {\n\t\t\tif(*d_res) {\n\t\t\t\tiput(*d_res);\n\t\t\t}\n\t\t\t*d_res = dir;\n\t\t} else {\n\t\t\tiput(dir);\n\t\t}\n\t\tdir = i;\n\t\t*i_res = i;\n\t}\n\n\tkfree((unsigned int)name);\n\tif(d_res) {\n\t\tif(*d_res) {\n\t\t\tiput(*d_res);\n\t\t}\n\t\t/*\n\t\t * If that was the last component of the path,\n\t\t * then return the directory.\n\t\t */\n\t\tif(*path == '\\0') {\n\t\t\t*d_res = dir;\n\t\t\tdir->count++;\n\t\t} else {\n\t\t\t/* that's a non-existent directory */\n\t\t\t*d_res = NULL;\n\t\t\terrno = -ENOENT;\n\t\t}\n\t\tiput(dir);\n\t\t*i_res = NULL;\n\t} else {\n\t\tiput(dir);\n\t}\n\n\treturn errno;\n}\n\nint parse_namei(char *path, struct inode *base_dir, struct inode **i_res, struct inode **d_res, int follow_links)\n{\n\tstruct inode *dir;\n\tint errno;\n\n\tif(!path) {\n\t\treturn -EFAULT;\n\t}\n\tif(*path == '\\0') {\n\t\treturn -ENOENT;\n\t}\n\n\tif(!(dir = base_dir)) {\n\t\tdir = current->pwd;\n\t}\n\n\t/* it is definitely an absolute path */\n\tif(path[0] == '/') {\n\t\tdir = current->root;\n\t}\n\tdir->count++;\n\terrno = do_namei(path, dir, i_res, d_res, follow_links);\n\treturn errno;\n}\n\n/*\n * namei() returns:\n * i_res -> the inode of the last component of the path, or NULL.\n * d_res -> the inode of the directory where i_res resides, or NULL.\n */\nint namei(char *path, struct inode **i_res, struct inode **d_res, int follow_links)\n{\n\t*i_res = NULL;\n\tif(d_res) {\n\t\t*d_res = NULL;\n\t}\n\treturn parse_namei(path, NULL, i_res, d_res, follow_links);\n}\n"
  },
  {
    "path": "fs/pipefs/Makefile",
    "content": "# fiwix/fs/pipefs/Makefile\n#\n# Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n# Distributed under the terms of the Fiwix License.\n#\n\n.c.o:\n\t$(CC) $(CFLAGS) -c -o $@ $<\n\nOBJS = super.o fifo.o pipe.o\n\nall:\t$(OBJS)\n\nclean:\n\trm -f *.o\n\n"
  },
  {
    "path": "fs/pipefs/fifo.c",
    "content": "/*\n * fiwix/fs/pipefs/fifo.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_pipe.h>\n#include <fiwix/stat.h>\n#include <fiwix/mm.h>\n#include <fiwix/sleep.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/sched.h>\n#include <fiwix/stdio.h>\n\nint fifo_open(struct inode *i, struct fd *f)\n{\n\t/* first open */\n\tif(i->count == 1) {\n\t\tif(!(i->u.pipefs.i_data = (void *)kmalloc(PAGE_SIZE))) {\n\t\t\treturn -ENOMEM;\n\t\t}\n\t\ti->u.pipefs.i_readoff = 0;\n\t\ti->u.pipefs.i_writeoff = 0;\n\t}\n\n\tif((f->flags & O_ACCMODE) == O_RDONLY) {\n\t\ti->u.pipefs.i_readers++;\n\t\twakeup(&pipefs_write);\n\t\tif(!(f->flags & O_NONBLOCK)) {\n\t\t\twhile(!i->u.pipefs.i_writers) {\n\t\t\t\tif(sleep(&pipefs_read, PROC_INTERRUPTIBLE)) {\n\t\t\t\t\tif(!--i->u.pipefs.i_readers) {\n\t\t\t\t\t\twakeup(&pipefs_write);\n\t\t\t\t\t}\n\t\t\t\t\treturn -EINTR;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif((f->flags & O_ACCMODE) == O_WRONLY) {\n\t\tif((f->flags & O_NONBLOCK) && !i->u.pipefs.i_readers) {\n\t\t\treturn -ENXIO;\n\t\t}\n\n\t\ti->u.pipefs.i_writers++;\n\t\twakeup(&pipefs_read);\n\t\tif(!(f->flags & O_NONBLOCK)) {\n\t\t\twhile(!i->u.pipefs.i_readers) {\n\t\t\t\tif(sleep(&pipefs_write, PROC_INTERRUPTIBLE)) {\n\t\t\t\t\tif(!--i->u.pipefs.i_writers) {\n\t\t\t\t\t\twakeup(&pipefs_read);\n\t\t\t\t\t}\n\t\t\t\t\treturn -EINTR;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif((f->flags & O_ACCMODE) == O_RDWR) {\n\t\ti->u.pipefs.i_readers++;\n\t\ti->u.pipefs.i_writers++;\n\t\twakeup(&pipefs_write);\n\t\twakeup(&pipefs_read);\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "fs/pipefs/pipe.c",
    "content": "/*\n * fiwix/fs/pipefs/pipe.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_pipe.h>\n#include <fiwix/stat.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/ioctl.h>\n#include <fiwix/sleep.h>\n#include <fiwix/sched.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstatic struct resource pipe_resource = { 0, 0 };\n\nint pipefs_close(struct inode *i, struct fd *f)\n{\n\tif((f->flags & O_ACCMODE) == O_RDONLY) {\n\t\tif(!--i->u.pipefs.i_readers) {\n\t\t\twakeup(&do_select);\n\t\t\twakeup(&pipefs_write);\n\t\t}\n\t}\n\tif((f->flags & O_ACCMODE) == O_WRONLY) {\n\t\tif(!--i->u.pipefs.i_writers) {\n\t\t\twakeup(&do_select);\n\t\t\twakeup(&pipefs_read);\n\t\t}\n\t}\n\tif((f->flags & O_ACCMODE) == O_RDWR) {\n\t\tif(!--i->u.pipefs.i_readers) {\n\t\t\twakeup(&do_select);\n\t\t\twakeup(&pipefs_write);\n\t\t}\n\t\tif(!--i->u.pipefs.i_writers) {\n\t\t\twakeup(&do_select);\n\t\t\twakeup(&pipefs_read);\n\t\t}\n\t}\n\treturn 0;\n}\n\nint pipefs_read(struct inode *i, struct fd *f, char *buffer, __size_t count)\n{\n\t__size_t bytes_read;\n\t__size_t n, limit;\n\tchar *data;\n\n\tbytes_read = 0;\n\tdata = i->u.pipefs.i_data;\n\n\twhile(count) {\n\t\tif(i->u.pipefs.i_writeoff) {\n\t\t\tif(i->u.pipefs.i_readoff >= i->u.pipefs.i_writeoff) {\n\t\t\t\tlimit = PIPE_BUF - i->u.pipefs.i_readoff;\n\t\t\t} else {\n\t\t\t\tlimit = i->u.pipefs.i_writeoff - i->u.pipefs.i_readoff;\n\t\t\t}\n\t\t} else {\n\t\t\tlimit = PIPE_BUF - i->u.pipefs.i_readoff;\n\t\t}\n\t\tn = MIN(limit, count);\n\t\tif(i->i_size && n) {\n\t\t\tlock_resource(&pipe_resource);\n\t\t\tmemcpy_b(buffer + bytes_read, data + i->u.pipefs.i_readoff, n);\n\t\t\tbytes_read += n;\n\t\t\ti->u.pipefs.i_readoff += n;\n\t\t\ti->i_size -= n;\n\t\t\tif(i->u.pipefs.i_writeoff >= PIPE_BUF) {\n\t\t\t\ti->u.pipefs.i_writeoff = 0;\n\t\t\t}\n\t\t\tunlock_resource(&pipe_resource);\n\t\t\twakeup(&do_select);\n\t\t\twakeup(&pipefs_write);\n\t\t\tbreak;\n\t\t} else {\n\t\t\tif(i->u.pipefs.i_writers) {\n\t\t\t\tif(f->flags & O_NONBLOCK) {\n\t\t\t\t\treturn -EAGAIN;\n\t\t\t\t}\n\t\t\t\tif(sleep(&pipefs_read, PROC_INTERRUPTIBLE)) {\n\t\t\t\t\treturn -EINTR;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif(i->i_size) {\n\t\t\t\t\tif(i->u.pipefs.i_readoff >= PIPE_BUF) {\n\t\t\t\t\t\ti->u.pipefs.i_readoff = 0;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\tif(!i->i_size) {\n\t\ti->u.pipefs.i_readoff = 0;\n\t\ti->u.pipefs.i_writeoff = 0;\n\t}\n\treturn bytes_read;\n}\n\nint pipefs_write(struct inode *i, struct fd *f, const char *buffer, __size_t count)\n{\n\t__size_t bytes_written;\n\t__size_t n;\n\tchar *data;\n\tint limit;\n\n\tbytes_written = 0;\n\tdata = i->u.pipefs.i_data;\n\n\twhile(bytes_written < count) {\n\t\t/* if there are no readers then send signal and return */\n\t\tif(!i->u.pipefs.i_readers) {\n\t\t\tsend_sig(current, SIGPIPE);\n\t\t\treturn -EPIPE;\n\t\t}\n\n\t\tif(i->u.pipefs.i_readoff) {\n\t\t\tif(i->u.pipefs.i_writeoff <= i->u.pipefs.i_readoff) {\n\t\t\t\tlimit = i->u.pipefs.i_readoff;\n\t\t\t} else {\n\t\t\t\tlimit = PIPE_BUF;\n\t\t\t}\n\t\t} else {\n\t\t\tlimit = PIPE_BUF;\n\t\t}\n\n\t\tn = MIN((count - bytes_written), (limit - i->u.pipefs.i_writeoff));\n\n\t\t/*\n\t\t * POSIX requires that any write operation involving less than\n\t\t * or equal to PIPE_BUF bytes, must be automatically executed\n\t\t * and finished without being interleaved with write operations\n\t\t * of other processes to the same pipe.\n\t\t*/\n\t\tif(n && n <= PIPE_BUF) {\n\t\t\tlock_resource(&pipe_resource);\n\t\t\tmemcpy_b(data + i->u.pipefs.i_writeoff, buffer + bytes_written, n);\n\t\t\tbytes_written += n;\n\t\t\ti->u.pipefs.i_writeoff += n;\n\t\t\ti->i_size += n;\n\t\t\tif(i->u.pipefs.i_readoff >= PIPE_BUF) {\n\t\t\t\ti->u.pipefs.i_readoff = 0;\n\t\t\t}\n\t\t\tunlock_resource(&pipe_resource);\n\t\t\twakeup(&do_select);\n\t\t\twakeup(&pipefs_read);\n\t\t\tcontinue;\n\t\t}\n\n\t\twakeup(&do_select);\n\t\twakeup(&pipefs_read);\n\t\tif(!(f->flags & O_NONBLOCK)) {\n\t\t\tif(sleep(&pipefs_write, PROC_INTERRUPTIBLE)) {\n\t\t\t\treturn -EINTR;\n\t\t\t}\n\t\t} else {\n\t\t\treturn -EAGAIN;\n\t\t}\n\t}\n\treturn bytes_written;\n}\n\nint pipefs_ioctl(struct inode *i, struct fd *f, int cmd, unsigned int arg)\n{\n\tint errno;\n\n\tswitch(cmd) {\n\t\tcase FIONREAD:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned int)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tmemcpy_b((void *)arg, &i->i_size, sizeof(unsigned int));\n\t\t\tbreak;\n\t\tdefault:\n\t\t\treturn -EINVAL;\n\t}\n\treturn 0;\n}\n\n__loff_t pipefs_llseek(struct inode *i, __loff_t offset)\n{\n\treturn -ESPIPE;\n}\n\nint pipefs_select(struct inode *i, struct fd *f, int flag)\n{\n\tswitch(flag) {\n\t\tcase SEL_R:\n\t\t\t/*\n\t\t\t * if !i->i_size && !i->u.pipefs.i_writers\n\t\t\t * should also return 1?\n\t\t\t */\n\t\t\tif(i->i_size || !i->u.pipefs.i_writers) {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase SEL_W:\n\t\t\t/*\n\t\t\t * if i->i_size == PIPE_BUF && !i->u.pipefs.i_readers\n\t\t\t * should also return 1?\n\t\t\t */\n\t\t\tif(i->i_size < PIPE_BUF || !i->u.pipefs.i_readers) {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tbreak;\n\t}\n\treturn 0;\n}\n"
  },
  {
    "path": "fs/pipefs/super.c",
    "content": "/*\n * fiwix/fs/pipefs/super.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_pipe.h>\n#include <fiwix/stat.h>\n#include <fiwix/mm.h>\n#include <fiwix/sched.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstatic unsigned int i_counter;\n\nstruct fs_operations pipefs_fsop = {\n\tFSOP_KERN_MOUNT,\n\tPIPE_DEV,\n\n\tfifo_open,\n\tpipefs_close,\n\tpipefs_read,\n\tpipefs_write,\n\tpipefs_ioctl,\n\tpipefs_llseek,\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tpipefs_select,\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lookup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tpipefs_ialloc,\n\tpipefs_ifree,\n\tNULL,\t\t\t/* statfs */\n\tpipefs_read_superblock,\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nint pipefs_ialloc(struct inode *i, int mode)\n{\n\tstruct superblock *sb = i->sb;\n\n\tsuperblock_lock(sb);\n\ti_counter++;\n\tsuperblock_unlock(sb);\n\n\ti->i_mode = mode;\n\ti->dev = i->rdev = sb->dev;\n\ti->fsop = &pipefs_fsop;\n\ti->inode = i_counter;\n\ti->count = 2;\n\tif(!(i->u.pipefs.i_data = (void *)kmalloc(PAGE_SIZE))) {\n\t\treturn -ENOMEM;\n\t}\n\ti->u.pipefs.i_readoff = 0;\n\ti->u.pipefs.i_writeoff = 0;\n\ti->u.pipefs.i_readers = 1;\n\ti->u.pipefs.i_writers = 1;\n\treturn 0;\n}\n\nvoid pipefs_ifree(struct inode *i)\n{\n\tif(!i->u.pipefs.i_readers && !i->u.pipefs.i_writers) {\n\t\t/*\n\t\t * We need to ask before to kfree() because this function is\n\t\t * also called to free removed (with sys_unlink) fifo files.\n\t\t */\n\t\tif(i->u.pipefs.i_data) {\n\t\t\tkfree((unsigned int)i->u.pipefs.i_data);\n\t\t}\n\t}\n}\n\nint pipefs_read_superblock(__dev_t dev, struct superblock *sb)\n{\n\tsuperblock_lock(sb);\n\tsb->dev = dev;\n\tsb->fsop = &pipefs_fsop;\n\tsb->s_blocksize = BLKSIZE_1K;\n\ti_counter = 0;\n\tsuperblock_unlock(sb);\n\treturn 0;\n}\n\nint pipefs_init(void)\n{\n\treturn register_filesystem(\"pipefs\", &pipefs_fsop);\n}\n"
  },
  {
    "path": "fs/procfs/Makefile",
    "content": "# fiwix/fs/procfs/Makefile\n#\n# Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n# Distributed under the terms of the Fiwix License.\n#\n\n.c.o:\n\t$(CC) $(CFLAGS) -c -o $@ $<\n\nOBJS = super.o inode.o namei.o dir.o file.o symlink.o tree.o data.o kmsg.o\n\nall:\t$(OBJS)\n\nclean:\n\trm -f *.o\n\n"
  },
  {
    "path": "fs/procfs/data.c",
    "content": "/*\n * fiwix/fs/procfs/data.c\n *\n * Copyright 2018-2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/kparms.h>\n#include <fiwix/system.h>\n#include <fiwix/types.h>\n#include <fiwix/process.h>\n#include <fiwix/cmos.h>\n#include <fiwix/dma.h>\n#include <fiwix/ata.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/devices.h>\n#include <fiwix/locks.h>\n#include <fiwix/mm.h>\n#include <fiwix/mman.h>\n#include <fiwix/fs_proc.h>\n#include <fiwix/cpu.h>\n#include <fiwix/irq.h>\n#include <fiwix/sched.h>\n#include <fiwix/timer.h>\n#include <fiwix/utsname.h>\n#include <fiwix/version.h>\n#include <fiwix/socket.h>\n#include <fiwix/pci.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#define FSHIFT16\t16\n#define FIXED16_1\t(1 << FSHIFT16)\n#define LOAD_INT(x)     ((x) >> FSHIFT16)\n#define LOAD_FRAC(x)    LOAD_INT(((x) & (FIXED16_1 - 1)) * 100)\n\nstatic const char *pstate[] = {\n\t\"? (unused!)\",\n\t\"R (running)\",\n\t\"S (sleeping)\",\n\t\"Z (zombie)\",\n\t\"T (stopped)\",\n\t\"D (idle)\",\n};\n\n/*\n * procfs root directory related functions\n * ---------------------------------------\n */\nint data_proc_self(char *buffer, __pid_t pid)\n{\n\treturn sprintk(buffer, \"%s\", current->pidstr);\n}\n\nint data_proc_buddyinfo(char *buffer, __pid_t pid)\n{\n\tint n, level, size;\n\n\tsize = sprintk(buffer, \"Sizes:\");\n\tfor(level = 32, n = 0; n < BUDDY_MAX_LEVEL; n++, level <<= 1) {\n\t\tsize += sprintk(buffer + size, \"\\t%d\", level);\n\t}\n\tsize += sprintk(buffer + size, \"\\n\");\n\tsize += sprintk(buffer + size, \"------------------------------------------------------------\\n\");\n\tfor(n = 0; n < BUDDY_MAX_LEVEL; n++) {\n\t\tsize += sprintk(buffer + size, \"\\t%d\", kstat.buddy_low_count[n]);\n\t}\n\tsize += sprintk(buffer + size, \"\\n\\n\");\n\tsize += sprintk(buffer + size, \"Memory requested (used): %d KB (%d KB)\\n\", kstat.buddy_low_mem_requested / 1024, (kstat.buddy_low_num_pages * PAGE_SIZE / 1024));\n\n\treturn size;\n}\n\nint data_proc_cmdline(char *buffer, __pid_t pid)\n{\n\treturn sprintk(buffer, \"%s\\n\", kernel_cmdline);\n}\n\nint data_proc_cpuinfo(char *buffer, __pid_t pid)\n{\n\tint size;\n\n\tsize = sprintk(buffer, \"processor       : 0\\n\");\n\tsize += sprintk(buffer + size, \"cpu family      : %d86\\n\", cpu_table.family <= 6 ? cpu_table.family : 6);\n\tif(cpu_table.model >= 0) {\n\t\tsize += sprintk(buffer + size, \"model           : %d\\n\", cpu_table.model);\n\t} else {\n\t\tsize += sprintk(buffer + size, \"model           : unknown\\n\");\n\t}\n\n\tif(cpu_table.vendor_id) {\n\t\tsize += sprintk(buffer + size, \"vendor_id       : %s\\n\", cpu_table.vendor_id);\n\t}\n\tif(cpu_table.model_name) {\n\t\tsize += sprintk(buffer + size, \"model name      : %s\\n\", cpu_table.model_name);\n\t}\n\tif(cpu_table.stepping >= 0) {\n\t\tsize += sprintk(buffer + size, \"stepping        : %d\\n\", cpu_table.stepping);\n\t} else {\n\t\tsize += sprintk(buffer + size, \"stepping        : unknown\\n\");\n\t}\n\n\tsize += sprintk(buffer + size, \"cpu MHz         : \");\n\tif(cpu_table.hz) {\n\t\tsize += sprintk(buffer + size, \"%d.%d\\n\", (cpu_table.hz / 1000000), ((cpu_table.hz % 1000000) / 100000));\n\t} else {\n\t\tsize += sprintk(buffer + size, \"unknown\\n\");\n\t}\n\tif(cpu_table.cache) {\n\t\tsize += sprintk(buffer + size, \"cache size      : %s\\n\", cpu_table.cache);\n\t}\n\tsize += sprintk(buffer + size, \"cpuid           : %s\\n\", cpu_table.has_cpuid ? \"yes\" : \"no\");\n\tsize += sprintk(buffer + size, \"fpu             : %s\\n\", cpu_table.has_fpu ? \"yes\" : \"no\");\n\tsize += get_cpu_flags(buffer + size);\n\treturn size;\n}\n\nint data_proc_devices(char *buffer, __pid_t pid)\n{\n\tint n, size;\n\tstruct device *d;\n\n\tsize = sprintk(buffer, \"Character devices:\\n\");\n\tfor(n = 0; n < NR_CHRDEV; n++) {\n\t\td = chr_device_table[n];\n\t\twhile(d) {\n\t\t\tsize += sprintk(buffer + size, \"%3d %s\\n\", d->major, d->name);\n\t\t\td = d->next;\n\t\t}\n\t}\n\n\tsize += sprintk(buffer + size, \"\\nBlock devices:\\n\");\n\tfor(n = 0; n < NR_BLKDEV; n++) {\n\t\td = blk_device_table[n];\n\t\twhile(d) {\n\t\t\tsize += sprintk(buffer + size, \"%3d %s\\n\", d->major, d->name);\n\t\t\td = d->next;\n\t\t}\n\t}\n\treturn size;\n}\n\nint data_proc_dma(char *buffer, __pid_t pid)\n{\n\tint n, size;\n\n\tsize = 0;\n\tfor(n = 0; n < DMA_CHANNELS; n++) {\n\t\tif(dma_resources[n]) {\n\t\t\tsize += sprintk(buffer + size, \"%2d: %s\\n\", n, dma_resources[n]);\n\t\t}\n\t}\n\treturn size;\n}\n\nint data_proc_filesystems(char *buffer, __pid_t pid)\n{\n\tint n, size;\n\tint nodev;\n\n\tsize = 0;\n\tfor(n = 0; n < NR_FILESYSTEMS; n++) {\n\t\tif(filesystems_table[n].name) {\n\t\t\tnodev = 0;\n\t\t\tif(filesystems_table[n].fsop->flags != FSOP_REQUIRES_DEV) {\n\t\t\t\tnodev = 1;\n\t\t\t}\n\t\t\tsize += sprintk(buffer + size, \"%s %s\\n\", nodev ? \"nodev\" : \"     \", filesystems_table[n].name);\n\t\t}\n\t}\n\treturn size;\n}\n\nint data_proc_interrupts(char *buffer, __pid_t pid)\n{\n\tstruct interrupt *irq;\n\tint n, size;\n\n\tsize = 0;\n\tfor(n = 0; n < NR_IRQS; n++) {\n\t\tif((irq = irq_table[n])) {\n\t\t\tsize += sprintk(buffer + size, \"%3d: %9u %s\", n, irq->ticks, irq->name);\n\t\t\twhile((irq = irq->next)) {\n\t\t\t\tsize += sprintk(buffer + size, \",%s\", irq->name);\n\t\t\t}\n\t\t\tsize += sprintk(buffer + size, \"\\n\");\n\t\t}\n\t}\n\tsize += sprintk(buffer + size, \"SPU: %9u %s\\n\", kstat.sirqs, \"Spurious interrupts\");\n\treturn size;\n}\n\nint data_proc_loadavg(char *buffer, __pid_t pid)\n{\n\tint a, b, c;\n\tint size;\n\tstruct proc *p;\n\tint nrun = 0;\n\tint nprocs = 0;\n\n\ta = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT);\n\tb = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT);\n\tc = avenrun[2] << (SI_LOAD_SHIFT - FSHIFT);\n\n\tFOR_EACH_PROCESS(p) {\n\t\tnprocs++;\n\t\tif(p->state == PROC_RUNNING) {\n\t\t\tnrun++;\n\t\t}\n\t\tp = p->next;\n\t}\n\n\tsize = sprintk(buffer, \"%d.%02d %d.%02d %d.%02d %d/%d %d\\n\", LOAD_INT(a), LOAD_FRAC(a), LOAD_INT(b), LOAD_FRAC(b), LOAD_INT(c), LOAD_FRAC(c), nrun, nprocs, lastpid);\n\treturn size;\n}\n\nint data_proc_locks(char *buffer, __pid_t pid)\n{\n\tstruct flock_file *ff;\n\tint n, size;\n\n\tn = size = 0;\n\tff = flock_file_table;\n\n\twhile(ff) {\n\t\tif(ff->inode) {\n\t\t\tsize += sprintk(buffer + size, \"%d: FLOCK  ADVISORY  %s \", n + 1, ff->type & LOCK_SH ? \"READ \" : \"WRITE\");\n\t\t\tsize += sprintk(buffer + size, \"%d %x:%d:%d 0 EOF\\n\", ff->proc->pid, MAJOR(ff->inode->dev), MINOR(ff->inode->dev), ff->inode->inode);\n\t\t}\n\t\tn++;\n\t\tff = ff->next;\n\t}\n\n\treturn size;\n}\n\nint data_proc_meminfo(char *buffer, __pid_t pid)\n{\n\tstruct page *pg;\n\tint n, size;\n\n\tkstat.shared = 0;\n\tfor(n = 0; n < kstat.physical_pages; n++) {\n\t\tpg = &page_table[n];\n\t\tif(pg->flags & PAGE_RESERVED) {\n\t\t\tcontinue;\n\t\t}\n\t\tif(!pg->count) {\n\t\t\tcontinue;\n\t\t}\n\t\tkstat.shared += pg->count - 1;\n\t}\n\n\tsize = 0;\n\tsize += sprintk(buffer + size, \"        total:    used:    free:  shared: buffers:  cached:\\n\");\n\tsize += sprintk(buffer + size, \"Mem:  %8u %8u %8u %8u %8u %8u\\n\", kstat.total_mem_pages << PAGE_SHIFT, (kstat.total_mem_pages << PAGE_SHIFT) - (kstat.free_pages << PAGE_SHIFT), kstat.free_pages << PAGE_SHIFT, kstat.shared * 1024, kstat.buffers_size * 1024, kstat.cached * 1024);\n\tsize += sprintk(buffer + size, \"Swap: %8u %8u %8u\\n\", 0, 0, 0);\n\tsize += sprintk(buffer + size, \"MemTotal: %9d kB\\n\", kstat.total_mem_pages << 2);\n\tsize += sprintk(buffer + size, \"MemFree:  %9d kB\\n\", kstat.free_pages << 2);\n\tsize += sprintk(buffer + size, \"MemShared:%9d kB\\n\", kstat.shared);\n\tsize += sprintk(buffer + size, \"Buffers:  %9d kB\\n\", kstat.buffers_size);\n\tsize += sprintk(buffer + size, \"Cached:   %9d kB\\n\", kstat.cached);\n\tsize += sprintk(buffer + size, \"SwapTotal:%9d kB\\n\", 0);\n\tsize += sprintk(buffer + size, \"SwapFree: %9d kB\\n\", 0);\n\tsize += sprintk(buffer + size, \"Dirty:    %9d kB\\n\", kstat.dirty_buffers);\n\treturn size;\n}\n\nint data_proc_mounts(char *buffer, __pid_t pid)\n{\n\tint size;\n\tchar *flag;\n\tstruct mount *mp;\n\n\tsize = 0;\n\tmp = mount_table;\n\n\twhile(mp) {\n\t\tif(mp->fs->fsop->flags != FSOP_KERN_MOUNT) {\n\t\t\tflag = mp->sb.flags & MS_RDONLY ? \"ro\" : \"rw\";\n\t\t\tsize += sprintk(buffer + size, \"%s %s %s %s 0 0\\n\", mp->devname, mp->dirname, mp->fs->name, flag);\n\t\t}\n\t\tmp = mp->next;\n\t}\n\treturn size;\n}\n\nint data_proc_partitions(char *buffer, __pid_t pid)\n{\n\tint n, ctrl, drv, size;\n\tint minor, major;\n\tunsigned int blocks;\n\tstruct ide *ide;\n\tstruct ata_drv *drive;\n\n\tsize = 0;\n\tsize += sprintk(buffer + size, \"major minor  #blocks  name\\n\\n\");\n\n\tfor(ctrl = 0; ctrl < NR_IDE_CTRLS; ctrl++) {\n\t\tide = &ide_table[ctrl];\n\t\tfor(drv = 0; drv < NR_ATA_DRVS; drv++) {\n\t\t\tdrive = &ide->drive[drv];\n\t\t\tif(!drive->nr_sects) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif(drive->flags & DRIVE_IS_DISK) {\n\t\t\t\tmajor = (int)drive->major;\n\t\t\t\tminor = (int)drive->minor_shift;\n\t\t\t\tblocks = drive->nr_sects / 2;\n\t\t\t\tsize += sprintk(buffer + size, \"%4d  %4d  %9d %s\\n\", major, 0, blocks, drive->dev_name);\n\t\t\t\tfor(n = 0; n < NR_PARTITIONS; n++) {\n\t\t\t\t\tif(drive->part_table[n].type) {\n\t\t\t\t\t\tblocks = drive->part_table[n].nr_sects / 2;\n\t\t\t\t\t\tsize += sprintk(buffer + size, \"%4d  %4d  %9u %s%d\\n\", major, (n + 1) << minor, blocks, drive->dev_name, n + 1);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn size;\n}\n\nint data_proc_pci(char *buffer, __pid_t pid)\n{\n#ifdef CONFIG_PCI\n\tint size, n;\n\tstruct pci_device *pd;\n\n\tsize = sprintk(buffer, \"PCI devices found:\\n\");\n\tpd = pci_device_table;\n\n\twhile(pd) {\n\t\tsize += sprintk(buffer + size, \"  Bus %2d, device %3d, function %2d:\\n\", pd->bus, pd->dev, pd->func);\n\t\tsize += sprintk(buffer + size, \"    Class %04x: PCI device %04x:%04x (rev %d).\\n\", pd->class, pd->vendor_id, pd->device_id, pd->rev);\n\t\tif(pd->irq) {\n\t\t\tsize += sprintk(buffer + size, \"      IRQ %d.\\n\", pd->irq);\n\t\t}\n\t\tif(pd->hdr_type == PCI_HEADER_TYPE_NORMAL) {\n\t\t\tfor(n = 0; n < 6; n++) {\n\t\t\t\tif(pd->bar[n]) {\n\t\t\t\t\tif(pd->flags[n] & PCI_BASE_ADDR_SPACE_IO) {\n\t\t\t\t\t\tsize += sprintk(buffer + size, \"      I/O at 0x%x [0x%x].\\n\", pd->bar[n], pd->bar[n] + (pd->size[n] - 1));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif(pd->flags[n] & PCI_F_ADDR_SPACE_PREFET) {\n\t\t\t\t\t\t\tsize += sprintk(buffer + size, \"      Prefetchable \");\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tsize += sprintk(buffer + size, \"      Non-prefetchable \");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(pd->flags[n] & PCI_F_ADDR_MEM_32) {\n\t\t\t\t\t\t\tsize += sprintk(buffer + size, \"32\");\n\t\t\t\t\t\t} else if(pd->flags[n] & PCI_F_ADDR_MEM_64) {\n\t\t\t\t\t\t\tsize += sprintk(buffer + size, \"64\");\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tsize += sprintk(buffer + size, \"??\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsize += sprintk(buffer + size, \" bit memory at 0x%x [0x%x].\\n\", pd->bar[n], pd->bar[n] + (pd->size[n] - 1));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tpd = pd->next;\n\t}\n\treturn size;\n#else\n\treturn 0;\n#endif /* CONFIG_PCI */\n}\n\nint data_proc_rtc(char *buffer, __pid_t pid)\n{\n\tint size;\n\tshort int sec, min, hour;\n\tshort int day, month, year, century;\n\n\tsec = cmos_read_date(CMOS_SEC);\n\tmin = cmos_read_date(CMOS_MIN);\n\thour = cmos_read_date(CMOS_HOUR);\n\tday = cmos_read_date(CMOS_DAY);\n\tmonth = cmos_read_date(CMOS_MONTH);\n\tyear = cmos_read_date(CMOS_YEAR);\n\tcentury = cmos_read_date(CMOS_CENTURY);\n\tyear += century * 100;\n\n\tsize = 0;\n\tsize += sprintk(buffer + size, \"rtc_time\\t: %02d:%02d:%02d\\n\", hour, min, sec);\n\tsize += sprintk(buffer + size, \"rtc_date\\t: %02d-%02d-%02d\\n\", year, month, day);\n\tsec = cmos_read_date(CMOS_ASEC);\n\tmin = cmos_read_date(CMOS_AMIN);\n\thour = cmos_read_date(CMOS_AHOUR);\n\tsize += sprintk(buffer + size, \"alarm\\t\\t: %02d:%02d:%02d\\n\", hour, min, sec);\n\tsize += sprintk(buffer + size, \"DST_enable\\t: %s\\n\", cmos_read(CMOS_STATB) & CMOS_STATB_DSE ? \"yes\" : \"no\");\n\tsize += sprintk(buffer + size, \"BCD\\t\\t: %s\\n\", cmos_read(CMOS_STATB) & CMOS_STATB_DM ? \"no\" : \"yes\");\n\tsize += sprintk(buffer + size, \"24hr\\t\\t: %s\\n\", cmos_read(CMOS_STATB) & CMOS_STATB_24H ? \"yes\" : \"no\");\n\tsize += sprintk(buffer + size, \"square_wave\\t: %s\\n\", cmos_read(CMOS_STATB) & CMOS_STATB_SQWE ? \"yes\" : \"no\");\n\tsize += sprintk(buffer + size, \"alarm_IRQ\\t: %s\\n\", cmos_read(CMOS_STATB) & CMOS_STATB_AIE ? \"yes\" : \"no\");\n\tsize += sprintk(buffer + size, \"update_IRQ\\t: %s\\n\", cmos_read(CMOS_STATB) & CMOS_STATB_UIE ? \"yes\" : \"no\");\n\tsize += sprintk(buffer + size, \"periodic_IRQ\\t: %s\\n\", cmos_read(CMOS_STATB) & CMOS_STATB_PIE ? \"yes\" : \"no\");\n\tsize += sprintk(buffer + size, \"periodic_freq\\t: %s\\n\", (cmos_read(CMOS_STATA) & CMOS_STATA_IRQF) == 0x6 ? \"1024\" : \"?\");\n\tsize += sprintk(buffer + size, \"batt_status\\t: %s\\n\", cmos_read(CMOS_STATD) & CMOS_STATD_VRT ? \"okay\" : \"dead\");\n\treturn size;\n}\n\nint data_proc_stat(char *buffer, __pid_t pid)\n{\n\tint n, size;\n\tunsigned int idle;\n\tstruct interrupt *irq;\n\n\tidle = CURRENT_TICKS - (kstat.cpu_user + kstat.cpu_nice + kstat.cpu_system);\n\tsize = 0;\n\tsize += sprintk(buffer + size, \"cpu %d %d %d %d\\n\", kstat.cpu_user, kstat.cpu_nice, kstat.cpu_system, idle);\n\tsize += sprintk(buffer + size, \"disk 0 0 0 0\\n\");\n\tsize += sprintk(buffer + size, \"page 0 0\\n\");\n\tsize += sprintk(buffer + size, \"swap 0 0\\n\");\n\tsize += sprintk(buffer + size, \"intr %u\", kstat.irqs);\n\tfor(n = 0; n < NR_IRQS; n++) {\n\t\tirq = irq_table[n];\n\t\tif(irq) {\n\t\t\tsize += sprintk(buffer + size, \" %u\", irq->ticks);\n\t\t}\n\t}\n\tsize += sprintk(buffer + size, \"\\n\");\n\tsize += sprintk(buffer + size, \"ctxt %u\\n\", kstat.ctxt);\n\tsize += sprintk(buffer + size, \"btime %d\\n\", kstat.boot_time);\n\tsize += sprintk(buffer + size, \"processes %d\\n\", kstat.processes);\n\treturn size;\n}\n\nint data_proc_uptime(char *buffer, __pid_t pid)\n{\n\tstruct proc *p;\n\tunsigned int idle;\n\n\tp = &proc_table[IDLE];\n\tidle = tv2ticks(&p->usage.ru_utime);\n\tidle += tv2ticks(&p->usage.ru_stime);\n\treturn sprintk(buffer, \"%u.%02u %u.%02u\\n\", kstat.uptime, CURRENT_TICKS % HZ, idle / HZ, idle % HZ);\n}\n\nint data_proc_fullversion(char *buffer, __pid_t pid)\n{\n\treturn sprintk(buffer, \"Fiwix version %s %s\\n\", UTS_RELEASE, UTS_VERSION);\n}\n\n\nint data_proc_unix(char *buffer, __pid_t pid)\n{\n#ifdef CONFIG_NET\n\tstruct unix_info *u;\n\tstruct sockaddr_un *sun;\n\tstruct socket *s;\n\tstruct fd *fd;\n\tint size;\n\n\tsize = sprintk(buffer, \"Num       RefCount Protocol Flags    Type St Inode Path\\n\");\n\tu = unix_socket_head;\n\twhile(u) {\n\t\tsun = u->sun;\n\t\ts = u->socket;\n\t\tfd = s->fd;\n\t\tsize += sprintk(buffer + size, \"%08x: %08d %08d %08x %04d %02d % 5d %s\\n\",\n\t\t\t&s->u.unix_info,\n\t\t\tu->count,\t/* FIXME s->fd->count, */\n\t\t\t0,\n\t\t\ts->flags,\n\t\t\ts->type,\n\t\t\ts->state,\n\t\t\tfd->inode->inode,\n\t\t\tsun ? sun->sun_path : \"\");\n\t\tu = u->next;\n\t}\n\treturn size;\n#else\n\treturn 0;\n#endif /* CONFIG_NET */\n}\n\nint data_proc_pci_devices(char *buffer, __pid_t pid)\n{\n#ifdef CONFIG_PCI\n\tint size, n;\n\tstruct pci_device *pd;\n\n\tsize = 0;\n\tpd = pci_device_table;\n\n\twhile(pd) {\n\t\tsize += sprintk(buffer + size, \"%02x%02x\\t%04x%04x\\t%x\",\n\t\t\tpd->bus,\n\t\t\tPCI_DEVFN(pd->dev, pd->func),\n\t\t\tpd->vendor_id,\n\t\t\tpd->device_id,\n\t\t\tpd->irq);\n\t\tfor(n = 0; n < 6;n ++) {\n\t\t\tsize += sprintk(buffer + size, \"\\t%08x\", pd->obar[n]);\n\t\t}\n\t\tsize += sprintk(buffer + size, \"\\t%08x\", 0);\n\t\tfor(n = 0; n < 6;n ++) {\n\t\t\tsize += sprintk(buffer + size, \"\\t%08x\", pd->size[n]);\n\t\t}\n\t\tsize += sprintk(buffer + size, \"\\t%08x\", 0);\n\t\tif(pd->name) {\n\t\t\tsize += sprintk(buffer + size, \" %s\", pd->name);\n\t\t}\n\t\tsize += sprintk(buffer + size, \"\\n\");\n\t\tpd = pd->next;\n\t}\n\treturn size;\n#else\n\treturn 0;\n#endif /* CONFIG_PCI */\n}\n\nint data_proc_buffernr(char *buffer, __pid_t pid)\n{\n\treturn sprintk(buffer, \"%d\\n\", kstat.nr_buffers);\n}\n\nint data_proc_domainname(char *buffer, __pid_t pid)\n{\n\treturn sprintk(buffer, \"%s\\n\", sys_utsname.domainname);\n}\n\nint data_proc_filemax(char *buffer, __pid_t pid)\n{\n\treturn sprintk(buffer, \"%d\\n\", NR_OPENS);\n}\n\nint data_proc_filenr(char *buffer, __pid_t pid)\n{\n\tint n, nr;\n\n\tnr = 0;\n\tfor(n = 1; n < NR_OPENS; n++) {\n\t\tif(fd_table[n].count != 0) {\n\t\t\tnr++;\n\t\t}\n\t}\n\treturn sprintk(buffer, \"%d\\n\", nr);\n}\n\nint data_proc_hostname(char *buffer, __pid_t pid)\n{\n\treturn sprintk(buffer, \"%s\\n\", sys_utsname.nodename);\n}\n\nint data_proc_inodemax(char *buffer, __pid_t pid)\n{\n\treturn sprintk(buffer, \"%d\\n\", kstat.max_inodes);\n}\n\nint data_proc_inodenr(char *buffer, __pid_t pid)\n{\n\treturn sprintk(buffer, \"%d\\n\", kstat.nr_inodes);\n}\n\nint data_proc_osrelease(char *buffer, __pid_t pid)\n{\n\treturn sprintk(buffer, \"%s\\n\", UTS_RELEASE);\n}\n\nint data_proc_ostype(char *buffer, __pid_t pid)\n{\n\treturn sprintk(buffer, \"%s\\n\", UTS_SYSNAME);\n}\n\nint data_proc_version(char *buffer, __pid_t pid)\n{\n\treturn sprintk(buffer, \"%s\\n\", UTS_VERSION);\n}\n\nint data_proc_dirty_background_ratio(char *buffer, __pid_t pid)\n{\n\treturn sprintk(buffer, \"%d\\n\", BUFFER_DIRTY_RATIO);\n}\n\n\n/*\n * PID directory related functions\n * -------------------------------\n */\nint data_proc_pid_fd(char *buffer, __pid_t pid, __ino_t inode)\n{\n\tint size, ufd;\n\tstruct proc *p;\n\tstruct inode *i;\n\n\tsize = 0;\n\tufd = inode & 0xFFF;\n\tif((p = get_proc_by_pid(pid))) {\n\t\ti = fd_table[p->fd[ufd]].inode;\n\t\tsize = sprintk(buffer, \"[%02d%02d]:%d\", MAJOR(i->dev), MINOR(i->dev), i->inode);\n\t}\n\treturn size;\n}\n\nint data_proc_pid_cmdline(char *buffer, __pid_t pid)\n{\n\tint n, size;\n\tchar *arg, **argv;\n\tunsigned int addr,offset;\n\tstruct proc *p;\n\n\tsize = 0;\n\tif((p = get_proc_by_pid(pid))) {\n\t\toffset = (int)p->argv & ~PAGE_MASK;\n\t\taddr = get_mapped_addr(p, (int)p->argv) & PAGE_MASK;\n\t\taddr = P2V(addr);\n\t\targv = (char **)(addr + offset);\n\t\tfor(n = 0; n < p->argc && (int)argv[n]; n++) {\n\t\t\toffset = (int)argv[n] & ~PAGE_MASK;\n\t\t\taddr = get_mapped_addr(p, (int)argv[n]) & PAGE_MASK;\n\t\t\taddr = P2V(addr);\n\t\t\targ = (char *)(addr + offset);\n\t\t\tif(size + strlen(arg) < (PAGE_SIZE - 1)) {\n\t\t\t\tsize += sprintk(buffer + size, \"%s\", arg);\n\t\t\t\tbuffer[size++] = 0;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\treturn size;\n}\n\nint data_proc_pid_cwd(char *buffer, __pid_t pid)\n{\n\tint size;\n\tstruct proc *p;\n\tstruct inode *i;\n\n\tsize = 0;\n\tif((p = get_proc_by_pid(pid))) {\n\n\t\t/* zombie processes don't have current working directory */\n\t\tif(!p->pwd) {\n\t\t\treturn -ENOENT;\n\t\t}\n\n\t\ti = p->pwd;\n\t\tsize = sprintk(buffer, \"[%02d%02d]:%d\", MAJOR(i->rdev), MINOR(i->rdev), i->inode);\n\t}\n\treturn size;\n}\n\nint data_proc_pid_environ(char *buffer, __pid_t pid)\n{\n\tint n, size;\n\tchar *env, **envp;\n\tunsigned int addr, offset;\n\tstruct proc *p;\n\n\tsize = 0;\n\tif((p = get_proc_by_pid(pid))) {\n\t\toffset = (int)p->envp & ~PAGE_MASK;\n\t\taddr = get_mapped_addr(p, (int)p->envp) & PAGE_MASK;\n\t\taddr = P2V(addr);\n\t\tenvp = (char **)(addr + offset);\n\t\tfor(n = 0; n < p->envc && (int)envp[n]; n++) {\n\t\t\toffset = (int)envp[n] & ~PAGE_MASK;\n\t\t\taddr = get_mapped_addr(p, (int)envp[n]) & PAGE_MASK;\n\t\t\taddr = P2V(addr);\n\t\t\tenv = (char *)(addr + offset);\n\t\t\tif(size + strlen(env) < (PAGE_SIZE - 1)) {\n\t\t\t\tsize += sprintk(buffer + size, \"%s\", env);\n\t\t\t\tbuffer[size++] = 0;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\treturn size;\n}\n\nint data_proc_pid_exe(char *buffer, __pid_t pid)\n{\n\tint size;\n\tstruct proc *p;\n\tstruct inode *i;\n\n\tsize = 0;\n\tif((p = get_proc_by_pid(pid))) {\n\n\t\t/* kernel and zombie processes are programless */\n\n\t\t/*\n\t\t * This assumes that the first entry in the vma_table\n\t\t * contains the program's inode.\n\t\t */\n\t\tif(!p->vma_table || !p->vma_table->inode) {\n\t\t\treturn -ENOENT;\n\t\t}\n\n\t\ti = p->vma_table->inode;\n\t\tsize = sprintk(buffer, \"[%02d%02d]:%d\", MAJOR(i->rdev), MINOR(i->rdev), i->inode);\n\t}\n\treturn size;\n}\n\nint data_proc_pid_maps(char *buffer, __pid_t pid)\n{\n\tint size, len;\n\t__ino_t inode;\n\tint major, minor;\n\tchar *section;\n\tchar r, w, x, f;\n\tstruct proc *p;\n\tstruct vma *vma;\n\n\tsize = 0;\n\tif((p = get_proc_by_pid(pid))) {\n\t\tvma = p->vma_table;\n\t\twhile(vma) {\n\t\t\tr = vma->prot & PROT_READ ? 'r' : '-';\n\t\t\tw = vma->prot & PROT_WRITE ? 'w' : '-';\n\t\t\tx = vma->prot & PROT_EXEC ? 'x' : '-';\n\t\t\tif(vma->flags & MAP_SHARED) {\n\t\t\t\tf = 's';\n\t\t\t} else if(vma->flags & MAP_PRIVATE) {\n\t\t\t\tf = 'p';\n\t\t\t} else {\n\t\t\t\tf = '-';\n\t\t\t}\n\t\t\tswitch(vma->s_type) {\n\t\t\t\tcase P_TEXT:\tsection = \"text\";\n\t\t\t\t\t\tbreak;\n\t\t\t\tcase P_DATA:\tsection = \"data\";\n\t\t\t\t\t\tbreak;\n\t\t\t\tcase P_BSS:\tsection = \"bss\";\n\t\t\t\t\t\tbreak;\n\t\t\t\tcase P_HEAP:\tsection = \"heap\";\n\t\t\t\t\t\tbreak;\n\t\t\t\tcase P_STACK:\tsection = \"stack\";\n\t\t\t\t\t\tbreak;\n\t\t\t\tcase P_MMAP:\tsection = \"mmap\";\n\t\t\t\t\t\tbreak;\n\t\t\t\tcase P_SHM:\tsection = \"shm\";\n\t\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tsection = NULL;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tinode = major = minor = 0;\n\t\t\tif(vma->inode) {\n\t\t\t\tinode = vma->inode->inode;\n\t\t\t\tmajor = MAJOR(vma->inode->dev);\n\t\t\t\tminor = MINOR(vma->inode->dev);\n\t\t\t}\n\t\t\tlen = sprintk(buffer + size, \"%08x-%08x %c%c%c%c %08x %02d:%02d %- 10u [%s]\\n\", vma->start, vma->end, r, w, x, f, vma->offset, major, minor, inode, section);\n\t\t\tsize += len;\n\t\t\tvma = vma->next;\n\t\t}\n\t}\n\treturn size;\n}\n\nint data_proc_pid_mountinfo(char *buffer, __pid_t pid)\n{\n\tint n, size;\n\tchar *flag, *devname;\n\tstruct mount *mp;\n\n\tsize = n = 0;\n\tmp = mount_table;\n\n\twhile(mp) {\n\t\tif(mp->fs->fsop->flags != FSOP_KERN_MOUNT) {\n\t\t\tflag = mp->sb.flags & MS_RDONLY ? \"ro\" : \"rw\";\n\t\t\tdevname = mp->devname;\n\t\t\tif(!strcmp(devname, \"/dev/root\")) {\n\t\t\t\tdevname = kparms.rootdevname;\n\t\t\t}\n\t\t\tsize += sprintk(buffer + size, \"%d 0 %d:%d %s %s %s - %s %s %s\\n\", n, MAJOR(mp->dev), MINOR(mp->dev), \"/\", mp->dirname, flag, mp->fs->name, devname, flag);\n\t\t}\n\t\tn++;\n\t\tmp = mp->next;\n\t}\n\treturn size;\n}\n\nint data_proc_pid_root(char *buffer, __pid_t pid)\n{\n\tint size;\n\tstruct proc *p;\n\tstruct inode *i;\n\n\tsize = 0;\n\tif((p = get_proc_by_pid(pid))) {\n\n\t\t/* zombie processes don't have root directory */\n\t\tif(!p->root) {\n\t\t\treturn -ENOENT;\n\t\t}\n\n\t\ti = p->root;\n\t\tsize = sprintk(buffer, \"[%02d%02d]:%d\", MAJOR(i->rdev), MINOR(i->rdev), i->inode);\n\t}\n\treturn size;\n}\n\nint data_proc_pid_stat(char *buffer, __pid_t pid)\n{\n\tunsigned int esp, eip;\n\tint signum, mask;\n\t__sigset_t sigignored, sigcaught;\n\tstruct proc *p;\n\tstruct sigcontext *sc;\n\tstruct vma *vma;\n\tint size, text, data, stack, mmap;\n\n\tsize = text = data = stack = mmap = 0;\n\n\tif((p = get_proc_by_pid(pid))) {\n\t\tvma = p->vma_table;\n\t\twhile(vma) {\n\t\t\tswitch(vma->s_type) {\n\t\t\t\tcase P_TEXT:\n\t\t\t\t\ttext += vma->end - vma->start;\n\t\t\t\t\tbreak;\n\t\t\t\tcase P_HEAP:\n\t\t\t\t\tdata += vma->end - vma->start;\n\t\t\t\t\tbreak;\n\t\t\t\tcase P_STACK:\n\t\t\t\t\tstack += vma->end - vma->start;\n\t\t\t\t\tbreak;\n\t\t\t\tcase P_MMAP:\n\t\t\t\tcase P_SHM:\n\t\t\t\t\tmmap += vma->end - vma->start;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tvma = vma->next;\n\t\t}\n\n\t\tsigignored = sigcaught = 0;\n\t\tfor(signum = 0, mask = 1; signum < NSIG; signum++, mask <<= 1) {\n\t\t\tif(p->sigaction[signum].sa_handler == SIG_IGN) {\n\t\t\t\tsigignored |= mask;\n\t\t\t}\n\t\t\tif(p->sigaction[signum].sa_handler == SIG_DFL) {\n\t\t\t\tsigcaught |= mask;\n\t\t\t}\n\t\t}\n\n\t\tesp = eip = 0;\n\t\tif(p->sp) {\n\t\t\tsc = (struct sigcontext *)p->sp;\n\t\t\tesp = sc->oldesp;\n\t\t\teip = sc->eip;\n\t\t}\n\t\tsize = sprintk(buffer, \"%d (%s) %c %d %d %d %d %d %d %d %d %d %d %u %u %u %u %d %d %d %d %d %d %u %u %u %u %u %u %u %d %d %u %u %u\\n\",\n\t\t\tp->pid,\n\t\t\tp->argv0,\n\t\t\tpstate[p->state][0],\n\t\t\tp->ppid->pid, p->pgid, p->sid,\n\t\t\tp->ctty ? p->ctty->dev : 0,\n\t\t\tp->ctty ? p->ctty->pgid : - 1,\n\t\t\t0,\t\t\t/* flags */\n\t\t\t0, 0, 0, 0,\t\t/* minflt, cminflt, majflt, cmajflt */\n\t\t\ttv2ticks(&p->usage.ru_utime),\n\t\t\ttv2ticks(&p->usage.ru_stime),\n\t\t\ttv2ticks(&p->cusage.ru_utime),\n\t\t\ttv2ticks(&p->cusage.ru_stime),\n\t\t\t0,\t\t\t/* counter */\n\t\t\t0,\t\t\t/* priority */\n\t\t\t0,\t\t\t/* timeout */\n\t\t\t0,\t\t\t/* itrealvalue */\n\t\t\tp->start_time,\n\t\t\ttext + data + stack + mmap,\n\t\t\tp->rss,\n\t\t\t0x7FFFFFFF,\t\t/* rlim */\n\t\t\tp->entry_address & PAGE_MASK,\n\t\t\tp->end_code,\n\t\t\tPAGE_OFFSET - 1,\t/* startstack */\n\t\t\tesp,\t\t\t/* kstkesp */\n\t\t\teip,\t\t\t/* kstkeip */\n\t\t\tp->sigpending,\n\t\t\tp->sigblocked,\n\t\t\tsigignored,\n\t\t\tsigcaught,\n\t\t\tp->sleep_address\n\t\t);\n\t}\n\treturn size;\n}\n\nint data_proc_pid_statm(char *buffer, __pid_t pid)\n{\n\tint size;\n\tstruct proc *p;\n\tstruct vma *vma;\n\tint text, data, stack, mmap;\n\n\tsize = text = data = stack = mmap = 0;\n\tif((p = get_proc_by_pid(pid))) {\n\t\tvma = p->vma_table;\n\t\twhile(vma) {\n\t\t\tswitch(vma->s_type) {\n\t\t\t\tcase P_TEXT:\n\t\t\t\t\ttext += vma->end - vma->start;\n\t\t\t\t\tbreak;\n\t\t\t\tcase P_HEAP:\n\t\t\t\t\tdata += vma->end - vma->start;\n\t\t\t\t\tbreak;\n\t\t\t\tcase P_STACK:\n\t\t\t\t\tstack += vma->end - vma->start;\n\t\t\t\t\tbreak;\n\t\t\t\tcase P_MMAP:\n\t\t\t\tcase P_SHM:\n\t\t\t\t\tmmap += vma->end - vma->start;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tvma = vma->next;\n\t\t}\n\n\t\tsize = sprintk(buffer, \"%d\", (text + data + stack + mmap) / PAGE_SIZE);\n\t\tsize += sprintk(buffer + size, \" %d\", p->rss);\n\t\tsize += sprintk(buffer + size, \" 0\");\t/* shared mappings */\n\t\tsize += sprintk(buffer + size, \" %d\", text / PAGE_SIZE);\n\t\tsize += sprintk(buffer + size, \" 0\");\n\t\tsize += sprintk(buffer + size, \" %d\", (data + stack) / PAGE_SIZE);\n\t\tsize += sprintk(buffer + size, \" 0\\n\");\n\t}\n\treturn size;\n}\n\nint data_proc_pid_status(char *buffer, __pid_t pid)\n{\n\tint size;\n\tint signum, mask;\n\t__sigset_t sigignored, sigcaught;\n\tstruct proc *p;\n\tstruct vma *vma;\n\tint text, data, stack, mmap;\n\n\tsize = text = data = stack = mmap = 0;\n\tif((p = get_proc_by_pid(pid))) {\n\t\tvma = p->vma_table;\n\t\twhile(vma) {\n\t\t\tswitch(vma->s_type) {\n\t\t\t\tcase P_TEXT:\n\t\t\t\t\ttext += vma->end - vma->start;\n\t\t\t\t\tbreak;\n\t\t\t\tcase P_HEAP:\n\t\t\t\t\tdata += vma->end - vma->start;\n\t\t\t\t\tbreak;\n\t\t\t\tcase P_STACK:\n\t\t\t\t\tstack += vma->end - vma->start;\n\t\t\t\t\tbreak;\n\t\t\t\tcase P_MMAP:\n\t\t\t\tcase P_SHM:\n\t\t\t\t\tmmap += vma->end - vma->start;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tvma = vma->next;\n\t\t}\n\n\t\tsize = sprintk(buffer, \"Name:\\t%s\\n\", p->argv0);\n\t\tsize += sprintk(buffer + size, \"State:\\t%s\\n\", pstate[p->state]);\n\t\tsize += sprintk(buffer + size, \"Pid:\\t%d\\n\", p->pid);\n\t\tsize += sprintk(buffer + size, \"PPid:\\t%d\\n\", p->ppid->pid);\n\t\tsize += sprintk(buffer + size, \"Uid:\\t%d\\t%d\\t%d\\t-\\n\", p->uid, p->euid, p->suid);\n\t\tsize += sprintk(buffer + size, \"Gid:\\t%d\\t%d\\t%d\\t-\\n\", p->gid, p->egid, p->sgid);\n\t\tsize += sprintk(buffer + size, \"VmSize:\\t%8d kB\\n\", (text + data + stack + mmap) / 1024);\n\t\tsize += sprintk(buffer + size, \"VmLck:\\t%8d kB\\n\", 0);\n\t\tsize += sprintk(buffer + size, \"VmRSS:\\t%8d kB\\n\", p->rss << 2);\n\t\tsize += sprintk(buffer + size, \"VmData:\\t%8d kB\\n\", data / 1024);\n\t\tsize += sprintk(buffer + size, \"VmStk:\\t%8d kB\\n\", stack / 1024);\n\t\tsize += sprintk(buffer + size, \"VmExe:\\t%8d kB\\n\", text / 1024);\n\t\tsize += sprintk(buffer + size, \"VmLib:\\t%8d kB\\n\", 0);\n\t\tsize += sprintk(buffer + size, \"SigPnd:\\t%08x\\n\", p->sigpending);\n\t\tsize += sprintk(buffer + size, \"SigBlk:\\t%08x\\n\", p->sigblocked);\n\t\tsigignored = sigcaught = 0;\n\t\tfor(signum = 0, mask = 1; signum < NSIG; signum++, mask <<= 1) {\n\t\t\tif(p->sigaction[signum].sa_handler == SIG_IGN) {\n\t\t\t\tsigignored |= mask;\n\t\t\t}\n\t\t\tif(p->sigaction[signum].sa_handler == SIG_DFL) {\n\t\t\t\tsigcaught |= mask;\n\t\t\t}\n\t\t}\n\t\tsize += sprintk(buffer + size, \"SigIgn:\\t%08x\\n\", sigignored);\n\t\tsize += sprintk(buffer + size, \"SigCgt:\\t%08x\\n\", sigcaught);\n\t}\n\treturn size;\n}\n"
  },
  {
    "path": "fs/procfs/dir.c",
    "content": "/*\n * fiwix/fs/procfs/dir.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_proc.h>\n#include <fiwix/dirent.h>\n#include <fiwix/stat.h>\n#include <fiwix/mm.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstruct fs_operations procfs_dir_fsop = {\n\t0,\n\t0,\n\n\tprocfs_dir_open,\n\tprocfs_dir_close,\n\tprocfs_dir_read,\n\tNULL,\t\t\t/* write */\n\tNULL,\t\t\t/* ioctl */\n\tNULL,\t\t\t/* llseek */\n\tprocfs_readdir,\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tprocfs_bmap,\n\tprocfs_lookup,\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nstatic void free_all_fdstr(struct procfs_dir_entry *d)\n{\n\twhile(d) {\n\t\tif((d->inode & 0xF0000000) == PROC_FD_INO) {\n\t\t\tkfree((unsigned int)d->name);\n\t\t}\n\t\td++;\n\t}\n}\n\nstatic int proc_listdir(char *buffer, int count)\n{\n\tint n;\n\tstruct proc *p;\n\tstruct procfs_dir_entry *pd;\n\tstruct procfs_dir_entry d;\n\tint size;\n\n\tsize = 0;\n\tpd = (struct procfs_dir_entry *)buffer;\n\n\tFOR_EACH_PROCESS(p) {\n\t\td.inode = PROC_PID_INO + (p->pid << 12);\n\t\td.mode = S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;\n\t\td.nlink = 1;\n\t\td.lev = -1;\n\t\td.name_len = 1;\n\t\tn = p->pid;\n\t\twhile(n / 10) {\n\t\t\tn /= 10;\n\t\t\td.name_len++;\n\t\t}\n\t\td.name = p->pidstr;\n\t\td.data_fn = NULL;\n\n\t\tif(size + sizeof(struct procfs_dir_entry) > (count - 1)) {\n\t\t\tprintk(\"WARNING: kmalloc() is limited to 4096 bytes.\\n\");\n\t\t\tbreak;\n\t\t}\n\n\t\tsize += sizeof(struct procfs_dir_entry);\n\t\tmemcpy_b((void *)pd, (void *)&d, sizeof(struct procfs_dir_entry));\n\t\tpd++;\n\t\tp = p->next;\n\t}\n\treturn size;\n}\n\nstatic int proc_listfd(struct inode *i, char *buffer, int count)\n{\n\tint n;\n\tstruct proc *p;\n\tstruct procfs_dir_entry *pd;\n\tstruct procfs_dir_entry d;\n\tchar *fdstr;\n\tint size;\n\n\tsize = 0;\n\tpd = (struct procfs_dir_entry *)buffer;\n\n\tp = get_proc_by_pid((i->inode >> 12) & 0xFFFF);\n\tfor(n = 0; n < OPEN_MAX; n++) {\n\t\tif(p->fd[n]) {\n\t\t\td.inode = PROC_FD_INO + (p->pid << 12) + n;\n\t\t\td.mode = S_IFLNK | S_IRWXU;\n\t\t\td.nlink = 1;\n\t\t\td.lev = -1;\n\t\t\tif(!(fdstr = (char *)kmalloc(4 + 1))) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\td.name_len = sprintk(fdstr, \"%d\", n);\n\t\t\td.name = fdstr;\n\t\t\td.data_fn = NULL;\n\n\t\t\tif(size + sizeof(struct procfs_dir_entry) > (count - 1)) {\n\t\t\t\tprintk(\"WARNING: kmalloc() is limited to 4096 bytes.\\n\");\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tsize += sizeof(struct procfs_dir_entry);\n\t\t\tmemcpy_b((void *)pd, (void *)&d, sizeof(struct procfs_dir_entry));\n\t\t\tpd++;\n\t\t}\n\t}\n\tmemset_b((void *)pd + size, 0, sizeof(struct procfs_dir_entry));\n\treturn size;\n}\n\nstatic int dir_read(struct inode *i, struct fd *f, char *buffer, __size_t count)\n{\n\t__size_t total_read;\n\tunsigned int bytes;\n\tint len, lev;\n\tchar *buf;\n\n\tif(!(buf = (void *)kmalloc(PAGE_SIZE))) {\n\t\treturn -ENOMEM;\n\t}\n\tmemset_b(buf, 0, PAGE_SIZE);\n\n\t/* create the list of directories for each process */\n\tlen = 0;\n\tif(i->inode == PROC_ROOT_INO) {\n\t\tlen = proc_listdir(buf, count);\n\t}\n\n\t/* create the list of fds used for each process */\n\tif((i->inode & 0xF0000FFF) == PROC_PID_FD) {\n\t\tlen = proc_listfd(i, buf, count);\n\t}\n\n\t/* add the rest of static files in the main directory */\n\tlev = i->u.procfs.i_lev;\n\n\t/* calculate the size of the level without the last entry (NULL) */\n\tbytes = sizeof(procfs_array[lev]) - sizeof(struct procfs_dir_entry);\n\n\tif((len + bytes) > (count - 1)) {\n\t\tprintk(\"WARNING: %s(): len (%d) > count (%d).\\n\", __FUNCTION__, len, count);\n\t\tfree_all_fdstr((struct procfs_dir_entry *)buf);\n\t\tkfree((unsigned int)buf);\n\t\treturn 0;\n\t}\n\tmemcpy_b(buf + len, (char *)&procfs_array[lev], bytes);\n\tlen += bytes;\n\ttotal_read = f->offset = len;\n\tmemcpy_b(buffer, buf, len);\n\tkfree((unsigned int)buf);\n\treturn total_read;\n}\n\nint procfs_dir_open(struct inode *i, struct fd *f)\n{\n\tf->offset = 0;\n\treturn 0;\n}\n\nint procfs_dir_close(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\nint procfs_dir_read(struct inode *i, struct fd *f, char *buffer, __size_t count)\n{\n\treturn -EISDIR;\n}\n\nint procfs_readdir(struct inode *i, struct fd *f, struct dirent *dirent, __size_t count)\n{\n\tunsigned int offset, boffset, dirent_offset, doffset;\n\tint dirent_len;\n\t__size_t total_read;\n\tstruct procfs_dir_entry *d;\n\tint base_dirent_len;\n\tchar *buffer;\n\n\tif(!(buffer = (void *)kmalloc(PAGE_SIZE))) {\n\t\treturn -ENOMEM;\n\t}\n\n\tbase_dirent_len = sizeof(dirent->d_ino) + sizeof(dirent->d_off) + sizeof(dirent->d_reclen);\n\n\toffset = f->offset;\n\tboffset = dirent_offset = doffset = 0;\n\n\tboffset = offset & (PAGE_SIZE - 1);\t/* mod PAGE_SIZE */\n\n\ttotal_read = dir_read(i, f, buffer, PAGE_SIZE);\n\tif((count = MIN(total_read, count)) == 0) {\n\t\tkfree((unsigned int)buffer);\n\t\treturn dirent_offset;\n\t}\n\n\twhile(boffset < f->offset) {\n\t\td = (struct procfs_dir_entry *)(buffer + boffset);\n\t\tif(!d->inode) {\n\t\t\tbreak;\n\t\t}\n\t\tdirent_len = (base_dirent_len + (d->name_len + 1)) + 3;\n\t\tdirent_len &= ~3;\t/* round up */\n\t\tif((doffset + dirent_len) <= count) {\n\t\t\tboffset += sizeof(struct procfs_dir_entry);\n\t\t\toffset += sizeof(struct procfs_dir_entry);\n\t\t\tdoffset += dirent_len;\n\t\t\tdirent->d_ino = d->inode;\n\t\t\tdirent->d_off = offset;\n\t\t\tdirent->d_reclen = dirent_len;\n\t\t\tmemcpy_b(dirent->d_name, d->name, d->name_len);\n\t\t\tdirent->d_name[d->name_len] = 0;\n\t\t\tdirent = (struct dirent *)((char *)dirent + dirent_len);\n\t\t\tdirent_offset += dirent_len;\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t\tif((d->inode & 0xF0000000) == PROC_FD_INO) {\n\t\t\tkfree((unsigned int)d->name);\n\t\t}\n\t}\n\tf->offset = boffset;\n\tkfree((unsigned int)buffer);\n\treturn dirent_offset;\n}\n"
  },
  {
    "path": "fs/procfs/file.c",
    "content": "/*\n * fiwix/fs/procfs/file.c\n *\n * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_proc.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/mm.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstruct fs_operations procfs_file_fsop = {\n\t0,\n\t0,\n\n\tprocfs_file_open,\n\tprocfs_file_close,\n\tprocfs_file_read,\n\tNULL,\t\t\t/* write */\n\tNULL,\t\t\t/* ioctl */\n\tprocfs_file_llseek,\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tprocfs_bmap,\n\tNULL,\t\t\t/* lookup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nint procfs_file_open(struct inode *i, struct fd *f)\n{\n\tif(f->flags & (O_WRONLY | O_RDWR | O_TRUNC | O_APPEND)) {\n\t\treturn -EINVAL;\n\t}\n\tf->offset = 0;\n\treturn 0;\n}\n\nint procfs_file_close(struct inode *i, struct fd *f)\n{\n\treturn 0;\n}\n\nint procfs_file_read(struct inode *i, struct fd *f, char *buffer, __size_t count)\n{\n\t__size_t total_read;\n\tunsigned int boffset, bytes, size;\n\tint blksize;\n\tstruct procfs_dir_entry *d;\n\tchar *buf;\n\n\tif(!(d = get_procfs_by_inode(i))) {\n\t\treturn -EINVAL;\n\t}\n\tif(!d->data_fn) {\n\t\treturn -EINVAL;\n\t}\n\tif(!(buf = (void *)kmalloc(PAGE_SIZE))) {\n\t\treturn -ENOMEM;\n\t}\n\n\tsize = d->data_fn(buf, (i->inode >> 12) & 0xFFFF);\n\tblksize = i->sb->s_blocksize;\n\tif(f->offset > size) {\n\t\tf->offset = size;\n\t}\n\n\ttotal_read = 0;\n\n\tfor(;;) {\n\t\tcount = (f->offset + count > size) ? size - f->offset : count;\n\t\tif(!count) {\n\t\t\tbreak;\n\t\t}\n\n\t\tboffset = f->offset & (blksize - 1);\t/* mod blksize */\n\t\tbytes = blksize - boffset;\n\t\tbytes = MIN(bytes, count);\n\t\tmemcpy_b(buffer + total_read, buf + boffset, bytes);\n\t\ttotal_read += bytes;\n\t\tcount -= bytes;\n\t\tf->offset += bytes;\n\t}\n\n\tkfree((unsigned int)buf);\n\treturn total_read;\n}\n\n__loff_t procfs_file_llseek(struct inode *i, __loff_t offset)\n{\n\treturn offset;\n}\n"
  },
  {
    "path": "fs/procfs/inode.c",
    "content": "/*\n * fiwix/fs/procfs/inode.c\n *\n * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_proc.h>\n#include <fiwix/statfs.h>\n#include <fiwix/sleep.h>\n#include <fiwix/stat.h>\n#include <fiwix/sched.h>\n#include <fiwix/mm.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nint procfs_read_inode(struct inode *i)\n{\n\tint lev;\n\t__mode_t mode;\n\t__nlink_t nlink;\n\tstruct procfs_dir_entry *d;\n\n\tif((i->inode & 0xF0000FFF) == PROC_PID_INO) {\t/* dynamic PID dir */\n\t\tmode = S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;\n\t\tnlink = 3;\n\t\tlev = PROC_PID_LEV;\n\t} else {\n\t\tif((i->inode & 0xF0000000) == PROC_FD_INO) {\t/* dynamic FD symlink */\n\t\t\tmode = S_IFLNK | S_IRWXU;\n\t\t\tnlink = 1;\n\t\t\tlev = PROC_FD_LEV;\n\t\t} else {\n\t\t\tif(!(d = get_procfs_by_inode(i))) {\n\t\t\t\treturn -ENOENT;\n\t\t\t}\n\t\t\tmode = d->mode;\n\t\t\tnlink = d->nlink;\n\t\t\tlev = d->lev;\n\t\t}\n\t}\n\n\ti->i_mode = mode;\n\ti->i_uid = 0;\n\ti->i_size = 0;\n\tif(S_ISLNK(i->i_mode)) {\n\t\ti->i_size = 64;\n\t}\n\ti->i_atime = CURRENT_TIME;\n\ti->i_ctime = CURRENT_TIME;\n\ti->i_mtime = CURRENT_TIME;\n\ti->i_gid = 0;\n\ti->i_nlink = nlink;\n\ti->i_blocks = 0;\n\ti->i_flags = 0;\n\ti->state = INODE_LOCKED;\n\ti->count = 1;\n\ti->u.procfs.i_lev = lev;\n\tswitch(i->i_mode & S_IFMT) {\n\t\tcase S_IFDIR:\n\t\t\ti->fsop = &procfs_dir_fsop;\n\t\t\tbreak;\n\t\tcase S_IFREG:\n\t\t\ti->fsop = &procfs_file_fsop;\n\t\t\tbreak;\n\t\tcase S_IFLNK:\n\t\t\ti->fsop = &procfs_symlink_fsop;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tPANIC(\"invalid inode (%d) mode %08o.\\n\", i->inode, i->i_mode);\n\t}\n\tswitch(i->inode) {\n\t\tcase PROC_KMSG_INO:\n\t\t\ti->fsop = &procfs_kmsg_fsop;\n\t\t\tbreak;\n\t}\n\treturn 0;\n}\n\nint procfs_bmap(struct inode *i, __off_t offset, int mode)\n{\n\treturn i->u.procfs.i_lev;\n}\n\nvoid procfs_statfs(struct superblock *sb, struct statfs *statfsbuf)\n{\n\tstatfsbuf->f_type = PROC_SUPER_MAGIC;\n\tstatfsbuf->f_bsize = sb->s_blocksize;\n\tstatfsbuf->f_blocks = 0;\n\tstatfsbuf->f_bfree = 0;\n\tstatfsbuf->f_bavail = 0;\n\tstatfsbuf->f_files = 0;\n\tstatfsbuf->f_ffree = 0;\n\t/* statfsbuf->f_fsid = ? */\n\tstatfsbuf->f_namelen = NAME_MAX;\n}\n"
  },
  {
    "path": "fs/procfs/kmsg.c",
    "content": "/*\n * fiwix/fs/procfs/kmsg.c\n *\n * Copyright 2025, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/stat.h>\n#include <fiwix/fs.h>\n#include <fiwix/fs_proc.h>\n#include <fiwix/syslog.h>\n#include <fiwix/syscalls.h>\n#include <fiwix/string.h>\n\nstatic int kmsg_open(struct inode *i, struct fd *f)\n{\n\treturn sys_syslog(SYSLOG_OPEN, NULL, 0);\n}\n\nstatic int kmsg_close(struct inode *i, struct fd *f)\n{\n\treturn sys_syslog(SYSLOG_CLOSE, NULL, 0);\n}\n\nstatic int kmsg_read(struct inode *i, struct fd *f, char *buffer, __size_t count)\n{\n\treturn sys_syslog(SYSLOG_READ, buffer, count);\n}\n\nstatic int kmsg_select(struct inode *i, struct fd *f, int flag)\n{\n\tswitch(flag) {\n\t\tcase SEL_R:\n\t\t\tif(log_new_chars) {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tbreak;\n\t}\n\treturn 0;\n}\n\nstruct fs_operations procfs_kmsg_fsop = {\n\t0,\n\t0,\n\n\tkmsg_open,\n\tkmsg_close,\n\tkmsg_read,\n\tNULL,\t\t\t/* write */\n\tNULL,\t\t\t/* ioctl */\n\tNULL,\t\t\t/* llseek */\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tkmsg_select,\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lockup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n"
  },
  {
    "path": "fs/procfs/namei.c",
    "content": "/*\n * fiwix/fs/procfs/namei.c\n *\n * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_proc.h>\n#include <fiwix/process.h>\n#include <fiwix/stat.h>\n#include <fiwix/mm.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nint procfs_lookup(const char *name, struct inode *dir, struct inode **i_res)\n{\n\tint len, lev, ufd;\n\t__ino_t inode;\n\t__pid_t pid;\n\tstruct proc *p;\n\tstruct procfs_dir_entry *pdirent;\n\n\tpid = inode = 0;\n\tlen = strlen(name);\n\tif((dir->inode & 0xF0000000) == PROC_PID_INO) {\n\t\tpid = (dir->inode >> 12) & 0xFFFF;\n\t}\n\n\tlev = bmap(dir, 0, FOR_READING);\n\n\t/* <PID>/fd directory */\n\tif(lev == 2) {\n\t\tif(name[0] == '[') {\n\t\t\tiput(dir);\n\t\t\treturn -ENOENT;\n\t\t}\n\t\tpid = (dir->inode >> 12) & 0xFFFF;\n\t\tif(!(p = get_proc_by_pid(pid))) {\n\t\t\tiput(dir);\n\t\t\treturn -ENOENT;\n\t\t}\n\n\t\tif(name[0] == '.' && name[1] == '\\0') {\n\t\t\t*i_res = dir;\n\t\t\treturn 0;\n\t\t}\n\t\tif(name[0] == '.' && name[1] == '.') {\n\t\t\tinode = PROC_PID_INO + (p->pid << 12);\n\t\t\tif(!(*i_res = iget(dir->sb, inode))) {\n\t\t\t\tiput(dir);\n\t\t\t\treturn -EACCES;\n\t\t\t}\n\t\t\tiput(dir);\n\t\t\treturn 0;\n\t\t}\n\n\t\tufd = atoi(name);\n\t\tif(p->fd[ufd]) {\n\t\t\tinode = (PROC_FD_INO + (pid << 12)) + ufd;\n\t\t\tif(!(*i_res = iget(dir->sb, inode))) {\n\t\t\t\tiput(dir);\n\t\t\t\treturn -EACCES;\n\t\t\t}\n\t\t\tiput(dir);\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tpdirent = procfs_array[lev];\n\twhile(pdirent->inode && !inode) {\n\t\tif(len == pdirent->name_len) {\n\t\t\tif(!(strcmp(pdirent->name, name))) {\n\t\t\t\tinode = pdirent->inode;\n\t\t\t\tif(pid) {\n\t\t\t\t\tinode = (PROC_PID_INO + (pid << 12)) + (inode & 0xFFF);\n\t\t\t\t\tif(strcmp(\".\", name) == 0) {\n\t\t\t\t\t\tinode = dir->inode;\n\t\t\t\t\t}\n\t\t\t\t\tif(strcmp(\"..\", name) == 0) {\n\t\t\t\t\t\tinode = pdirent->inode;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif(inode) {\n\t\t\t/*\n\t\t\t * This prevents a deadlock in iget() when\n\t\t\t * trying to lock '.' when 'dir' is the same\n\t\t\t * directory (ls -lai <dir>).\n\t\t\t */\n\t\t\tif(inode == dir->inode) {\n\t\t\t\t*i_res = dir;\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tif(!(*i_res = iget(dir->sb, inode))) {\n\t\t\t\tiput(dir);\n\t\t\t\treturn -EACCES;\n\t\t\t}\n\t\t\tiput(dir);\n\t\t\treturn 0;\n\t\t}\n\t\tpdirent++;\n\t}\n\n\tFOR_EACH_PROCESS(p) {\n\t\tif(len == strlen(p->pidstr)) {\n\t\t\tif(!(strcmp(p->pidstr, name))) {\n\t\t\t\tinode = PROC_PID_INO + (p->pid << 12);\n\t\t\t}\n\t\t}\n\t\tif(inode) {\n\t\t\tif(!(*i_res = iget(dir->sb, inode))) {\n\t\t\t\tiput(dir);\n\t\t\t\treturn -EACCES;\n\t\t\t}\n\t\t\tiput(dir);\n\t\t\treturn 0;\n\t\t}\n\t\tp = p->next;\n\t}\n\tiput(dir);\n\treturn -ENOENT;\n}\n"
  },
  {
    "path": "fs/procfs/super.c",
    "content": "/*\n * fiwix/fs/procfs/super.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_proc.h>\n#include <fiwix/stat.h>\n#include <fiwix/mm.h>\n#include <fiwix/sched.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstruct fs_operations procfs_fsop = {\n\t0,\n\tPROC_DEV,\n\n\tNULL,\t\t\t/* open */\n\tNULL,\t\t\t/* close */\n\tNULL,\t\t\t/* read */\n\tNULL,\t\t\t/* write */\n\tNULL,\t\t\t/* ioctl */\n\tNULL,\t\t\t/* llseek */\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lookup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tprocfs_read_inode,\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tprocfs_statfs,\n\tprocfs_read_superblock,\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nint procfs_read_superblock(__dev_t dev, struct superblock *sb)\n{\n\tsuperblock_lock(sb);\n\tsb->dev = dev;\n\tsb->fsop = &procfs_fsop;\n\tsb->s_blocksize = PAGE_SIZE;\n\n\tif(!(sb->root = iget(sb, PROC_ROOT_INO))) {\n\t\tprintk(\"WARNING: %s(): unable to get root inode.\\n\", __FUNCTION__);\n\t\tsuperblock_unlock(sb);\n\t\treturn -EINVAL;\n\t}\n\tsb->root->u.procfs.i_lev = 0;\n\n\tsuperblock_unlock(sb);\n\treturn 0;\n}\n\nint procfs_init(void)\n{\n\treturn register_filesystem(\"proc\", &procfs_fsop);\n}\n"
  },
  {
    "path": "fs/procfs/symlink.c",
    "content": "/*\n * fiwix/fs/procfs/symlink.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/buffer.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_proc.h>\n#include <fiwix/mm.h>\n#include <fiwix/stat.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstruct fs_operations procfs_symlink_fsop = {\n\t0,\n\t0,\n\n\tNULL,\t\t\t/* open */\n\tNULL,\t\t\t/* close */\n\tNULL,\t\t\t/* read */\n\tNULL,\t\t\t/* write */\n\tNULL,\t\t\t/* ioctl */\n\tNULL,\t\t\t/* llseek */\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tNULL,\t\t\t/* select */\n\n\tprocfs_readlink,\n\tprocfs_followlink,\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lookup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tNULL,\t\t\t/* ialloc */\n\tNULL,\t\t\t/* ifree */\n\tNULL,\t\t\t/* statfs */\n\tNULL,\t\t\t/* read_superblock */\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nint procfs_readlink(struct inode *i, char *buffer, __size_t count)\n{\n\tint size_read;\n\tstruct procfs_dir_entry *d;\n\tchar *buf;\n\n\tif((i->inode & 0xF0000000) == PROC_FD_INO) {\n\t\tif(!(buf = (char *)kmalloc(PAGE_SIZE))) {\n\t\t\treturn -ENOMEM;\n\t\t}\n\t\tif((size_read = data_proc_pid_fd(buf, (i->inode >> 12) & 0xFFFF, i->inode))) {\n\t\t\tif(size_read > count) {\n\t\t\t\tsize_read = count;\n\t\t\t}\n\t\t\tmemcpy_b(buffer, buf, size_read);\n\t\t}\n\t\tkfree((unsigned int)buf);\n\t\treturn size_read;\n\t}\n\n\tif(!(d = get_procfs_by_inode(i))) {\n\t\treturn -EINVAL;\n\t}\n\n\tif(!d->data_fn) {\n\t\treturn -EINVAL;\n\t}\n\n\tif(!(buf = (char *)kmalloc(PAGE_SIZE))) {\n\t\treturn -ENOMEM;\n\t}\n\n\tif((size_read = d->data_fn(buf, (i->inode >> 12) & 0xFFFF)) > 0) {\n\t\tif(size_read > count) {\n\t\t\tsize_read = count;\n\t\t}\n\t\tmemcpy_b(buffer, buf, size_read);\n\t}\n\tkfree((unsigned int)buf);\n\treturn size_read;\n}\n\nint procfs_followlink(struct inode *dir, struct inode *i, struct inode **i_res)\n{\n\t__ino_t errno;\n\t__pid_t pid;\n\tstruct proc *p;\n\tint ufd;\n\n\tif(!i) {\n\t\treturn -ENOENT;\n\t}\n\tif(!(S_ISLNK(i->i_mode))) {\n\t\tprintk(\"%s(): Oops, inode '%d' is not a symlink (!?).\\n\", __FUNCTION__, i->inode);\n\t\treturn 0;\n\t}\n\n\tp = NULL;\n\tif((pid = (i->inode >> 12) & 0xFFFF)) {\n\t\tif(!(p = get_proc_by_pid(pid))) {\n\t\t\tiput(i);\n\t\t\treturn -ENOENT;\n\t\t}\n\t}\n\n\tif((i->inode & 0xF0000000) == PROC_FD_INO) {\n\t\tufd = i->inode & 0xFFF;\n\t\t*i_res = fd_table[p->fd[ufd]].inode;\n\t\tfd_table[p->fd[ufd]].inode->count++;\n\t\tiput(i);\n\t\treturn 0;\n\t}\n\n\tswitch(i->inode & 0xF0000FFF) {\n\t\tcase PROC_PID_CWD:\n\t\t\tif(!p->pwd) {\n\t\t\t\treturn -ENOENT;\n\t\t\t}\n\t\t\t*i_res = p->pwd;\n\t\t\tp->pwd->count++;\n\t\t\tiput(i);\n\t\t\tbreak;\n\t\tcase PROC_PID_EXE:\n\t\t\t/*\n\t\t\t * This assumes that the first entry in the vma_table\n\t\t\t * contains the program's inode.\n\t\t\t */\n\t\t\tif(!p->vma_table || !p->vma_table->inode) {\n\t\t\t\treturn -ENOENT;\n\t\t\t}\n\t\t\t*i_res = p->vma_table->inode;\n\t\t\tp->vma_table->inode->count++;\n\t\t\tiput(i);\n\t\t\tbreak;\n\t\tcase PROC_PID_ROOT:\n\t\t\tif(!p->root) {\n\t\t\t\treturn -ENOENT;\n\t\t\t}\n\t\t\t*i_res = p->root;\n\t\t\tp->root->count++;\n\t\t\tiput(i);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tiput(i);\n\t\t\tif((errno = parse_namei(current->pidstr, dir, i_res, NULL, FOLLOW_LINKS))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t}\n\treturn 0;\n}\n"
  },
  {
    "path": "fs/procfs/tree.c",
    "content": "/*\n * fiwix/fs/procfs/tree.c\n *\n * Copyright 2018-2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/stat.h>\n#include <fiwix/fs.h>\n#include <fiwix/fs_proc.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#define DIR\tS_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | \\\n\t\tS_IXOTH\t\t\t\t\t/* dr-xr-xr-x */\n#define DIRFD\tS_IFDIR | S_IRUSR | S_IXUSR\t\t/* dr-x------ */\n#define REG\tS_IFREG | S_IRUSR | S_IRGRP | S_IROTH\t/* -r--r--r-- */\n#define REGUSR\tS_IFREG | S_IRUSR\t\t\t/* -r-------- */\n#define LNK\tS_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO\t/* lrwxrwxrwx */\n#define LNKPID\tS_IFLNK | S_IRWXU\t\t\t/* lrwx------ */\n\n/*\n * WARNING: every time a new entry is added to this array you must also change\n * the PROC_ARRAY_ENTRIES value defined in fs_proc.h.\n */\nstruct procfs_dir_entry procfs_array[][PROC_ARRAY_ENTRIES + 1] = {\n   {\t/* [lev 0] / */\n\t{ 1,     DIR,    2, 0, 1,  \".\",   NULL },\n\t{ 2,     DIR,    2, 0, 2,  \"..\",  NULL },\n\t{ 3,     DIR,    3, 3, 3,  \"bus\", NULL },\n\t{ 4,     DIR,    2, 4, 3,  \"net\", NULL },\n\t{ 5,     DIR,    4, 5, 3,  \"sys\", NULL },\n\t{ 6,             REG,    1, 0, 9,  \"buddyinfo\",  data_proc_buddyinfo },\n\t{ 7,             REG,    1, 0, 7,  \"cmdline\",    data_proc_cmdline },\n\t{ 8,             REG,    1, 0, 7,  \"cpuinfo\",    data_proc_cpuinfo },\n\t{ 9,             REG,    1, 0, 7,  \"devices\",    data_proc_devices },\n\t{ 10,            REG,    1, 0, 3,  \"dma\",        data_proc_dma },\n\t{ 11,            REG,    1, 0, 11, \"filesystems\",data_proc_filesystems },\n\t{ 12,            REG,    1, 0, 10, \"interrupts\", data_proc_interrupts },\n\t{ PROC_KMSG_INO, REGUSR, 1, 0, 4,  \"kmsg\",       NULL },\n\t{ 14,            REG,    1, 0, 7,  \"loadavg\",    data_proc_loadavg },\n\t{ 15,            REG,    1, 0, 5,  \"locks\",      data_proc_locks },\n\t{ 16,            REG,    1, 0, 7,  \"meminfo\",    data_proc_meminfo },\n\t{ 17,            REG,    1, 0, 6,  \"mounts\",     data_proc_mounts },\n\t{ 18,            REG,    1, 0, 10, \"partitions\", data_proc_partitions },\n\t{ 19,            REG,    1, 0, 3,  \"pci\",        data_proc_pci },\n\t{ 20,            REG,    1, 0, 3,  \"rtc\",        data_proc_rtc },\n\t{ 21,            LNK,    1, 0, 4,  \"self\",       data_proc_self },\n\t{ 22,            REG,    1, 0, 4,  \"stat\",       data_proc_stat },\n\t{ 23,            REG,    1, 0, 6,  \"uptime\",     data_proc_uptime },\n\t{ 24,            REG,    1, 0, 7,  \"version\",    data_proc_fullversion },\n\t{ 0, 0, 0, 0, 0, NULL, NULL }\n   },\n   {\t/* [lev 1] /PID/ */\n\t{ 1000,  DIR,  2, 1, 1,  \".\",   NULL },\n\t{ 1,     DIR,  2, 0, 2,  \"..\",  NULL },\n\t{ PROC_PID_FD,      DIRFD,  2, 2, 2,  \"fd\",       NULL },\n\t{ PROC_PID_CMDLINE, REG,    1, 1, 7,  \"cmdline\",  data_proc_pid_cmdline },\n\t{ PROC_PID_CWD,     LNKPID, 1, 1, 3,  \"cwd\",      data_proc_pid_cwd },\n\t{ PROC_PID_ENVIRON, REGUSR, 1, 1, 7,  \"environ\",  data_proc_pid_environ },\n\t{ PROC_PID_EXE,     LNKPID, 1, 1, 3,  \"exe\",      data_proc_pid_exe },\n\t{ PROC_PID_MAPS,    REG,    1, 1, 4,  \"maps\",     data_proc_pid_maps },\n\t{ PROC_PID_MOUNTINFO,REG,   1, 1, 9,  \"mountinfo\",data_proc_pid_mountinfo },\n\t{ PROC_PID_ROOT,    LNKPID, 1, 1, 4,  \"root\",     data_proc_pid_root },\n\t{ PROC_PID_STAT,    REG,    1, 1, 4,  \"stat\",     data_proc_pid_stat },\n\t{ PROC_PID_STATM,   REG,    1, 1, 5,  \"statm\",    data_proc_pid_statm },\n\t{ PROC_PID_STATUS,  REG,    1, 1, 6,  \"status\",   data_proc_pid_status },\n\t{ 0, 0, 0, 0, 0, NULL, NULL }\n   },\n\n   {\t/* [lev 2] /PID/fd/ */\n\t{ 2000,  DIRFD,  2, 2, 1,  \".\",   NULL },\n\t{ 1000,  DIR,    2, 2, 2,  \"..\",  NULL },\n\t{ 0, 0, 0, 0, 0, NULL, NULL }\n   },\n\n   {\t/* [lev 3] /bus/ */\n\t{ 3,     DIR,  3, 3, 1,  \".\",       NULL },\n\t{ 1,     DIR,  2, 0, 2,  \"..\",      NULL },\n\t{ 3001,  DIR,  2, 6, 3,  \"pci\",     NULL },\n\t{ 0, 0, 0, 0, 0, NULL, NULL }\n   },\n   {\t/* [lev 4] /net/ */\n\t{ 4,     DIR,  2, 4, 1,  \".\",   NULL },\n\t{ 1,     DIR,  2, 0, 2,  \"..\",  NULL },\n\t{ 4001,  REG,  1, 4, 4, \"unix\", data_proc_unix },\n\t{ 0, 0, 0, 0, 0, NULL, NULL }\n   },\n   {\t/* [lev 5] /sys/ */\n\t{ 5,     DIR,  2, 5, 1,  \".\",       NULL },\n\t{ 1,     DIR,  2, 0, 2,  \"..\",      NULL },\n\t{ 5001,  DIR,  2, 7, 6,  \"kernel\",  NULL },\n\t{ 5002,  DIR,  2, 8, 2,  \"vm\",      NULL },\n\t{ 0, 0, 0, 0, 0, NULL, NULL }\n   },\n   {\t/* [3001] /bus/pci/ */\n\t{ 3001,  DIR,  2, 4, 1,  \".\",   NULL },\n\t{ 3,     DIR,  3, 3, 2,  \"..\",  NULL },\n\t{ 6001,  REG,  1, 6, 7,  \"devices\", data_proc_pci_devices },\n\t{ 0, 0, 0, 0, 0, NULL, NULL }\n   },\n   {\t/* [5001] /sys/kernel/ */\n\t{ 5001,  DIR,  2, 7, 1,  \".\",   NULL },\n\t{ 5,     DIR,  2, 3, 2,  \"..\",  NULL },\n\t{ 7001,  REG,  1, 7, 9,  \"buffer-nr\",  data_proc_buffernr },\n\t{ 7002,  REG,  1, 7, 10, \"domainname\", data_proc_domainname },\n\t{ 7003,  REG,  1, 7, 8,  \"file-max\",   data_proc_filemax },\n\t{ 7004,  REG,  1, 7, 7,  \"file-nr\",    data_proc_filenr },\n\t{ 7005,  REG,  1, 7, 8,  \"hostname\",   data_proc_hostname },\n\t{ 7006,  REG,  1, 7, 9,  \"inode-max\",  data_proc_inodemax },\n\t{ 7007,  REG,  1, 7, 8,  \"inode-nr\",   data_proc_inodenr },\n\t{ 7008,  REG,  1, 7, 9,  \"osrelease\",  data_proc_osrelease },\n\t{ 7009,  REG,  1, 7, 6,  \"ostype\",     data_proc_ostype },\n\t{ 7010,  REG,  1, 7, 7,  \"version\",    data_proc_version },\n\t{ 0, 0, 0, 0, 0, NULL, NULL }\n   },\n   {\t/* [5002] /sys/vm/ */\n\t{ 5002,  DIR,  2, 8, 1,  \".\",   NULL },\n\t{ 5,     DIR,  2, 3, 2,  \"..\",  NULL },\n\t{ 8001,  REG,  1, 8, 22, \"dirty_background_ratio\", data_proc_dirty_background_ratio },\n\t{ 0, 0, 0, 0, 0, NULL, NULL }\n   }\n};\n\nstruct procfs_dir_entry *get_procfs_by_inode(struct inode *i)\n{\n\t__ino_t inode;\n\tint n, lev;\n\tstruct procfs_dir_entry *d;\n\n\tinode = i->inode;\n\tfor(lev = 0; procfs_array[lev][0].inode; lev++) {\n\t\tif(lev == PROC_PID_LEV) {\t/* PID entries */\n\t\t\tif((i->inode & 0xF0000000) == PROC_PID_INO) {\n\t\t\t\tinode = i->inode & 0xF0000FFF;\n\t\t\t}\n\t\t}\n\t\td = procfs_array[lev];\n\t\tfor(n = 0; n < PROC_ARRAY_ENTRIES && d->inode; n++) {\n\t\t\tif(d->inode == inode) {\n\t\t\t\treturn d;\n\t\t\t}\n\t\t\td++;\n\t\t}\n\t}\n\n\treturn NULL;\n}\n"
  },
  {
    "path": "fs/script.c",
    "content": "/*\n * fiwix/fs/script.c\n *\n * Copyright 2019-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/limits.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nint script_load(char *interpreter, char *args, char *data)\n{\n\tchar *p;\n\tint n, noargs;\n\n\t/* has shebang? */\n\tif(data[0] != '#' || data[1] != '!') {\n\t\treturn -ENOEXEC;\n\t}\n\n\t/* discard possible blanks before the interpreter name */\n\tfor(n = 2; n < NAME_MAX; n++) {\n\t\tif(data[n] != ' ' && data[n] != '\\t') {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t/* get the interpreter name */\n\tp = interpreter;\n\tnoargs = 0;\n\twhile(n < NAME_MAX) {\n\t\tif(data[n] == '\\n' || data[n] == '\\0') {\n\t\t\tnoargs = 1;\n\t\t\tbreak;\n\t\t}\n\t\tif(data[n] == ' ' || data[n] == '\\t') {\n\t\t\tbreak;\n\t\t}\n\t\t*p = data[n];\n\t\tn++;\n\t\tp++;\n\t}\n\n\tif(!interpreter) {\n\t\treturn -ENOEXEC;\n\t}\n\n\n\t/* get the interpreter arguments */\n\tif(!noargs) {\n\t\tp = args;\n\t\t/* discard possible blanks before the arguments */\n\t\twhile(n < NAME_MAX) {\n\t\t\tif(data[n] != ' ' && data[n] != '\\t') {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tn++;\n\t\t}\n\t\twhile(n < NAME_MAX) {\n\t\t\tif(data[n] == '\\n' || data[n] == '\\0') {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t*p = data[n];\n\t\t\tn++;\n\t\t\tp++;\n\t\t}\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "fs/sockfs/Makefile",
    "content": "# fiwix/fs/sockfs/Makefile\n#\n# Copyright 2023, Jordi Sanfeliu. All rights reserved.\n# Distributed under the terms of the Fiwix License.\n#\n\n.c.o:\n\t$(CC) $(CFLAGS) -c -o $@ $<\n\nOBJS = super.o socket.o\n\nall:\t$(OBJS)\n\nclean:\n\trm -f *.o\n\n"
  },
  {
    "path": "fs/sockfs/socket.c",
    "content": "/*\n * fiwix/fs/sockfs/socket.c\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_sock.h>\n#include <fiwix/net.h>\n#include <fiwix/string.h>\n\n#ifdef CONFIG_NET\nint sockfs_open(struct inode *i, struct fd *f)\n{\n\treturn -ENXIO;\n}\n\nint sockfs_close(struct inode *i, struct fd *f)\n{\n\tstruct socket *s;\n\n\ts = &i->u.sockfs.sock;\n\tsock_free(s);\n\treturn 0;\n}\n\nint sockfs_read(struct inode *i, struct fd *f, char *buffer, __size_t count)\n{\n\tstruct socket *s;\n\n\ts = &i->u.sockfs.sock;\n\treturn s->ops->read(s, f, buffer, count);\n}\n\nint sockfs_write(struct inode *i, struct fd *f, const char *buffer, __size_t count)\n{\n\tstruct socket *s;\n\n\ts = &i->u.sockfs.sock;\n\treturn s->ops->write(s, f, buffer, count);\n}\n\nint sockfs_ioctl(struct inode *i, struct fd *f, int cmd, unsigned int arg)\n{\n\tstruct socket *s;\n\n\ts = &i->u.sockfs.sock;\n\treturn s->ops->ioctl(s, f, cmd, arg);\n}\n\n__loff_t sockfs_llseek(struct inode *i, __loff_t offset)\n{\n        return -ESPIPE;\n}\n\nint sockfs_select(struct inode *i, struct fd *f, int flag)\n{\n\tstruct socket *s;\n\n\ts = &i->u.sockfs.sock;\n\treturn s->ops->select(s, flag);\n}\n#endif /* CONFIG_NET */\n"
  },
  {
    "path": "fs/sockfs/super.c",
    "content": "/*\n * fiwix/fs/sockfs/super.c\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fs_sock.h>\n#include <fiwix/stat.h>\n#include <fiwix/mm.h>\n#include <fiwix/sched.h>\n#include <fiwix/string.h>\n\n#ifdef CONFIG_NET\nstatic unsigned int i_counter;\n\nstruct fs_operations sockfs_fsop = {\n\tFSOP_KERN_MOUNT,\n\tSOCK_DEV,\n\n\tsockfs_open,\n\tsockfs_close,\n\tsockfs_read,\n\tsockfs_write,\n\tsockfs_ioctl,\n\tsockfs_llseek,\n\tNULL,\t\t\t/* readdir */\n\tNULL,\t\t\t/* readdir64 */\n\tNULL,\t\t\t/* mmap */\n\tsockfs_select,\n\n\tNULL,\t\t\t/* readlink */\n\tNULL,\t\t\t/* followlink */\n\tNULL,\t\t\t/* bmap */\n\tNULL,\t\t\t/* lookup */\n\tNULL,\t\t\t/* rmdir */\n\tNULL,\t\t\t/* link */\n\tNULL,\t\t\t/* unlink */\n\tNULL,\t\t\t/* symlink */\n\tNULL,\t\t\t/* mkdir */\n\tNULL,\t\t\t/* mknod */\n\tNULL,\t\t\t/* truncate */\n\tNULL,\t\t\t/* create */\n\tNULL,\t\t\t/* rename */\n\n\tNULL,\t\t\t/* read_block */\n\tNULL,\t\t\t/* write_block */\n\n\tNULL,\t\t\t/* read_inode */\n\tNULL,\t\t\t/* write_inode */\n\tsockfs_ialloc,\n\tsockfs_ifree,\n\tNULL,\t\t\t/* statfs */\n\tsockfs_read_superblock,\n\tNULL,\t\t\t/* remount_fs */\n\tNULL,\t\t\t/* write_superblock */\n\tNULL\t\t\t/* release_superblock */\n};\n\nint sockfs_ialloc(struct inode *i, int mode)\n{\n\tstruct superblock *sb = i->sb;\n\n\tsuperblock_lock(sb);\n\ti_counter++;\n\tsuperblock_unlock(sb);\n\n\ti->i_mode = mode;\n\ti->dev = i->rdev = sb->dev;\n\ti->fsop = &sockfs_fsop;\n\ti->inode = i_counter;\n\ti->count = 1;\n\t/*\n\tif(!(i->u.sockfs.sock = (struct socket *)kmalloc(sizeof(struct socket)))) {\n\t\treturn -ENOMEM;\n\t}\n\t*/\n\tmemset_b(&i->u.sockfs.sock, 0, sizeof(struct socket));\n\treturn 0;\n}\n\nvoid sockfs_ifree(struct inode *i)\n{\n\t/*\n\tif(i->u.sockfs.sock) {\n\t\tkfree((unsigned int)i->u.sockfs.sock);\n\t}\n\t*/\n}\n\nint sockfs_read_superblock(__dev_t dev, struct superblock *sb)\n{\n\tsuperblock_lock(sb);\n\tsb->dev = dev;\n\tsb->fsop = &sockfs_fsop;\n\tsb->s_blocksize = BLKSIZE_1K;\n\ti_counter = 0;\n\tsuperblock_unlock(sb);\n\treturn 0;\n}\n\nint sockfs_init(void)\n{\n\treturn register_filesystem(\"sockfs\", &sockfs_fsop);\n}\n#endif /* CONFIG_NET */\n"
  },
  {
    "path": "fs/super.c",
    "content": "/*\n * fiwix/fs/super.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/kparms.h>\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/sleep.h>\n#include <fiwix/sched.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n#include <fiwix/mm.h>\n\nstruct mount *mount_table = NULL;\nstatic struct resource sync_resource = { 0, 0 };\n\nvoid superblock_lock(struct superblock *sb)\n{\n\tunsigned int flags;\n\n\tfor(;;) {\n\t\tSAVE_FLAGS(flags); CLI();\n\t\tif(sb->state & SUPERBLOCK_LOCKED) {\n\t\t\tRESTORE_FLAGS(flags);\n\t\t\tsleep(sb, PROC_UNINTERRUPTIBLE);\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t}\n\tsb->state |= SUPERBLOCK_LOCKED;\n\tRESTORE_FLAGS(flags);\n}\n \nvoid superblock_unlock(struct superblock *sb)\n{\n\tunsigned int flags;\n\n\tSAVE_FLAGS(flags); CLI();\n\tsb->state &= ~SUPERBLOCK_LOCKED;\n\twakeup(sb);\n\tRESTORE_FLAGS(flags);\n}\n\nstruct mount *add_mount_point(__dev_t dev, const char *devname, const char *dirname)\n{\n\tunsigned int flags;\n\tstruct mount *mp;\n\n\tif(kstat.mount_points + 1 > NR_MOUNT_POINTS) {\n\t\tprintk(\"WARNING: tried to exceed NR_MOUNT_POINTS (%d).\\n\", NR_MOUNT_POINTS);\n\t\treturn NULL;\n\t}\n\n\t/* check if this device is already mounted */\n\tif(get_superblock(dev)) {\n\t\treturn NULL;\n\t}\n\n\tif(!(mp = (struct mount *)kmalloc(sizeof(struct mount)))) {\n\t\treturn NULL;\n\t}\n\tmemset_b(mp, 0, sizeof(struct mount));\n\n\tif(!(mp->devname = (char *)kmalloc(strlen(devname) + 1))) {\n\t\tkfree((unsigned int)mp);\n\t\treturn NULL;\n\t}\n\tif(!(mp->dirname = (char *)kmalloc(strlen(dirname) + 1))) {\n\t\tkfree((unsigned int)mp->devname);\n\t\tkfree((unsigned int)mp);\n\t\treturn NULL;\n\t}\n\n\tSAVE_FLAGS(flags); CLI();\n\tif(!mount_table) {\n\t\tmount_table = mp;\n\t} else {\n\t\tmp->prev = mount_table->prev;\n\t\tmount_table->prev->next = mp;\n\t}\n\tmount_table->prev = mp;\n\tRESTORE_FLAGS(flags);\n\n\tmp->dev = dev;\n\tstrcpy(mp->devname, devname);\n\tstrcpy(mp->dirname, dirname);\n\tkstat.mount_points++;\n\treturn mp;\n}\n\nvoid del_mount_point(struct mount *mp)\n{\n\tunsigned int flags;\n\tstruct mount *tmp;\n\n\ttmp = mp;\n\n\tif(!mp->next && !mp->prev) {\n\t\tprintk(\"WARNING: %s(): trying to umount an unexistent mount point (%x, '%s', '%s').\\n\", __FUNCTION__, mp->dev, mp->devname, mp->dirname);\n\t\treturn;\n\t}\n\n\tSAVE_FLAGS(flags); CLI();\n\tif(mp->next) {\n\t\tmp->next->prev = mp->prev;\n\t}\n\tif(mp->prev) {\n\t\tif(mp != mount_table) {\n\t\t\tmp->prev->next = mp->next;\n\t\t}\n\t}\n\tif(!mp->next) {\n\t\tmount_table->prev = mp->prev;\n\t}\n\tif(mp == mount_table) {\n\t\tmount_table = mp->next;\n\t}\n\tRESTORE_FLAGS(flags);\n\n\tkfree((unsigned int)tmp->devname);\n\tkfree((unsigned int)tmp->dirname);\n\tkfree((unsigned int)tmp);\n\tkstat.mount_points--;\n}\n\nstruct mount *get_mount_point(struct inode *i)\n{\n\tstruct mount *mp;\n\n\tmp = mount_table;\n\n\twhile(mp) {\n\t\tif(S_ISDIR(i->i_mode)) {\n\t\t\tif(mp->sb.root == i) {\n\t\t\t\treturn mp;\n\t\t\t}\n\t\t}\n\t\tif(S_ISBLK(i->i_mode)) {\n\t\t\tif(mp->dev == i->rdev) {\n\t\t\t\treturn mp;\n\t\t\t}\n\t\t}\n\t\tmp = mp->next;\n\t}\n\n\treturn NULL;\n}\n\nstruct superblock *get_superblock(__dev_t dev)\n{\n\tstruct mount *mp;\n\n\tmp = mount_table;\n\n\twhile(mp) {\n\t\tif(mp->dev == dev) {\n\t\t\treturn &mp->sb;\n\t\t}\n\t\tmp = mp->next;\n\t}\n\treturn NULL;\n}\n\nvoid sync_superblocks(__dev_t dev)\n{\n\tstruct superblock *sb;\n\tstruct mount *mp;\n\n\tmp = mount_table;\n\n\tlock_resource(&sync_resource);\n\twhile(mp) {\n\t\tif(!dev || mp->dev == dev) {\n\t\t\tsb = &mp->sb;\n\t\t\tif((sb->state & SUPERBLOCK_DIRTY) && !(sb->flags & MS_RDONLY)) {\n\t\t\t\tif(sb->fsop->write_superblock(sb)) {\n\t\t\t\t\tprintk(\"WARNING: %s(): I/O error on device %d,%d while syncing superblock.\\n\", __FUNCTION__, MAJOR(sb->dev), MINOR(sb->dev));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tmp = mp->next;\n\t}\n\tunlock_resource(&sync_resource);\n}\n\n/* pseudo-filesystems are only mountable by the kernel */\nint kern_mount(__dev_t dev, struct filesystems *fs)\n{\n\tstruct mount *mp;\n\n\tif(!(mp = add_mount_point(dev, \"none\", \"none\"))) {\n\t\treturn -EBUSY;\n\t}\n\n\tif(fs->fsop->read_superblock(dev, &mp->sb)) {\n\t\tdel_mount_point(mp);\n\t\treturn -EINVAL;\n\t}\n\n\tmp->sb.dir = NULL;\n\tmp->fs = fs;\n\tfs->mp = mp;\n\treturn 0;\n}\n\nint mount_root(void)\n{\n\tstruct filesystems *fs;\n\tstruct mount *mp;\n\n\t/*\n\t * FIXME: before trying to mount the filesystem, we should first\n\t * check if '_rootdev' is a device successfully registered.\n\t */\n\n\tif(!kparms.rootdev) {\n\t\tPANIC(\"root device not defined.\\n\");\n\t}\n\n\tif(!(fs = get_filesystem(kparms.rootfstype))) {\n\t\tprintk(\"WARNING: %s(): '%s' is not a registered filesystem. Defaulting to 'ext2'.\\n\", __FUNCTION__, kparms.rootfstype);\n\t\tif(!(fs = get_filesystem(\"ext2\"))) {\n\t\t\tPANIC(\"ext2 filesystem is not registered!\\n\");\n\t\t}\n\t}\n\n\tif(!(mp = add_mount_point(kparms.rootdev, \"/dev/root\", \"/\"))) {\n\t\tPANIC(\"unable to get a free mount point.\\n\");\n\t}\n\n\tif(kparms.ro) {\n\t\tmp->sb.flags = MS_RDONLY;\n\t}\n\tif(fs->fsop->read_superblock(kparms.rootdev, &mp->sb)) {\n\t\tPANIC(\"unable to mount root filesystem on %s.\\n\", kparms.rootdevname);\n\t}\n\n\tmp->sb.root->mount_point = mp->sb.root;\n\tmp->sb.root->count++;\n\tmp->sb.dir = mp->sb.root;\n\tmp->sb.dir->count++;\n\tmp->fs = fs;\n\n\tcurrent->root = mp->sb.root;\n\tcurrent->root->count++;\n\tcurrent->pwd = mp->sb.root;\n\tcurrent->pwd->count++;\n\tiput(mp->sb.root);\n\n\tprintk(\"mounted root device (%s filesystem)\", fs->name);\n\tif(mp->sb.flags & MS_RDONLY) {\n\t\tprintk(\" in readonly mode\");\n\t}\n\tprintk(\".\\n\");\n\treturn 0;\n}\n"
  },
  {
    "path": "include/fiwix/asm.h",
    "content": "/*\n * fiwix/include/fiwix/asm.h\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_ASM_H\n#define _FIWIX_ASM_H\n\nextern void except0(void);\nextern void except1(void);\nextern void except2(void);\nextern void except3(void);\nextern void except4(void);\nextern void except5(void);\nextern void except6(void);\nextern void except7(void);\nextern void except8(void);\nextern void except9(void);\nextern void except10(void);\nextern void except11(void);\nextern void except12(void);\nextern void except13(void);\nextern void except14(void);\nextern void except15(void);\nextern void except16(void);\nextern void except17(void);\nextern void except18(void);\nextern void except19(void);\nextern void except20(void);\nextern void except21(void);\nextern void except22(void);\nextern void except23(void);\nextern void except24(void);\nextern void except25(void);\nextern void except26(void);\nextern void except27(void);\nextern void except28(void);\nextern void except29(void);\nextern void except30(void);\nextern void except31(void);\n\nextern void irq0(void);\nextern void irq1(void);\nextern void irq2(void);\nextern void irq3(void);\nextern void irq4(void);\nextern void irq5(void);\nextern void irq6(void);\nextern void irq7(void);\nextern void irq8(void);\nextern void irq9(void);\nextern void irq10(void);\nextern void irq11(void);\nextern void irq12(void);\nextern void irq13(void);\nextern void irq14(void);\nextern void irq15(void);\nextern void unknown_irq(void);\n\nextern void switch_to_user_mode(void);\nextern void sighandler_trampoline(void);\nextern void end_sighandler_trampoline(void);\nextern void syscall(void);\nextern void return_from_syscall(void);\nextern void do_switch(unsigned int *, unsigned int *, unsigned int, unsigned int, unsigned int, unsigned short int);\n\nint cpuid(void);\nint getfpu(void);\nint get_cpu_vendor_id(void);\nint signature_flags(void);\nint brand_str(void);\nint tlbinfo(void);\n\nunsigned char inport_b(unsigned int);\nunsigned short int inport_w(unsigned int);\nunsigned int inport_l(unsigned int);\nvoid inport_sw(unsigned int, void *, unsigned int);\nvoid inport_sl(unsigned int, void *, unsigned int);\nvoid outport_b(unsigned int, unsigned char);\nvoid outport_w(unsigned int, unsigned short int);\nvoid outport_l(unsigned int, unsigned int);\nvoid outport_sw(unsigned int, void *, unsigned int);\nvoid outport_sl(unsigned int, void *, unsigned int);\n\nvoid load_gdt(unsigned int);\nvoid load_idt(unsigned int);\nvoid activate_kpage_dir(void);\nvoid load_tr(unsigned int);\nunsigned long long int get_rdtsc(void);\nvoid invalidate_tlb(void);\n\n#define CLI() __asm__ __volatile__ (\"cli\":::\"memory\")\n#define STI() __asm__ __volatile__ (\"sti\":::\"memory\")\n#define NOP() __asm__ __volatile__ (\"nop\":::\"memory\")\n#define HLT() __asm__ __volatile__ (\"hlt\":::\"memory\")\n\n#define GET_CR2(cr2)\t__asm__ __volatile__ (\"movl %%cr2, %0\" : \"=r\" (cr2));\n#define GET_ESP(esp)\t__asm__ __volatile__ (\"movl %%esp, %0\" : \"=r\" (esp));\n#define SET_ESP(esp)\t__asm__ __volatile__ (\"movl %0, %%esp\" :: \"r\" (esp));\n#define GET_GS(gs)\t__asm__ __volatile__ (\"movl %%gs, %0\" : \"=r\" (gs));\n\n#define SAVE_FLAGS(flags)\t\t\t\\\n\t__asm__ __volatile__(\t\t\t\\\n\t\t\"pushfl ; popl %0\\n\\t\"\t\t\\\n\t\t: \"=r\" (flags)\t\t\t\\\n\t\t: /* no input */\t\t\\\n\t\t: \"memory\"\t\t\t\\\n\t);\n\n#define RESTORE_FLAGS(x)\t\t\t\\\n\t__asm__ __volatile__(\t\t\t\\\n\t\t\"pushl %0 ; popfl\\n\\t\"\t\t\\\n\t\t: /* no output */\t\t\\\n\t\t: \"r\" (flags)\t\t\t\\\n\t\t: \"memory\"\t\t\t\\\n\t);\n\n#ifdef __TINYC__\n/*\n * tcc loads \"r\" (register) arguments automatically into registers using this order:\n * eax, ecx, edx, ebx\n * Therefore, we rearrange the arguments so they go into the correct registers.\n */\n#define USER_SYSCALL(num, arg1, arg2, arg3)\t\\\n\t__asm__ __volatile__(\t\t\t\\\n\t\t\"int    $0x80\\n\\t\"\t\t\\\n\t\t: /* no output */\t\t\\\n\t\t: \"r\"((unsigned int)num), \"r\"((unsigned int)arg2), \"r\"((unsigned int)arg3), \"r\"((unsigned int)arg1)\t\\\n\t);\n#else\n#define USER_SYSCALL(num, arg1, arg2, arg3)\t\\\n\t__asm__ __volatile__(\t\t\t\\\n\t\t\"movl   %0, %%eax\\n\\t\"\t\t\\\n\t\t\"movl   %1, %%ebx\\n\\t\"\t\t\\\n\t\t\"movl   %2, %%ecx\\n\\t\"\t\t\\\n\t\t\"movl   %3, %%edx\\n\\t\"\t\t\\\n\t\t\"int    $0x80\\n\\t\"\t\t\\\n\t\t: /* no output */\t\t\\\n\t\t: \"eax\"((unsigned int)num), \"ebx\"((unsigned int)arg1), \"ecx\"((unsigned int)arg2), \"edx\"((unsigned int)arg3)\t\\\n\t);\n#endif\n\n/*\nstatic inline unsigned long long int get_rdtsc(void)\n{\n\tunsigned int eax, edx;\n\n\t__asm__ __volatile__(\"rdtsc\" : \"=a\" (eax), \"=d\" (edx));\n\treturn ((unsigned long long int)eax) | (((unsigned long long int)edx) << 32);\n}\n*/\n\n#endif /* _FIWIX_ASM_H */\n"
  },
  {
    "path": "include/fiwix/ata.h",
    "content": "/*\n * fiwix/include/fiwix/ata.h\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_ATA_H\n#define _FIWIX_ATA_H\n\n#include <fiwix/fs.h>\n#include <fiwix/part.h>\n#include <fiwix/sigcontext.h>\n#include <fiwix/blk_queue.h>\n#include <fiwix/timer.h>\n\n#define IDE0_IRQ\t\t14\t/* primary controller interrupt */\n#define IDE1_IRQ\t\t15\t/* secondary controller interrupt */\n\n#define IDE0_MAJOR\t\t3\t/* 1st controller major number */\n#define IDE1_MAJOR\t\t22\t/* 2nd controller major number */\n#define IDE_MINORS\t\t4\t/* max. minors/partitions per unit */\n#define IDE_MASTER_MSF\t\t0\t/* IDE master minor shift factor */\n#define IDE_SLAVE_MSF\t\t6\t/* IDE slave minor shift factor */\n\n#define IDE_PRIMARY\t\t0\n#define IDE_SECONDARY\t\t1\n#define IDE_MASTER\t\t0\n#define IDE_SLAVE\t\t1\n#define GET_DRIVE_NUM(_dev_)\t((MINOR(_dev_) & (1 <<IDE_SLAVE_MSF)) ? IDE_SLAVE : IDE_MASTER)\n\n#define NR_IDE_CTRLS\t\t2\t/* IDE controllers */\n#define NR_ATA_DRVS\t\t2\t/* max. drives per IDE controller */\n\n/* controller addresses */\n#define IDE0_BASE\t\t0x1F0\t/* primary controller base addr */\n#define IDE0_CTRL\t\t0x3F4\t/* primary controller control port */\n#define IDE1_BASE\t\t0x170\t/* secondary controller base addr */\n#define IDE1_CTRL\t\t0x374\t/* secondary controller control port */\n\n#define IDE_BASE_LEN\t\t7\t/* controller address length */\n\n#define ATA_RDY_RETR_LONG\t50000\t/* long delay for fast CPUs */\n#define ATA_RDY_RETR_SHORT\t500\t/* short delay for slow CPUs */\n#define MAX_IDE_ERR\t\t10\t/* number of retries */\n#define MAX_CD_ERR\t\t5\t/* number of retries in CDROMs */\n\n#define SET_ATA_RDY_RETR(retries)\t\t\t\t\t\\\n\tif((cpu_table.hz / 1000000) <= 100) {\t\t\t\t\\\n\t\tretries = ATA_RDY_RETR_SHORT;\t\t\t\t\\\n\t} else {\t\t\t\t\t\t\t\\\n\t\tretries = ATA_RDY_RETR_LONG;\t\t\t\t\\\n\t}\n\n#define WAIT_FOR_DISK\t(1 * HZ)\t/* timeout for hard disk */\n#define WAIT_FOR_CD \t(3 * HZ)\t/* timeout for cdrom */\n\n/* controller registers */\n#define ATA_DATA\t\t0x0\t/* Data Port Register (R/W) */\n#define ATA_ERROR\t\t0x1\t/* Error Register (R) */\n#define ATA_FEATURES\t\t0x1\t/* Features Register (W) */\n#define ATA_SECCNT\t\t0x2\t/* Sector Count Register (R/W) */\n#define ATA_SECTOR\t\t0x3\t/* Sector Number Register (R/W) */\n#define ATA_LOWLBA\t\t0x3\t/* Low Byte of LBA Register (R/W) */\n#define ATA_LCYL\t\t0x4\t/* Cylinder Low Register (R/W) */\n#define ATA_MIDLBA\t\t0x4\t/* Mid Byte of LBA Register (R/W) */\n#define ATA_HCYL\t\t0x5\t/* Cylinder High Register (R/W) */\n#define ATA_HIGHLBA\t\t0x5\t/* High Byte of LBA Register (R/W) */\n#define ATA_DRVHD\t\t0x6\t/* Drive/Head Register (R/W) */\n#define ATA_STATUS\t\t0x7\t/* Status Register (R) */\n#define ATA_COMMAND\t\t0x7\t/* Command Register (W) */\n\n#define ATA_ALT_STATUS\t\t0x2\t/* Alternate Register (R) */\n#define ATA_DEV_CTRL\t\t0x2\t/* Device Control Register (W) */\n\n/* error register bits */\n#define ATA_ERR_AMNF\t\t0x01\t/* Address Mark Not Found */\n#define ATA_ERR_TK0NF\t\t0x02\t/* Track 0 Not Found */\n#define ATA_ERR_ABRT\t\t0x04\t/* Aborted Command */\n#define ATA_ERR_MCR\t\t0x08\t/* Media Change Registered */\n#define ATA_ERR_IDNF\t\t0x10\t/* Sector ID Field Not Found */\n#define ATA_ERR_MC\t\t0x20\t/* Media Changed */\n#define ATA_ERR_UNC\t\t0x40\t/* Uncorrectable Data Error */\n#define ATA_ERR_BBK\t\t0x80\t/* Bad Block */\n\n/* status register bits */\n#define ATA_STAT_ERR\t\t0x01\t/* an error ocurred */\n#define ATA_STAT_SENS\t\t0x02\t/* sense data available */\n#define ATA_STAT_CORR\t\t0x04\t/* a correctable error ocurred */\n#define ATA_STAT_DRQ\t\t0x08\t/* device is ready to transfer */\n#define ATA_STAT_DSC\t\t0x10\t/* device requests service o intr. */\n#define ATA_STAT_DWF\t\t0x20\t/* drive write fault */\n#define ATA_STAT_RDY\t\t0x40\t/* drive is ready */\n#define ATA_STAT_BSY\t\t0x80\t/* drive is busy */\n\n#define ATA_CHS_MODE\t\t0xA0\t/* select CHS mode */\n#define ATA_LBA_MODE\t\t0xE0\t/* select LBA mode */\n\n/* alternate & device control register bits */\n#define ATA_DEVCTR_DRQ\t\t0x08\t/* Data Request */\n#define ATA_DEVCTR_NIEN\t\t0x02\t/* Disable Interrupt */\n#define ATA_DEVCTR_SRST\t\t0x04\t/* Software Reset */\n\n/* ATA I/O commands (28 bit LBA) */\n#define ATA_READ_PIO\t\t0x20\t/* read sector(s) with retries */\n#define ATA_READ_MULTIPLE_PIO\t0xC4\t/* read multiple sectors */\n#define ATA_WRITE_PIO\t\t0x30\t/* write sector(s) with retries */\n#define ATA_WRITE_MULTIPLE_PIO\t0xC5\t/* write multiple sectors */\n#define ATA_READ_DMA\t\t0xC8\t/* read data using DMA */\n#define ATA_WRITE_DMA\t\t0xCA\t/* write data using DMA */\n\n/* ATA config commands */\n#define ATA_SET_MULTIPLE_MODE\t0xC6\n#define ATA_PACKET\t\t0xA0\n#define ATA_IDENTIFY\t\t0xEC\t/* identify ATA device */\n#define ATA_SET_FEATURES\t0xEF\n\n/* ATA_SET_FEATURES subcommands */\n#define ATA_SET_XFERMODE\t0x03\t/* set transfer mode */\n#define ATA_SET_XFERMODE_UDMA\t0x40\n#define ATA_SET_XFERMODE_PIO\t0x08\n\n/* ATAPI commands */\n#define ATAPI_IDENTIFY_PACKET\t0xA1\t/* identify ATAPI device */\n#define ATAPI_TEST_UNIT\t\t0x00\n#define ATAPI_REQUEST_SENSE\t0x03\n#define ATAPI_START_STOP\t0x1B\n#define ATAPI_MEDIUM_REMOVAL\t0x1E\n#define ATAPI_GET_CAPACITY\t0x25\n#define ATAPI_READ10\t\t0x28\n\n#define CD_UNLOCK_MEDIUM\t0x00\t/* allow medium removal */\n#define CD_LOCK_MEDIUM\t\t0x01\t/* prevent medium removal */\n#define CD_EJECT\t\t0x02\t/* eject the CD if possible */\n#define CD_LOAD\t\t\t0x03\t/* load the CD (closes tray) */\n\n/* ATAPI CD additional sense code */\n#define ASC_NOT_READY\t\t0x04\n#define ASC_NO_MEDIUM\t\t0x3A\n\n/* capabilities */\n#define ATA_HAS_DMA\t\t0x100\t/* device supports DMA */\n#define ATA_HAS_LBA\t\t0x200\n#define ATA_MIN_LBA\t\t16514064/* sectors limit for using CHS */\n\n/* general configuration bits */\n#define ATA_HAS_CURR_VALUES\t0x01\t/* current logical values are valid */\n#define ATA_HAS_ADVANCED_PIO\t0x02\t/* device supports PIO 3 or 4 */\n#define ATA_HAS_UDMA\t\t0x04\t/* device supports UDMA */\n#define ATA_REMOVABLE\t\t0x80\t/* removable media device */\n\n/* ATAPI types */\n#define ATAPI_IS_SEQ_ACCESS\t0x01\t/* sequential-access device */\n#define ATAPI_IS_PRINTER\t0x02\n#define ATAPI_IS_PROCESSOR\t0x03\n#define ATAPI_IS_WRITE_ONCE\t0x04\n#define ATAPI_IS_CDROM\t\t0x05\t/* Command Packet Set is MMC-5 */\n#define ATAPI_IS_SCANNER\t0x06\n\n/* ATA drive flags */\n#define DRIVE_IS_ATAPI\t\t0x01\n#define DRIVE_IS_DISK\t\t0x02\n#define DRIVE_IS_CDROM\t\t0x04\n#define DRIVE_REQUIRES_LBA\t0x08\n#define DRIVE_HAS_RW_MULTIPLE\t0x10\n#define DRIVE_HAS_DMA\t\t0x20\n#define DRIVE_HAS_DATA32\t0x40\n\n#define PRDT_MARK_END\t\t0x8000\n#define WAKEUP_AND_RETURN\t1\n\n/* ATA/ATAPI-4 based */\nstruct ata_drv_ident {\n\tunsigned short int gen_config;\t\t/* general configuration bits */\n\tunsigned short int logic_cyls;\t\t/* logical cylinders */\n\tunsigned short int reserved2;\n\tunsigned short int logic_heads;\t\t/* logical heads */\n\tunsigned short int retired4;\n\tunsigned short int retired5;\n\tunsigned short int logic_spt;\t\t/* logical sectors/track */\n\tunsigned short int retired7;\n\tunsigned short int retired8;\n\tunsigned short int retired9;\n\tchar serial_number[20];\t\t\t/* serial number */\n\tunsigned short int vendor_spec20;\n\tunsigned short int buffer_cache;\n\tunsigned short int vendor_spec22;\t/* reserved */\n\tchar firmware_rev[8];\t\t\t/* firmware version */\n\tchar model_number[40];\t\t\t/* model number */\n\tunsigned short int rw_multiple;\n\tunsigned short int reserved48;\n\tunsigned short int capabilities;\t/* capabilities */\n\tunsigned short int reserved50;\n\tunsigned short int pio_mode;\t\t/* PIO data transfer mode*/\n\tunsigned short int dma_mode;\n\tunsigned short int fields_validity;\t/* fields validity */\n\tunsigned short int cur_log_cyls;\t/* current logical cylinders */\n\tunsigned short int cur_log_heads;\t/* current logical heads */\n\tunsigned short int cur_log_spt;\t\t/* current logical sectors/track */\n\tunsigned short int cur_capacity;\t/* current capacity in sectors */\n\tunsigned short int cur_capacity2;\t/* 32bit number */\n\tunsigned short int mult_sect_set;\t/* multiple sector settings */\n\tunsigned short int tot_sectors;\t\t/* sectors (LBA only) */\n\tunsigned short int tot_sectors2;\t/* 32bit number */\n\tunsigned short int singleword_dma;\n\tunsigned short int multiword_dma;\t/* multiword DMA settings */\n\tunsigned short int adv_pio_modes;\t/* advanced PIO modes */\n\tunsigned short int min_multiword;\t/* min. Multiword DMA transfer */\n\tunsigned short int rec_multiword;\t/* recommended Multiword DMS transfer */\n\tunsigned short int min_pio_wo_fc;\t/* min. PIO w/o flow control */\n\tunsigned short int min_pio_w_fc;\t/* min. PIO with flow control */\n\tunsigned short int reserved69;\n\tunsigned short int reserved70;\n\tunsigned short int reserved71;\n\tunsigned short int reserved72;\n\tunsigned short int reserved73;\n\tunsigned short int reserved74;\n\tunsigned short int queue_depth;\t\t/* queue depth */\n\tunsigned short int reserved76;\n\tunsigned short int reserved77;\n\tunsigned short int reserved78;\n\tunsigned short int reserved79;\n\tunsigned short int majorver;\t\t/* major version number */\n\tunsigned short int minorver;\t\t/* minor version number */\n\tunsigned short int cmdset1;\t\t/* command set supported */\n\tunsigned short int cmdset2;\t\t/* command set supported */\n\tunsigned short int cmdsf_ext;\t\t/* command set/feature sup.ext. */\n\tunsigned short int cmdsf_enable1;\t/* command s/f enabled */\n\tunsigned short int cmdsf_enable2;\t/* command s/f enabled */\n\tunsigned short int cmdsf_default;\t/* command s/f default */\n\tunsigned short int ultradma;\t\t/* ultra DMA mode */\n\tunsigned short int reserved89;\n\tunsigned short int reserved90;\n\tunsigned short int curapm;\t\t/* current APM values */\n\tunsigned short int reserved92_126[35];\n\tunsigned short int r_status_notif;\t/* removable media status notif. */\n\tunsigned short int security_status;\t/* security status */\n\tunsigned short int vendor_spec129_159[31];\n\tunsigned short int reserved160_255[96];\n};\n\nstruct prd {\n\tunsigned int addr;\t\t/* physical address of buffer */\n\tunsigned short int size;\t/* transfer size */\n\tunsigned short int eot;\t\t/* End-Of-Table mark */\n};\n\nstruct ide;\t/* needed to satisfy the reference inside xfer_data & ata_drv */\n\nstruct xfer_data {\n\t__dev_t dev;\n\t__blk_t block;\n\tchar *buffer;\n\tint blksize;\n\tint sectors_to_io;\n\t__off_t offset;\n\tint minor;\n\tint datalen;\n\tint nrsectors;\n\tint count;\n\tint retries;\n\tint max_retries;\n\tint bm_cmd;\n\tint cmd;\n\tchar *mode;\n\tint (*rw_end_fn)(struct ide *, struct xfer_data *);\n};\n\nstruct ata_xfer {\n\tvoid (*copy_read_fn)(unsigned int, void *, unsigned int);\n\tint read_cmd;\n\tvoid (*copy_write_fn)(unsigned int, void *, unsigned int);\n\tint write_cmd;\n\tchar copy_raw_factor;\t\t/* 2 for 16bit, 4 for 32bit */\n\tstruct prd prd_table;\t\t/* Physical Region Descriptor table */\n};\n\nstruct ata_drv {\n\tint num;\t\t\t/* master or slave */\n\tchar *name;\n\tchar *dev_name;\n\tunsigned char major;\t\t/* major number */\n\tunsigned int flags;\n\tint minor_shift;\t\t/* shift factor to get the real minor */\n\tint lba_cyls;\n\tint lba_heads;\n\tshort int lba_factor;\n\tunsigned int nr_sects;\t\t/* total sectors (LBA) */\n\tint pio_mode;\n\tint udma_mode;\n\tint multi;\n\tstruct fs_operations *fsop;\n\tstruct ata_drv_ident ident;\n\tstruct ata_xfer xfer;\n\tstruct xfer_data xd;\t\t/* transfer data setup */\n\tint (*read_fn)(struct ide *, struct ata_drv *, struct xfer_data *);\n\tint (*write_fn)(struct ide *, struct ata_drv *, struct xfer_data *);\n\tint (*read_end_fn)(struct ide *, struct xfer_data *);\n\tint (*write_end_fn)(struct ide *, struct xfer_data *);\n\tstruct partition part_table[NR_PARTITIONS];\n};\n\nstruct ide {\n\tint channel;\t\t\t/* primary or secondary */\n\tchar *name;\n\tint base;\t\t\t/* base address */\n\tint ctrl;\t\t\t/* control port address */\n\tint bm;\t\t\t\t/* bus master */\n\tshort int irq;\n\tint wait_interrupt;\n\tint irq_timeout;\n\tvoid *timer_fn;\n\tstruct callout_req creq;\n\tstruct pci_device *pci_dev;\n\tstruct device *device;\n\tstruct ata_drv drive[NR_ATA_DRVS];\n};\n\nextern struct ide *ide_table;\n\nvoid irq_ide0(int, struct sigcontext *);\nvoid ide0_timer(unsigned int);\nvoid irq_ide1(int, struct sigcontext *);\nvoid ide1_timer(unsigned int);\n\nvoid ata_error(struct ide *, int);\nvoid ata_delay(void);\nvoid ata_wait400ns(struct ide *);\nint ata_wait_nobusy(struct ide *);\nint ata_wait_state(struct ide *, unsigned char);\nint ata_io(struct ide *, struct ata_drv *, __off_t, int);\nvoid ata_set_timeout(struct ide *, int, int);\nvoid ata_end_request(struct ide *);\nint ata_select_drv(struct ide *, int, int, unsigned char);\nstruct ide *get_ide_controller(__dev_t);\nvoid ide_table_init(struct ide *, int);\nint ata_channel_init(struct ide *);\n\nint ata_open(struct inode *, struct fd *);\nint ata_close(struct inode *, struct fd *);\nint ata_read(__dev_t, __blk_t, char *, int);\nint ata_write(__dev_t, __blk_t, char *, int);\nint ata_ioctl(struct inode *, struct fd *, int, unsigned int);\n__loff_t ata_llseek(struct inode *, __loff_t);\nvoid ata_init(void);\n\n#endif /* _FIWIX_ATA_H */\n"
  },
  {
    "path": "include/fiwix/ata_hd.h",
    "content": "/*\n * fiwix/include/fiwix/ata_hd.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_ATA_HD_H\n#define _FIWIX_ATA_HD_H\n\n#include <fiwix/types.h>\n\n#define ATA_HD_SECTSIZE\t\t512\t/* sector size (in bytes) */\n\nint ata_hd_open(struct inode *, struct fd *);\nint ata_hd_close(struct inode *, struct fd *);\nint ata_hd_read(__dev_t, __blk_t, char *, int);\nint ata_hd_write(__dev_t, __blk_t, char *, int);\nint ata_hd_ioctl(struct inode *, struct fd *, int, unsigned int);\n__loff_t ata_hd_llseek(struct inode *, __loff_t);\nint ata_hd_init(struct ide *, struct ata_drv *);\n\n#endif /* _FIWIX_ATA_HD_H */\n"
  },
  {
    "path": "include/fiwix/ata_pci.h",
    "content": "/*\n * fiwix/include/fiwix/ata_pci.h\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_ATA_PCI_H\n#define _FIWIX_ATA_PCI_H\n\n#ifdef CONFIG_PCI\n#include <fiwix/ata.h>\n\nvoid ata_setup_dma(struct ide *, struct ata_drv *, char *, int, int);\nvoid ata_start_dma(struct ide *, struct ata_drv *);\nvoid ata_stop_dma(struct ide *, struct ata_drv *);\nint ata_pci(struct ide *);\n#endif /* CONFIG_PCI */\n\n#endif /* _FIWIX_ATA_PCI_H */\n"
  },
  {
    "path": "include/fiwix/atapi.h",
    "content": "/*\n * fiwix/include/fiwix/atapi.h\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_ATAPI_H\n#define _FIWIX_ATAPI_H\n\n#include <fiwix/ata.h>\n\nstatic char *sense_key_err[] = {\n\t\"NO SENSE\",\n\t\"RECOVERED ERROR\",\n\t\"NOT READY\",\n\t\"MEDIUM ERROR\",\n\t\"HARDWARE ERROR\",\n\t\"ILLEGAL REQUEST\",\n\t\"UNIT ATTENTION\",\n\t\"DATA PROTECT\",\n\t\"RESERVED\",\n\t\"RESERVED\",\n\t\"RESERVED\",\n\t\"ABORTED COMMAND\",\n\t\"MISCOMPARE\",\n\t\"RESERVED\"\n};\n\nenum {\n\tRS_NO_SENSE,\n\tRS_RECOVERED_ERROR,\n\tRS_NOT_READY,\n\tRS_MEDIUM_ERROR,\n\tRS_HARDWARE_ERROR,\n\tRS_ILLEGAL_REQUEST,\n\tRS_UNIT_ATTENTION,\n\tRS_DATA_PROTECT,\n\tRS_RESERVED1,\n\tRS_RESERVED2,\n\tRS_RESERVED3,\n\tRS_ABORTED_COMMAND,\n\tRS_MISCOMPARE,\n\tRS_RESERVED4\n};\n\nint send_packet_command(unsigned char *, struct ide *, struct ata_drv *, int);\nint atapi_cmd_testunit(struct ide *, struct ata_drv *);\nint atapi_cmd_reqsense(struct ide *, struct ata_drv *);\nint atapi_cmd_startstop(int, struct ide *, struct ata_drv *);\nint atapi_cmd_mediumrm(int, struct ide *, struct ata_drv *);\nint atapi_cmd_get_capacity(struct ide *, struct ata_drv *);\nint atapi_cmd_read10(struct ide *, struct ata_drv *);\n\n#endif /* _FIWIX_ATAPI_H */\n"
  },
  {
    "path": "include/fiwix/atapi_cd.h",
    "content": "/*\n * fiwix/include/fiwix/atapi_cd.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_ATAPI_CD_H\n#define _FIWIX_ATAPI_CD_H\n\n#include <fiwix/fs.h>\n\n#define ATAPI_CD_SECTSIZE\tBLKSIZE_2K\t/* sector size (in bytes) */\n\nint atapi_cd_open(struct inode *, struct fd *);\nint atapi_cd_close(struct inode *, struct fd *);\nint atapi_cd_read(__dev_t, __blk_t, char *, int);\nint atapi_cd_ioctl(struct inode *, struct fd *, int, unsigned int);\n__loff_t atapi_cd_llseek(struct inode *, __loff_t);\nint atapi_cd_init(struct ide *, struct ata_drv *);\n\n#endif /* _FIWIX_ATAPI_CD_H */\n"
  },
  {
    "path": "include/fiwix/bga.h",
    "content": "/*\n * fiwix/include/fiwix/bga.h\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifdef CONFIG_BGA\n\n#ifndef _FIWIX_BGA_H\n#define _FIWIX_BGA_H\n\n#define VBE_DISPI_IOPORT_INDEX\t\t0x01CE\n#define VBE_DISPI_IOPORT_DATA\t\t0x01CF\n\n#define VBE_DISPI_INDEX_ID\t\t0x0\n#define VBE_DISPI_INDEX_XRES\t\t0x1\n#define VBE_DISPI_INDEX_YRES\t\t0x2\n#define VBE_DISPI_INDEX_BPP\t\t0x3\n#define VBE_DISPI_INDEX_ENABLE\t\t0x4\n#define VBE_DISPI_INDEX_BANK\t\t0x5\n#define VBE_DISPI_INDEX_VIRT_WIDTH\t0x6\n#define VBE_DISPI_INDEX_VIRT_HEIGHT\t0x7\n#define VBE_DISPI_INDEX_X_OFFSET\t0x8\n#define VBE_DISPI_INDEX_Y_OFFSET\t0x9\n#define VBE_DISPI_INDEX_VIDEO_MEMORY_64K\t0xA\n\n#define VBE_DISPI_ID4\t\t\t0xB0C4\n\n#define VBE_DISPI_DISABLED\t\t0x00\n#define VBE_DISPI_ENABLED\t\t0x01\n#define VBE_DISPI_LFB_ENABLED\t\t0x40\n#define VBE_DISPI_NOCLEARMEM\t\t0x80\n\nvoid bga_init(void);\n\n#endif /* _FIWIX_BGA_H */\n\n#endif /* CONFIG_BGA */\n"
  },
  {
    "path": "include/fiwix/bios.h",
    "content": "/*\n * fiwix/include/fiwix/bios.h\n *\n * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_BIOS_H\n#define _FIWIX_BIOS_H\n\n#include <fiwix/multiboot1.h>\n\n#define NR_BIOS_MM_ENT\t\t50\t/* entries in BIOS memory map */\n\nstruct bios_mem_map {\n\tunsigned int from;\n\tunsigned int from_hi;\n\tunsigned int to;\n\tunsigned int to_hi;\n\tint type;\n};\nextern struct bios_mem_map bios_mem_map[NR_BIOS_MM_ENT];\nextern struct bios_mem_map kernel_mem_map[NR_BIOS_MM_ENT];\nextern char bios_data[256];\n\nint is_addr_in_bios_map(unsigned int);\nvoid bios_map_reserve(unsigned int, unsigned int);\nvoid bios_map_init(struct multiboot_mmap_entry *, unsigned int);\n\n#endif /* _FIWIX_BIOS_H */\n"
  },
  {
    "path": "include/fiwix/blk_queue.h",
    "content": "/*\n * fiwix/include/fiwix/blk_queue.h\n *\n * Copyright 2024, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_BLKQUEUE_H\n#define _FIWIX_BLKQUEUE_H\n\n#include <fiwix/config.h>\n#include <fiwix/types.h>\n#include <fiwix/devices.h>\n\n#define BR_PROCESSING\t1\n#define BR_COMPLETED\t2\n\n#define BRF_NOBLOCK\t1\n\nstruct blk_request {\n\tint status;\n\tint errno;\n\t__dev_t dev;\n\t__blk_t block;\n\tint size;\n\tint flags;\n\tstruct buffer *buffer;\n\tstruct device *device;\n\tint (*fn)(__dev_t, __blk_t, char *, int);\n\tint left;\n\tstruct blk_request *next;\n\tstruct blk_request *next_group;\n\tstruct blk_request *head_group;\n};\n\nvoid add_blk_request(struct blk_request *);\nint do_blk_request(struct device *, void *, struct buffer *);\nvoid run_blk_request(struct device *);\n\n#endif /* _FIWIX_BLKQUEUE_H */\n"
  },
  {
    "path": "include/fiwix/buffer.h",
    "content": "/*\n * fiwix/include/fiwix/buffer.h\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_BUFFER_H\n#define _FIWIX_BUFFER_H\n\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/blk_queue.h>\n\n/* buffer flags */\n#define BUFFER_VALID\t0x01\n#define BUFFER_LOCKED\t0x02\n#define BUFFER_DIRTY\t0x04\n\n#define BLK_READ\t1\n#define BLK_WRITE\t2\n\nstruct buffer {\n\t__dev_t dev;\t\t\t/* device number */\n\t__blk_t block;\t\t\t/* block number */\n\tint size;\t\t\t/* block size (in bytes) */\n\tint flags;\n\tchar *data;\t\t\t/* block contents */\n\tunsigned int mark;\t\t/* a mark to identify a buffer */\n\tstruct buffer *prev;\n\tstruct buffer *next;\n\tstruct buffer *prev_hash;\n\tstruct buffer *next_hash;\n\tstruct buffer *prev_free;\n\tstruct buffer *next_free;\n\tstruct buffer *prev_dirty;\n\tstruct buffer *next_dirty;\n\tstruct buffer *first_sibling;\n\tstruct buffer *next_sibling;\n\tstruct buffer *next_retained;\n};\nextern struct buffer *buffer_table;\nextern struct buffer **buffer_hash_table;\n\n/* value to be determined during system startup */\nextern unsigned int buffer_hash_table_size;\t/* size in bytes */\n\nint gbread(struct device *, struct blk_request *);\nstruct buffer *bread(__dev_t, __blk_t, int);\nvoid bwrite(struct buffer *);\nvoid brelse(struct buffer *);\nvoid sync_buffers(__dev_t);\nvoid invalidate_buffers(__dev_t);\nint reclaim_buffers(void);\nint kbdflushd(void);\nvoid buffer_init(void);\n\n#endif /* _FIWIX_BUFFER_H */\n"
  },
  {
    "path": "include/fiwix/charq.h",
    "content": "/*\n * fiwix/include/fiwix/charq.h\n *\n * Copyright 2024, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_CHARQ_H\n#define _FIWIX_CHARQ_H\n\n#define CBSIZE\t\t1024\t/* number of characters in cblock */\n#define NR_CB_QUEUE\t1\t/* number of cblocks per queue */\n\n#define LAST_CHAR(q)\t((q)->tail ? (q)->tail->data[(q)->tail->end_off - 1] : '\\0')\n\nstruct clist {\n\tunsigned short int count;\n\tunsigned short int cb_num;\n\tstruct cblock *head;\n\tstruct cblock *tail;\n};\n\nstruct cblock {\n\tunsigned short int start_off;\n\tunsigned short int end_off;\n\tunsigned char data[CBSIZE];\n\tstruct cblock *prev;\n\tstruct cblock *next;\n};\n\nint charq_putchar(struct clist *, unsigned char);\nint charq_unputchar(struct clist *);\nunsigned char charq_getchar(struct clist *);\nvoid charq_flush(struct clist *);\nint charq_room(struct clist *q);\nvoid charq_init(void);\n\n#endif /* _FIWIX_CHARQ_H */\n"
  },
  {
    "path": "include/fiwix/cmos.h",
    "content": "/*\n * fiwix/include/fiwix/cmos.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_CMOS_H\n#define _FIWIX_CMOS_H\n\n#define CMOS_INDEX\t0x70\n#define CMOS_DATA\t0x71\n\n#define CMOS_STATA_IRQF\t0x0F\t/* periodic interrupt frequency */\n#define CMOS_STATA_UIP\t0x80\t/* time update in progress */\n\n#define CMOS_STATB_DSE\t0x01\t/* enable daylight savings */\n#define CMOS_STATB_24H\t0x02\t/* 24-hour mode (0=12h, 1=24h) */\n#define CMOS_STATB_DM\t0x04\t/* time/date in binary mode (0=BCD, 1=binary) */\n#define CMOS_STATB_SQWE\t0x08\t/* enable square wave frequency */\n#define CMOS_STATB_UIE\t0x10\t/* enable update-ended interrupt */\n#define CMOS_STATB_AIE\t0x20\t/* enable alarm interrupt */\n#define CMOS_STATB_PIE\t0x40\t/* enable periodic interrupt */\n#define CMOS_STATB_SET\t0x80\t/* abort clock update */\n\n#define CMOS_STATD_VRT\t0x80\t/* valid RAM and time */\n\n/* CMOS RAM data registers */\n#define CMOS_SEC\t0x00\t/* second */\n#define CMOS_ASEC\t0x01\t/* alarm second */\n#define CMOS_MIN\t0x02\t/* minute */\n#define CMOS_AMIN\t0x03\t/* alarm minute */\n#define CMOS_HOUR\t0x04\t/* hour */\n#define CMOS_AHOUR\t0x05\t/* alarm hour */\n#define CMOS_DOW\t0x06\t/* day of week */\n#define CMOS_DAY\t0x07\t/* day */\n#define CMOS_MONTH\t0x08\t/* month */\n#define CMOS_YEAR\t0x09\t/* last two digits of year */\n#define CMOS_STATA\t0x0A\t/* status register A */\n#define CMOS_STATB\t0x0B\t/* status register B */\n#define CMOS_STATC\t0x0C\t/* status register C */\n#define CMOS_STATD\t0x0D\t/* status register D */\n#define CMOS_DIAG\t0x0E\t/* diagnostics status */\n#define CMOS_FDDTYPE\t0x10\t/* floppy disk drive type */\n#define CMOS_HDDTYPE\t0x12\t/* hard disk drive type */\n#define CMOS_CENTURY\t0x32\t/* century */\n\n/* conversions */\n#define BCD2BIN(bcd)\t(((bcd) >> 4) * 10) + ((bcd) & 0x0F)\n#define BIN2BCD(bin)\t((bin) % 10) | (((bin) / 10) << 4)\n\nint cmos_update_in_progress(void);\nunsigned char cmos_read_date(unsigned char);\nvoid cmos_write_date(unsigned char, unsigned char);\nunsigned char cmos_read(unsigned char);\nvoid cmos_write(unsigned char, unsigned char);\n\n#endif /* _FIWIX_CMOS_H */\n"
  },
  {
    "path": "include/fiwix/config.h",
    "content": "/*\n * fiwix/include/fiwix/config.h\n *\n * Copyright 2018-2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_CONFIG_H\n#define _FIWIX_CONFIG_H\n\n/* kernel tuning options */\n#define NR_PROCS\t\t64\t/* max. number of processes */\n#define NR_CALLOUTS\t\tNR_PROCS\t/* max. active callouts */\n#define NR_MOUNT_POINTS\t\t8\t/* max. number of mounted filesystems */\n#define NR_OPENS\t\t1024\t/* max. number of opened files */\n#define NR_FLOCKS\t\t(NR_PROCS * 5)\t/* max. number of flocks */\n\n#define FREE_PAGES_RATIO\t5\t/* % minimum of free memory pages */\n#define PAGE_HASH_PER_10K\t10\t/* % of % of hash buckets relative to\n\t\t\t\t\t   the number of physical pages */\n#define MAX_PAGES_HASH\t\t16\t/* max. number of pages in hash table */\n#define BUFFER_PERCENTAGE\t100\t/* % of memory for buffer cache */\n#define BUFFER_HASH_PERCENTAGE\t10\t/* % of hash buckets relative to the\n\t\t\t\t\t   size of the buffer table */\n#define NR_BUF_RECLAIM\t\t250\t/* buffers reclaimed in a single shot */\n#define BUFFER_DIRTY_RATIO\t5\t/* % of dirty buffers in buffer cache */\n#define INODE_PERCENTAGE\t5\t/* % of memory for the inode table and\n\t\t\t\t\t   hash table */\n#define INODE_HASH_PERCENTAGE\t10\t/* % of hash buckets relative to the\n\t\t\t\t\t   size of the inode table */\n\n#define MAX_PID_VALUE\t\t32767\t/* max. value for PID */\n#define SCREENS_LOG\t\t6\t/* max. number of screens in console's\n\t\t\t\t\t   scroll back */\n#define MAX_SPU_NOTICES\t\t10\t/* max. number of messages on spurious\n\t\t\t\t\t   interrupts */\n#define RAMDISK_DRIVES\t\t1\t/* num. of all-purpose ramdisk drives */\n#define NR_SYSCONSOLES\t\t1\t/* max. number of system consoles */\n\n\n/* toggle configuration options */\n#define CONFIG_PCI\n#define CONFIG_PCI_NAMES\n#undef CONFIG_SYSCALL_6TH_ARG\n#define CONFIG_SYSVIPC\n#define CONFIG_BGA\n#undef CONFIG_KEXEC\n#define CONFIG_OFFSET64\n#undef CONFIG_VM_SPLIT22\n#undef CONFIG_FS_MINIX\n#undef CONFIG_MMAP2\n#define CONFIG_NET\n#define CONFIG_PRINTK64\n#define CONFIG_PSAUX\n#define CONFIG_UNIX98_PTYS\n\n\n/* configuration options to help debugging */\n#define CONFIG_VERBOSE_SEGFAULTS\n#undef CONFIG_QEMU_DEBUGCON\n\n\n#ifdef CUSTOM_CONFIG_H\n#include <fiwix/custom_config.h>\n#endif\n\n#endif /* _FIWIX_CONFIG_H */\n"
  },
  {
    "path": "include/fiwix/console.h",
    "content": "/*\n * fiwix/include/fiwix/console.h\n *\n * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_CONSOLE_H\n#define _FIWIX_CONSOLE_H\n\n#include <fiwix/vt.h>\n\n#define NR_VCONSOLES\t\t12\t/* number of virtual consoles */\n\n#define VCONSOLES_MAJOR\t\t4\t/* virtual consoles major number */\n#define SYSCON_MAJOR\t\t5\t/* system console major number */\n\n/* Graphic Rendition Combination Modes */\n#define SGR_DEFAULT\t\t0\t/* back to the default rendition */\n#define SGR_BOLD\t\t1\t/* set bold */\n#define SGR_BLINK\t\t5\t/* set slowly blinking */\n#define SGR_REVERSE\t\t7\t/* set reverse video */\n#define SGR_BOLD_OFF\t\t21\t/* unset bold */\n#define SGR_BLINK_OFF\t\t25\t/* unset blinking */\n#define SGR_REVERSE_OFF\t\t27\t/* unset reverse video */\n\n#define SGR_BLACK_FG\t\t30\t/* set black foreground */\n#define SGR_RED_FG\t\t31\t/* set red foreground */\n#define SGR_GREEN_FG\t\t32\t/* set green foreground */\n#define SGR_BROWN_FG\t\t33\t/* set brown foreground */\n#define SGR_BLUE_FG\t\t34\t/* set blue foreground */\n#define SGR_MAGENTA_FG\t\t35\t/* set magenta foreground */\n#define SGR_CYAN_FG\t\t36\t/* set cyan foreground */\n#define SGR_WHITE_FG\t\t37\t/* set white foreground */\n\n#define SGR_DEFAULT_FG_U_ON\t38\t/* set def. fg color (underline on) */\n#define SGR_DEFAULT_FG_U_OFF\t39\t/* set def. fg color (underline off) */\n\n#define SGR_BLACK_BG\t\t40\t/* set black background */\n#define SGR_RED_BG\t\t41\t/* set red background */\n#define SGR_GREEN_BG\t\t42\t/* set green background */\n#define SGR_BROWN_BG\t\t43\t/* set brown background */\n#define SGR_BLUE_BG\t\t44\t/* set blue background */\n#define SGR_MAGENTA_BG\t\t45\t/* set magenta background */\n#define SGR_CYAN_BG\t\t46\t/* set cyan background */\n#define SGR_WHITE_BG\t\t47\t/* set white background */\n\n#define SGR_DEFAULT_BG\t\t49\t/* set default background color */\n\n#define NPARMS\t\t\t16\n#define BLANK_INTERVAL\t(0 * HZ)\t/* 0 seconds (no screen blank) */\n\n#define COLOR_BLACK\t\t0x0000\n#define COLOR_BLUE\t\t0x0100\n#define COLOR_GREEN\t\t0x0200\n#define COLOR_CYAN\t\t0x0300\n#define COLOR_RED\t\t0x0400\n#define COLOR_MAGENTA\t\t0x0500\n#define COLOR_BROWN\t\t0x0600\n#define COLOR_WHITE\t\t0x0700\n#define BG_BLACK\t\t0x0000\n#define BG_BLUE\t\t\t0x1000\n#define BG_GREEN\t\t0x2000\n#define BG_CYAN\t\t\t0x3000\n#define BG_RED\t\t\t0x4000\n#define BG_MAGENTA\t\t0x5000\n#define BG_BROWN\t\t0x6000\n#define BG_WHITE\t\t0x7000\n\n#define DEF_MODE\t\t(COLOR_WHITE | BG_BLACK)\n#define BLANK_MEM\t\t(DEF_MODE | ' ')\n\n#define SCREEN_COLS\t\tvideo.columns\n#define SCREEN_LINES\t\tvideo.lines\n#define SCREEN_SIZE\t\t(video.columns * video.lines)\n#define VC_BUF_LINES\t\t(video.lines * SCREENS_LOG)\n#define VC_BUF_SIZE\t\t(video.columns * VC_BUF_LINES)\n\n#define SCROLL_UP\t\t1\n#define SCROLL_DOWN\t\t2\n\n#define BS\t\t\t127\t/* backspace */\n\n#define VPF_VGA\t\t\t0x01\t/* VGA text mode */\n#define VPF_VESAFB\t\t0x02\t/* x86 framebuffer */\n#define VPF_CURSOR_ON\t\t0x04\t/* draw cursor */\n\n#define ON\t\t\t1\n#define OFF\t\t\t0\n#define COND\t\t\t2\n\n/* console flags */\n#define CONSOLE_HAS_FOCUS       0x0001\n#define CONSOLE_BLANKED         0x0002\n\n\nextern short int current_cons;\t/* current console (/dev/tty1 ... /dev/tty12) */\n\nextern short int *vc_screen[NR_VCONSOLES + 1];\n\n/*\n * This is the scrollback history buffer which is used only in the active\n * vconsole. Everytime a vconsole is switched, the screen contents of the\n * new vconsole is copied back to this buffer. Only the visible screen is\n * copied, so switching vconsoles means losing the scrollback history.\n */\nextern short int *vcbuf;\n\nstruct vconsole {\n\tint x;\t\t/* current column */\n\tint y;\t\t/* current line */\n\tint top, lines, columns;\n\tshort int check_x;\n\tunsigned char led_status;\n\tunsigned char scrlock, numlock, capslock;\n\tunsigned char esc, sbracket, semicolon, question;\n\tint flags;\n\tint parmv1, parmv2;\n\tint nparms, parms[NPARMS];\n\tunsigned short int color_attr;\n\tunsigned char bold, underline, blink, reverse;\n\tunsigned char *vidmem;\t/* write here only when console has focus */\n\tshort int *screen;\t/* the back-buffer of the screen */\n\tint saved_x, cursor_x;\n\tint saved_y, cursor_y;\n\tstruct vt_mode vt_mode;\n\tunsigned char vc_mode;\n\tint switchto_tty;\n\tstruct tty *tty;\n};\n\nstruct video_parms {\n\tstruct pci_device *pci_dev;\n\tint flags;\n\tunsigned int *address;\n\tint port;\n\tint memsize;\n\tunsigned char signature[32];\n\tint columns;\n\tint lines;\n\tint buf_y;\n\tint buf_top;\n\tint fb_version;\n\tint fb_width;\n\tint fb_height;\n\tint fb_char_width;\n\tint fb_char_height;\n\tint fb_bpp;\n\tint fb_pixelwidth;\n\tint fb_pitch;\n\tint fb_linesize;\n\tint fb_size;\t/* size of screen based on resolution */\n\tint fb_vsize;\t/* size of screen based on columns x lines */\n\n\t/* video driver operations */\n\tvoid (*put_char)(struct vconsole *, unsigned char);\n\tvoid (*insert_char)(struct vconsole *);\n\tvoid (*delete_char)(struct vconsole *);\n\tvoid (*update_curpos)(struct vconsole *);\n\tvoid (*show_cursor)(struct vconsole *, int);\n\tvoid (*get_curpos)(struct vconsole *);\n\tvoid (*write_screen)(struct vconsole *, int, int, short int);\n\tvoid (*blank_screen)(struct vconsole *);\n\tvoid (*scroll_screen)(struct vconsole *, int, int);\n\tvoid (*restore_screen)(struct vconsole *);\n\tvoid (*screen_on)(struct vconsole *);\n\tvoid (*buf_scroll)(struct vconsole *, int);\n\tvoid (*cursor_blink)(unsigned int);\n};\nextern struct video_parms video;\n\nvoid vconsole_reset(struct tty *);\nvoid vconsole_write(struct tty *);\nvoid vconsole_select(int);\nvoid vconsole_select_final(int);\nvoid vconsole_restore(struct vconsole *);\nvoid unblank_screen(struct vconsole *);\nvoid vconsole_start(struct tty *);\nvoid vconsole_stop(struct tty *);\nvoid vconsole_beep(void);\nvoid vconsole_deltab(struct tty *);\nvoid console_flush_log_buf(char *, unsigned int);\nvoid console_init(void);\n\n#endif /* _FIWIX_CONSOLE_H */\n"
  },
  {
    "path": "include/fiwix/cpu.h",
    "content": "/*\n * fiwix/include/fiwix/cpu.h\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_CPU_H\n#define _FIWIX_CPU_H\n\n#define CPU_FPU\t\t0x00000001\t/* Floating-Point Unit on chip */\n#define CPU_VME\t\t0x00000002\t/* Virtual 8086 Mode Enhancements */\n#define CPU_DE\t\t0x00000004\t/* Debugging Extensions */\n#define CPU_PSE\t\t0x00000008\t/* Page Size Extension */\n#define CPU_TSC\t\t0x00000010\t/* Time Stamp Counter */\n#define CPU_MSR\t\t0x00000020\t/* Model Specific Registers */\n#define CPU_PAE\t\t0x00000040\t/* Physical Address Extension */\n#define CPU_MCE\t\t0x00000080\t/* Machine Check Exception */\n#define CPU_CX8\t\t0x00000100\t/* CMPXCHG8B instruction supported */\n#define CPU_APIC\t0x00000200\t/* On-chip APIC hardware supported */\n#define CPU_RES10\t0x00000400\t/* Reserved */\n#define CPU_SEP\t\t0x00000800\t/* Fast System Call */\n#define CPU_MTRR\t0x00001000\t/* Memory Type Range Registers */\n#define CPU_PGE\t\t0x00002000\t/* Page Global Enable */\n#define CPU_MCA\t\t0x00004000\t/* Machine Check Architecture */\n#define CPU_CMOV\t0x00008000\t/* Conditional Move Instruction */\n#define CPU_PAT\t\t0x00010000\t/* Page Attribute Table */\n#define CPU_PSE36\t0x00020000\t/* 36-bit Page Size Extension */\n#define CPU_PSN\t\t0x00040000\t/* Processor Serial Number */\n#define CPU_CLFSH\t0x00080000\t/* CLFLUSH instruction supported */\n#define CPU_RES20\t0x00100000\t/* Reserved */\n#define CPU_DS\t\t0x00200000\t/* Debug Store */\n#define CPU_ACPI\t0x00400000\t/* Thermal Monitor and others */\n#define CPU_MMX\t\t0x00800000\t/* Intel Architecture MMX Technology */\n#define CPU_FXSR\t0x01000000\t/* Fast Floating Point Save and Rest. */\n#define CPU_SSE\t\t0x02000000\t/* Streaming SIMD Extensions */\n#define CPU_SSE2\t0x04000000\t/* Streaming SIMD Extensions 2 */\n#define CPU_SS\t\t0x08000000\t/* Self-Snoop */\n#define CPU_HTT\t\t0x10000000\t/* Hyper-Threading Technology */\n#define CPU_TM\t\t0x20000000\t/* Thermal Monitor */\n#define CPU_RES30\t0x40000000\t/* Reserved */\n#define CPU_PBE\t\t0x80000000\t/* Pending Break Enable */\n\n#define RESERVED_DESC\t0x80000000\t/* TLB descriptor reserved */\n\nstruct cpu {\n\tchar *vendor_id;\n\tchar family;\n\tchar model;\n\tchar *model_name;\n\tchar stepping;\n\tunsigned int hz;\n\tchar *cache;\n\tchar has_cpuid;\n\tchar has_fpu;\n\tint flags;\n};\nextern struct cpu cpu_table;\n\nstruct cpu_type {\n\tint cpu;\n\tchar *name[20];\n};\n\nint get_cpu_flags(char *);\nvoid cpu_init(void);\n\n#endif /* _FIWIX_CPU_H */\n"
  },
  {
    "path": "include/fiwix/ctype.h",
    "content": "/*\n * fiwix/include/fiwix/ctype.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_CTYPE_H\n#define _FIWIX_CTYPE_H\n\n#define _U\t0x01    /* upper case */\n#define _L\t0x02    /* lower case */\n#define _N\t0x04    /* numeral (digit) */\n#define _S\t0x08    /* spacing character */\n#define _P\t0x10    /* punctuation */\n#define _C\t0x20    /* control character */\n#define _X\t0x40    /* hexadecimal */\n#define _B\t0x80    /* blank */\n\nextern unsigned char _ctype[];\n\n#define ISALPHA(ch)\t((_ctype + 1)[ch] & (_U | _L))\n#define ISUPPER(ch)\t((_ctype + 1)[ch] & _U)\n#define ISLOWER(ch)\t((_ctype + 1)[ch] & _L)\n#define ISDIGIT(ch)\t((_ctype + 1)[ch] & _N)\n#define ISALNUM(ch)\t((_ctype + 1)[ch] & (_U | _L | _N))\n#define ISSPACE(ch)\t((_ctype + 1)[ch] & _S)\n#define ISPUNCT(ch)\t((_ctype + 1)[ch] & _P)\n#define ISCNTRL(ch)\t((_ctype + 1)[ch] & _C)\n#define ISXDIGIT(ch)\t((_ctype + 1)[ch] & (_N | _X))\n#define ISPRINT(ch)\t((_ctype + 1)[ch] & (_P | _U | _L | _N | _S))\n\n#define ISASCII(ch)\t((unsigned) ch <= 0x7F)\n#define TOASCII(ch)\t((unsigned) ch & 0x7F)\n\n#define TOUPPER(ch)\t((ch) & ~32)\n#define TOLOWER(ch)\t((ch) | 32)\n\n#endif /* _FIWIX_CTYPE_H */\n"
  },
  {
    "path": "include/fiwix/devices.h",
    "content": "/*\n * fiwix/include/fiwix/devices.h\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_DEVICES_H\n#define _FIWIX_DEVICES_H\n\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n\n#define NR_BLKDEV\t255\t/* maximum number of block devices */\n#define NR_CHRDEV\t255\t/* maximum number of char devices */\n#define BLK_DEV\t\t1\t/* block device */\n#define CHR_DEV\t\t2\t/* character device */\n#define MAX_MINORS\t256\t/* maximum number of minors per device */\n#define MINOR_BITS\t(MAX_MINORS / (sizeof(unsigned int) * 8))\n\n#define SET_MINOR(minors, bit)   ((minors[(bit) / 32]) |= (1 << ((bit) % 32)))\n#define CLEAR_MINOR(minors, bit) ((minors[(bit) / 32]) &= ~(1 << ((bit) % 32)))\n#define TEST_MINOR(minors, bit)\t ((minors[(bit) / 32]) & (1 << ((bit) % 32)))\n\nstruct device {\n\tchar *name;\n\tunsigned char major;\n\tunsigned int minors[MINOR_BITS];/* bitmap of MAX_MINORS bits */\n\tunsigned int *blksize;\t\t/* default minor blocksizes, in KB */\n\tvoid *device_data;\t\t/* mostly used for minor sizes, in KB */\n\tstruct fs_operations *fsop;\n\tvoid *requests_queue;\n\tvoid *xfer_data;\n\tstruct device *next;\n};\n\nextern struct device *chr_device_table[NR_CHRDEV];\nextern struct device *blk_device_table[NR_BLKDEV];\n\nint register_device(int, struct device *);\nvoid unregister_device(int, struct device *);\nstruct device *get_device(int, __dev_t);\nint chr_dev_open(struct inode *, struct fd *);\nint blk_dev_open(struct inode *, struct fd *);\nint blk_dev_close(struct inode *, struct fd *);\nint blk_dev_read(struct inode *, struct fd *, char *, __size_t);\nint blk_dev_write(struct inode *, struct fd *, const char *, __size_t);\nint blk_dev_ioctl(struct inode *, struct fd *, int, unsigned int);\n__loff_t blk_dev_llseek(struct inode *, __loff_t);\n\nvoid dev_init(void);\n\n#endif /* _FIWIX_DEVICES_H */\n"
  },
  {
    "path": "include/fiwix/dirent.h",
    "content": "/*\n * fiwix/include/fiwix/dirent.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_DIRENT_H\n#define _FIWIX_DIRENT_H\n\n#include <fiwix/types.h>\n#include <fiwix/limits.h>\n\nstruct dirent {\n\t__ino_t d_ino;\t\t\t/* inode number */\n\t__off_t d_off;\t\t\t/* offset to next dirent */\n\tunsigned short int d_reclen;\t/* length of this dirent */\n\tchar d_name[NAME_MAX + 1];\t/* file name (null-terminated) */\n};\n\nstruct dirent64 {\n\t__ino64_t d_ino;\t\t/* inode number */\n\t__loff_t d_off;\t\t\t/* offset to next dirent */\n\tunsigned short d_reclen;\t/* length of this dirent */\n\tunsigned char d_type;\t\t/* file type */\n\tchar d_name[];\t\t\t/* file name (null-terminated) */\n};\n\n#define DT_UNKNOWN 0\n#define DT_FIFO 1\n#define DT_CHR 2\n#define DT_DIR 4\n#define DT_BLK 6\n#define DT_REG 8\n#define DT_LNK 10\n#define DT_SOCK 12\n#define DT_WHT 14\n\n#endif /* _FIWIX_DIRENT_H */\n"
  },
  {
    "path": "include/fiwix/dma.h",
    "content": "/*\n * fiwix/include/fiwix/dma.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_DMA_H\n#define _FIWIX_DMA_H\n\n#define DMA_CHANNELS\t\t8\t/* max. number of DMA channels */\n\n#define DMA_MASK_CHANNEL\t0x04\n#define DMA_UNMASK_CHANNEL\t0x00\n\n#define DMA_MODE_VERIFY\t\t0x00\n#define DMA_MODE_WRITE\t\t0x04\t/* read device -> write memory */\n#define DMA_MODE_READ\t\t0x08\t/* read memory -> write device */\n#define DMA_MODE_AUTOINIT\t0x10\n#define DMA_MODE_ADDRES_DEC\t0x20\n#define DMA_MODE_DEMAND\t\t0x00\n#define DMA_MODE_SINGLE\t\t0x40\n#define DMA_MODE_BLOCK\t\t0x80\n#define DMA_MODE_CASCADE\t0xC0\n\nextern char *dma_resources[DMA_CHANNELS];\n\nvoid start_dma(int, void *, unsigned int, int);\nint dma_register(int, char *);\nint dma_unregister(int);\nvoid dma_init(void);\n\n#endif /* _FIWIX_DMA_H */\n"
  },
  {
    "path": "include/fiwix/errno.h",
    "content": "#ifndef _FIWIX_ERRNO_H\n#define _FIWIX_ERRNO_H\n\n#define EPERM\t\t1\t/* Operation not permitted - Not owner\t*/\n#define ENOENT\t\t2\t/* No such file or directory\t\t*/\n#define ESRCH\t\t3\t/* No such process\t\t\t*/\n#define EINTR\t\t4\t/* Interrupted system call\t\t*/\n#define EIO\t\t5\t/* I/O error\t\t\t\t*/\n#define ENXIO\t\t6\t/* No such device or address\t\t*/\n#define E2BIG\t\t7\t/* Arg list too long\t\t\t*/\n#define ENOEXEC\t\t8\t/* Exec format error\t\t\t*/\n#define EBADF\t\t9\t/* Bad file number\t\t\t*/\n#define ECHILD\t\t10\t/* No child processes\t\t\t*/\n#define EAGAIN\t\t11\t/* Try again - No more processes\t*/\n#define ENOMEM\t\t12\t/* Out of memory - No enough space\t*/\n#define EACCES\t\t13\t/* Permission denied\t\t\t*/\n#define EFAULT\t\t14\t/* Bad address\t\t\t\t*/\n#define ENOTBLK\t\t15\t/* Block device required\t\t*/\n#define EBUSY\t\t16\t/* Device or resource busy\t\t*/\n#define EEXIST\t\t17\t/* File exists\t\t\t\t*/\n#define EXDEV\t\t18\t/* Cross-device link\t\t\t*/\n#define ENODEV\t\t19\t/* No such device\t\t\t*/\n#define ENOTDIR\t\t20\t/* Not a directory\t\t\t*/\n#define EISDIR\t\t21\t/* Is a directory\t\t\t*/\n#define EINVAL\t\t22\t/* Invalid argument\t\t\t*/\n#define ENFILE\t\t23\t/* File table overflow\t\t\t*/\n#define EMFILE\t\t24\t/* Too many open files\t\t\t*/\n#define ENOTTY\t\t25\t/* Not a typewriter\t\t\t*/\n#define ETXTBSY\t\t26\t/* Text file busy\t\t\t*/\n#define EFBIG\t\t27\t/* File too large\t\t\t*/\n#define ENOSPC\t\t28\t/* No space left on device\t\t*/\n#define ESPIPE\t\t29\t/* Illegal seek\t\t\t\t*/\n#define EROFS\t\t30\t/* Read-only file system\t\t*/\n#define EMLINK\t\t31\t/* Too many links\t\t\t*/\n#define EPIPE\t\t32\t/* Broken pipe\t\t\t\t*/\n#define EDOM\t\t33\t/* Math argument out of domain of func\t*/\n#define ERANGE\t\t34\t/* Math result not representable\t*/\n#define EDEADLK\t\t35\t/* Resource deadlock would occur\t*/\n#define ENAMETOOLONG\t36\t/* File name too long\t\t\t*/\n#define ENOLCK\t\t37\t/* No record locks available\t\t*/\n#define ENOSYS\t\t38\t/* Function not implemented\t\t*/\n#define ENOTEMPTY\t39\t/* Directory not empty\t\t\t*/\n#define ELOOP\t\t40\t/* Too many symbolic links encountered\t*/\n#define EWOULDBLOCK\tEAGAIN\t/* Operation would block\t\t*/\n#define ENOMSG\t\t42\t/* No message of desired type\t\t*/\n#define EIDRM\t\t43\t/* Identifier removed\t\t\t*/\n#define ECHRNG\t\t44\t/* Channel number out of range\t\t*/\n#define EL2NSYNC\t45\t/* Level 2 not synchronized\t\t*/\n#define EL3HLT\t\t46\t/* Level 3 halted\t\t\t*/\n#define EL3RST\t\t47\t/* Level 3 reset\t\t\t*/\n#define ELNRNG\t\t48\t/* Link number out of range\t\t*/\n#define EUNATCH\t\t49\t/* Protocol driver not attached\t\t*/\n#define ENOCSI\t\t50\t/* No CSI structure available\t\t*/\n#define EL2HLT\t\t51\t/* Level 2 halted\t\t\t*/\n#define EBADE\t\t52\t/* Invalid exchange\t\t\t*/\n#define EBADR\t\t53\t/* Invalid request descriptor\t\t*/\n#define EXFULL\t\t54\t/* Exchange full\t\t\t*/\n#define ENOANO\t\t55\t/* No anode\t\t\t\t*/\n#define EBADRQC\t\t56\t/* Invalid request code\t\t\t*/\n#define EBADSLT\t\t57\t/* Invalid slot\t\t\t\t*/\n\n#define EDEADLOCK\tEDEADLK\n\n#define EBFONT\t\t59\t/* Bad font file format\t\t\t*/\n#define ENOSTR\t\t60\t/* Device not a stream\t\t\t*/\n#define ENODATA\t\t61\t/* No data available\t\t\t*/\n#define ETIME\t\t62\t/* Timer expired\t\t\t*/\n#define ENOSR\t\t63\t/* Out of streams resources\t\t*/\n#define ENONET\t\t64\t/* Machine is not on the network\t*/\n#define ENOPKG\t\t65\t/* Package not installed\t\t*/\n#define EREMOTE\t\t66\t/* Object is remote\t\t\t*/\n#define ENOLINK\t\t67\t/* Link has been severed\t\t*/\n#define EADV\t\t68\t/* Advertise error\t\t\t*/\n#define ESRMNT\t\t69\t/* Srmount error\t\t\t*/\n#define ECOMM\t\t70\t/* Communication error on send\t\t*/\n#define EPROTO\t\t71\t/* Protocol error\t\t\t*/\n#define EMULTIHOP\t72\t/* Multihop attempted\t\t\t*/\n#define EDOTDOT\t\t73\t/* RFS specific error\t\t\t*/\n#define EBADMSG\t\t74\t/* Not a data message\t\t\t*/\n#define EOVERFLOW\t75\t/* Value too large for defined data type */\n#define ENOTUNIQ\t76\t/* Name not unique on network\t\t*/\n#define EBADFD\t\t77\t/* File descriptor in bad state\t\t*/\n#define EREMCHG\t\t78\t/* Remote address changed\t\t*/\n#define ELIBACC\t\t79\t/* Can not access a needed shared library */\n#define ELIBBAD\t\t80\t/* Accessing a corrupted shared library */\n#define ELIBSCN\t\t81\t/* .lib section in a.out corrupted\t*/\n#define ELIBMAX\t\t82\t/* Attempting to link in too many shared libraries */\n#define ELIBEXEC\t83\t/* Cannot exec a shared library directly */\n#define EILSEQ\t\t84\t/* Illegal byte sequence\t\t*/\n#define ERESTART\t85\t/* Interrupted system call should be restarted */\n#define ESTRPIPE\t86\t/* Streams pipe error\t\t\t*/\n#define EUSERS\t\t87\t/* Too many users\t\t\t*/\n#define ENOTSOCK\t88\t/* Socket operation on non-socket\t*/\n#define EDESTADDRREQ\t89\t/* Destination address required\t\t*/\n#define EMSGSIZE\t90\t/* Message too long\t\t\t*/\n#define EPROTOTYPE\t91\t/* Protocol wrong type for socket\t*/\n#define ENOPROTOOPT\t92\t/* Protocol not available\t\t*/\n#define EPROTONOSUPPORT\t93\t/* Protocol not supported\t\t*/\n#define ESOCKTNOSUPPORT\t94\t/* Socket type not supported\t\t*/\n#define EOPNOTSUPP\t95\t/* Operation not supported on transport endpoint */\n#define EPFNOSUPPORT\t96\t/* Protocol family not supported\t*/\n#define EAFNOSUPPORT\t97\t/* Address family not supported by protocol */\n#define EADDRINUSE\t98\t/* Address already in use\t\t*/\n#define EADDRNOTAVAIL\t99\t/* Cannot assign requested address\t*/\n#define ENETDOWN\t100\t/* Network is down\t\t\t*/\n#define ENETUNREACH\t101\t/* Network is unreachable\t\t*/\n#define ENETRESET\t102\t/* Network dropped connection because of reset */\n#define ECONNABORTED\t103\t/* Software caused connection abort\t*/\n#define ECONNRESET\t104\t/* Connection reset by peer\t\t*/\n#define ENOBUFS\t\t105\t/* No buffer space available\t\t*/\n#define EISCONN\t\t106\t/* Transport endpoint is already connected */\n#define ENOTCONN\t107\t/* Transport endpoint is not connected\t*/\n#define ESHUTDOWN\t108\t/* Cannot send after transport endpoint shutdown */\n#define ETOOMANYREFS\t109\t/* Too many references: cannot splice\t*/\n#define ETIMEDOUT\t110\t/* Connection timed out\t\t\t*/\n#define ECONNREFUSED\t111\t/* Connection refused\t\t\t*/\n#define EHOSTDOWN\t112\t/* Host is down\t\t\t\t*/\n#define EHOSTUNREACH\t113\t/* No route to host\t\t\t*/\n#define EALREADY\t114\t/* Operation already in progress\t*/\n#define EINPROGRESS\t115\t/* Operation now in progress\t\t*/\n#define ESTALE\t\t116\t/* Stale NFS file handle\t\t*/\n#define EUCLEAN\t\t117\t/* Structure needs cleaning\t\t*/\n#define ENOTNAM\t\t118\t/* Not a XENIX named type file\t\t*/\n#define ENAVAIL\t\t119\t/* No XENIX semaphores available\t*/\n#define EISNAM\t\t120\t/* Is a named type file\t\t\t*/\n#define EREMOTEIO\t121\t/* Remote I/O error\t\t\t*/\n#define EDQUOT\t\t122\t/* Quota exceeded\t\t\t*/\n\n#define ENOMEDIUM\t123\t/* No medium found\t\t\t*/\n#define EMEDIUMTYPE\t124\t/* Wrong medium type\t\t\t*/\n\n#endif\t/* _FIWIX_ERRNO_H */\n"
  },
  {
    "path": "include/fiwix/fb.h",
    "content": "/*\n * fiwix/include/fiwix/fb.h\n *\n * Copyright 2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_FB_H\n#define _FIWIX_FB_H\n\n#include <fiwix/fs.h>\n\n#define FB_MAJOR\t29\t/* major number */\n#define FB_MINOR\t0\t/* minor number */\n\nint fb_open(struct inode *, struct fd *);\nint fb_close(struct inode *, struct fd *);\nint fb_read(struct inode *, struct fd *, char *, __size_t);\nint fb_write(struct inode *, struct fd *, const char *, __size_t);\nint fb_mmap(struct inode *, struct vma *);\nint fb_ioctl(struct inode *, struct fd *, int, unsigned int);\n__loff_t fb_llseek(struct inode *, __loff_t);\n\nvoid fb_init(void);\n\n#endif /* _FIWIX_FB_H */\n"
  },
  {
    "path": "include/fiwix/fbcon.h",
    "content": "/*\n * fiwix/include/fiwix/fbcon.h\n *\n * Copyright 2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_FBCON_H\n#define _FIWIX_FBCON_H\n\nvoid fbcon_put_char(struct vconsole *, unsigned char);\n\nvoid fbcon_put_char(struct vconsole *, unsigned char);\nvoid fbcon_insert_char(struct vconsole *);\nvoid fbcon_delete_char(struct vconsole *);\nvoid fbcon_update_curpos(struct vconsole *);\nvoid fbcon_show_cursor(struct vconsole *, int);\nvoid fbcon_get_curpos(struct vconsole *);\nvoid fbcon_write_screen(struct vconsole *, int, int, short int);\nvoid fbcon_blank_screen(struct vconsole *);\nvoid fbcon_scroll_screen(struct vconsole *, int, int);\nvoid fbcon_restore_screen(struct vconsole *);\nvoid fbcon_screen_on(struct vconsole *);\nvoid fbcon_screen_off(unsigned int);\nvoid fbcon_buf_scroll(struct vconsole *, int);\nvoid fbcon_cursor_blink(unsigned int);\nvoid fbcon_init(void);\n\n#endif /* _FIWIX_FBCON_H */\n"
  },
  {
    "path": "include/fiwix/fcntl.h",
    "content": "/*\n * fiwix/include/fiwix/fcntl.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_FCNTL_H\n#define _FIWIX_FCNTL_H\n\n#include <fiwix/types.h>\n\n#define O_ACCMODE\t   0003\n#define O_RDONLY\t     00\n#define O_WRONLY\t     01\n#define O_RDWR\t\t     02\n\n/* for open() only */\n#define O_CREAT\t\t   0100\t/* create file if it does not exist */\n#define O_EXCL\t\t   0200\t/* exclusive use flag */\n#define O_NOCTTY\t   0400\t/* do not assign controlling terminal */\n#define O_TRUNC\t\t  01000\t/* truncate flag */\n#define O_DIRECTORY\t0200000 /* only open if directory */\n#define O_NOFOLLOW\t0400000\t/* do not follow symbolic links */\n\n#define O_APPEND\t  02000\n#define O_NONBLOCK\t  04000\n#define O_NDELAY\tO_NONBLOCK\n#define O_SYNC\t\t 010000\n\n#define F_DUPFD\t\t0\t/* duplicate file descriptor */\n#define F_GETFD\t\t1\t/* get file descriptor flags */\n#define F_SETFD\t\t2\t/* set file descriptor flags */\n#define F_GETFL\t\t3\t/* get status flags and file access modes */\n#define F_SETFL\t\t4\t/* set file status flags */\n#define F_GETLK\t\t5\t/* get record locking information */\n#define F_SETLK\t\t6\t/* set record locking information */\n#define F_SETLKW\t7\t/* same as F_SETLK; wait if blocked */\n#define F_GETLK64\t12\n#define F_SETLK64\t13\n#define F_SETLKW64\t14\n#define F_DUPFD_CLOEXEC\t1030\t/* duplicate file descriptor with close-on-exec*/\n\n/* get/set process or process group ID to receive SIGURG signals */\n#define F_SETOWN\t8\t/* for sockets only */\n#define F_GETOWN\t9\t/* for sockets only */\n\n/* for F_[GET|SET]FL */\n#define FD_CLOEXEC\t1\t/* close the file descriptor upon exec() */\n\n/* for POSIX fcntl() */\n#define F_RDLCK\t\t0\t/* shared or read lock */\n#define F_WRLCK\t\t1\t/* exclusive or write lock */\n#define F_UNLCK\t\t2\t/* unlock */\n\n/* for BSD flock() */\n#define LOCK_SH\t\t1\t/* shared lock */\n#define LOCK_EX\t\t2\t/* exclusive lock */\n#define LOCK_NB\t\t4\t/* or'd with one of the above to prevent\n\t\t\t\t   blocking */\n#define LOCK_UN\t\t8\t/* unlock */\n\n/* IEEE Std 1003.1, 2004 Edition */\nstruct flock {\n\tshort int l_type;\t/* type of lock: F_RDLCK, F_WRLCK, F_UNLCK */\n\tshort int l_whence;\t/* flag for 'l_start': SEEK_SET, SEEK_CUR, ...*/\n\t__off_t l_start;\t/* relative offset in bytes */\n\t__off_t l_len;\t\t/* size; if 0 then until EOF */\n\t__pid_t l_pid;\t\t/* PID holding the lock; returned in F_GETLK */\n};\n\n#endif /* _FIWIX_FCNTL_H */\n"
  },
  {
    "path": "include/fiwix/fd.h",
    "content": "/*\n * fiwix/include/fiwix/fd.h\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_FD_H\n#define _FIWIX_FD_H\n\n#include <fiwix/config.h>\n#include <fiwix/types.h>\n\n#define CHECK_UFD(ufd)\t\t\t\t\t\t\t\\\n{\t\t\t\t\t\t\t\t\t\\\n\tif((ufd) > (OPEN_MAX - 1) || current->fd[(ufd)] == 0) {\t\t\\\n\t\treturn -EBADF;\t\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n}\t\t\t\t\t\t\t\t\t\\\n\nextern unsigned int fd_table_size;\t/* size in bytes */\nextern struct fd *fd_table;\n\nstruct fd {\n\tstruct inode *inode;\t\t/* file inode */\n\tunsigned short int flags;\t/* flags */\n\tunsigned short int count;\t/* number of opened instances */\n#ifdef CONFIG_OFFSET64\n\t__loff_t offset;\t\t/* r/w pointer position */\n#else\n\t__off_t offset;\t\t\t/* r/w pointer position */\n#endif /* CONFIG_OFFSET64 */\n\tvoid *private_data;\t\t/* needed for tty driver */\n};\n\n#endif /* _FIWIX_FS_H */\n"
  },
  {
    "path": "include/fiwix/filesystems.h",
    "content": "/*\n * fiwix/include/fiwix/filesystems.h\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_FILESYSTEMS_H\n#define _FIWIX_FILESYSTEMS_H\n\n#include <fiwix/types.h>\n#include <fiwix/limits.h>\n\n#define NR_FILESYSTEMS\t\t6\t/* supported filesystems */\n\n/* special device numbers for nodev filesystems */\nenum {\n\tFS_NODEV = 0xFFF0,\n\tDEVPTS_DEV,\n\tPIPE_DEV,\n\tPROC_DEV,\n\tSOCK_DEV,\n};\n\nstruct filesystems {\n\tconst char *name;\t\t/* filesystem name */\n\tstruct fs_operations *fsop;\t/* filesystem operations */\n\tstruct mount *mp;\t\t/* mount-table entry (only for nodev) */\n};\nextern struct filesystems filesystems_table[NR_FILESYSTEMS];\n\nstruct mount {\n\t__dev_t dev;\t\t\t/* device number */\n\tchar *devname;\t\t\t/* device name */\n\tchar *dirname;\t\t\t/* mount point directory name */\n\tstruct superblock sb;\t\t/* superblock */\n\tstruct filesystems *fs;\t\t/* pointer to filesystem structure */\n\tstruct mount *prev;\n\tstruct mount *next;\n};\nextern struct mount *mount_table;\n\nint register_filesystem(const char *, struct fs_operations *);\nstruct filesystems *get_filesystem(const char *);\nvoid fs_init(void);\n\nstruct superblock *get_superblock(__dev_t);\nvoid sync_superblocks(__dev_t);\nint kern_mount(__dev_t, struct filesystems *);\nint mount_root(void);\n\n\n/* minix prototypes */\nint minix_file_open(struct inode *, struct fd *);\nint minix_file_close(struct inode *, struct fd *);\nint minix_file_write(struct inode *, struct fd *, const char *, __size_t);\n__loff_t minix_file_llseek(struct inode *, __loff_t);\nint minix_dir_open(struct inode *, struct fd *);\nint minix_dir_close(struct inode *, struct fd *);\nint minix_dir_read(struct inode *, struct fd *, char *, __size_t);\nint minix_readdir(struct inode *, struct fd *, struct dirent *, __size_t);\nint minix_readlink(struct inode *, char *, __size_t);\nint minix_followlink(struct inode *, struct inode *, struct inode **);\nint minix_bmap(struct inode *, __off_t, int);\nint minix_lookup(const char *, struct inode *, struct inode **);\nint minix_rmdir(struct inode *, struct inode *);\nint minix_link(struct inode *, struct inode *, char *);\nint minix_unlink(struct inode *, struct inode *, char *);\nint minix_symlink(struct inode *, char *, char *);\nint minix_mkdir(struct inode *, char *, __mode_t);\nint minix_mknod(struct inode *, char *, __mode_t, __dev_t);\nint minix_truncate(struct inode *, __off_t);\nint minix_create(struct inode *, char *, int, __mode_t, struct inode **);\nint minix_rename(struct inode *, struct inode *, struct inode *, struct inode *, char *, char *);\nint minix_read_inode(struct inode *);\nint minix_write_inode(struct inode *);\nint minix_ialloc(struct inode *, int);\nvoid minix_ifree(struct inode *);\nvoid minix_statfs(struct superblock *, struct statfs *);\nint minix_read_superblock(__dev_t, struct superblock *);\nint minix_remount_fs(struct superblock *, int);\nint minix_write_superblock(struct superblock *);\nvoid minix_release_superblock(struct superblock *);\nint minix_init(void);\n\n/* ext2 prototypes */\nint ext2_file_open(struct inode *, struct fd *);\nint ext2_file_close(struct inode *, struct fd *);\nint ext2_file_write(struct inode *, struct fd *, const char *, __size_t);\n__loff_t ext2_file_llseek(struct inode *, __loff_t);\nint ext2_dir_open(struct inode *, struct fd *);\nint ext2_dir_close(struct inode *, struct fd *);\nint ext2_dir_read(struct inode *, struct fd *, char *, __size_t);\nint ext2_readdir(struct inode *, struct fd *, struct dirent *, __size_t);\nint ext2_readdir64(struct inode *, struct fd *, struct dirent64 *, __size_t);\nint ext2_readlink(struct inode *, char *, __size_t);\nint ext2_followlink(struct inode *, struct inode *, struct inode **);\nint ext2_bmap(struct inode *, __off_t, int);\nint ext2_lookup(const char *, struct inode *, struct inode **);\nint ext2_rmdir(struct inode *, struct inode *);\nint ext2_link(struct inode *, struct inode *, char *);\nint ext2_unlink(struct inode *, struct inode *, char *);\nint ext2_symlink(struct inode *, char *, char *);\nint ext2_mkdir(struct inode *, char *, __mode_t);\nint ext2_mknod(struct inode *, char *, __mode_t, __dev_t);\nint ext2_truncate(struct inode *, __off_t);\nint ext2_create(struct inode *, char *, int, __mode_t, struct inode **);\nint ext2_rename(struct inode *, struct inode *, struct inode *, struct inode *, char *, char *);\nint ext2_read_inode(struct inode *);\nint ext2_write_inode(struct inode *);\nint ext2_ialloc(struct inode *, int);\nvoid ext2_ifree(struct inode *);\nvoid ext2_statfs(struct superblock *, struct statfs *);\nint ext2_read_superblock(__dev_t, struct superblock *);\nint ext2_remount_fs(struct superblock *, int);\nint ext2_write_superblock(struct superblock *);\nvoid ext2_release_superblock(struct superblock *);\nint ext2_init(void);\n\n/* pipefs prototypes */\nint fifo_open(struct inode *, struct fd *);\nint pipefs_close(struct inode *, struct fd *);\nint pipefs_read(struct inode *, struct fd *, char *, __size_t);\nint pipefs_write(struct inode *, struct fd *, const char *, __size_t);\nint pipefs_ioctl(struct inode *, struct fd *, int, unsigned int);\n__loff_t pipefs_llseek(struct inode *, __loff_t);\nint pipefs_select(struct inode *, struct fd *, int);\nint pipefs_ialloc(struct inode *, int);\nvoid pipefs_ifree(struct inode *);\nint pipefs_read_superblock(__dev_t, struct superblock *);\nint pipefs_init(void);\n\n/* iso9660 prototypes */\nint iso9660_file_open(struct inode *, struct fd *);\nint iso9660_file_close(struct inode *, struct fd *);\n__loff_t iso9660_file_llseek(struct inode *, __loff_t);\nint iso9660_dir_open(struct inode *, struct fd *);\nint iso9660_dir_close(struct inode *, struct fd *);\nint iso9660_dir_read(struct inode *, struct fd *, char *, __size_t);\nint iso9660_readdir(struct inode *, struct fd *, struct dirent *, __size_t);\nint iso9660_readlink(struct inode *, char *, __size_t);\nint iso9660_followlink(struct inode *, struct inode *, struct inode **);\nint iso9660_bmap(struct inode *, __off_t, int);\nint iso9660_lookup(const char *, struct inode *, struct inode **);\nint iso9660_read_inode(struct inode *);\nvoid iso9660_statfs(struct superblock *, struct statfs *);\nint iso9660_read_superblock(__dev_t, struct superblock *);\nvoid iso9660_release_superblock(struct superblock *);\nint iso9660_init(void);\n\n/* procfs prototypes */\nint procfs_file_open(struct inode *, struct fd *);\nint procfs_file_close(struct inode *, struct fd *);\nint procfs_file_read(struct inode *, struct fd *, char *, __size_t);\n__loff_t procfs_file_llseek(struct inode *, __loff_t);\nint procfs_dir_open(struct inode *, struct fd *);\nint procfs_dir_close(struct inode *, struct fd *);\nint procfs_dir_read(struct inode *, struct fd *, char *, __size_t);\nint procfs_readdir(struct inode *, struct fd *, struct dirent *, __size_t);\nint procfs_readlink(struct inode *, char *, __size_t);\nint procfs_followlink(struct inode *, struct inode *, struct inode **);\nint procfs_bmap(struct inode *, __off_t, int);\nint procfs_lookup(const char *, struct inode *, struct inode **);\nint procfs_read_inode(struct inode *);\nvoid procfs_statfs(struct superblock *, struct statfs *);\nint procfs_read_superblock(__dev_t, struct superblock *);\nint procfs_init(void);\n\n#ifdef CONFIG_NET\n/* sockfs prototypes */\nint sockfs_open(struct inode *, struct fd *);\nint sockfs_close(struct inode *, struct fd *);\nint sockfs_read(struct inode *, struct fd *, char *, __size_t);\nint sockfs_write(struct inode *, struct fd *, const char *, __size_t);\nint sockfs_ioctl(struct inode *, struct fd *, int, unsigned int);\n__loff_t sockfs_llseek(struct inode *, __loff_t);\nint sockfs_select(struct inode *, struct fd *, int);\nint sockfs_ialloc(struct inode *, int);\nvoid sockfs_ifree(struct inode *);\nint sockfs_read_superblock(__dev_t, struct superblock *);\nint sockfs_init(void);\n#endif /* CONFIG_NET */\n\n#ifdef CONFIG_UNIX98_PTYS\n/* devpts prototypes */\nint devpts_dir_open(struct inode *, struct fd *);\nint devpts_dir_close(struct inode *, struct fd *);\nint devpts_dir_read(struct inode *, struct fd *, char *, __size_t);\nint devpts_readdir(struct inode *, struct fd *, struct dirent *, __size_t);\nint devpts_lookup(const char *, struct inode *, struct inode **);\nint devpts_read_inode(struct inode *);\nvoid devpts_statfs(struct superblock *, struct statfs *);\nint devpts_ialloc(struct inode *, int);\nvoid devpts_ifree(struct inode *);\nint devpts_read_superblock(__dev_t, struct superblock *);\nint devpts_init(void);\n#endif /* CONFIG_UNIX98_PTYS */\n\n#endif /* _FIWIX_FILESYSTEMS_H */\n"
  },
  {
    "path": "include/fiwix/floppy.h",
    "content": "/*\n * fiwix/include/fiwix/floppy.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_FLOPPY_H\n#define _FIWIX_FLOPPY_H\n\n#include <fiwix/fs.h>\n#include <fiwix/sigcontext.h>\n\n#define FLOPPY_IRQ\t6\n#define FLOPPY_DMA\t2\t/* DMA channel */\n\n#define FDC_MAJOR\t2\t/* fdd major number */\n\n#define FDC_SECTSIZE\t512\t/* sector size (in bytes) */\n#define FDC_TR_DEFAULT\t0\t/* timer reason is IRQ */\n#define FDC_TR_MOTOR\t1\t/* timer reason is motor on */\n\n#define FDC_SRA\t\t0x3F0\t/* Status Register A */\n#define FDC_SRB\t\t0x3F1\t/* Status Register B */\n#define FDC_DOR\t\t0x3F2\t/* Digital Output Register */\n#define FDC_MSR\t\t0x3F4\t/* Main Status Register */\n#define FDC_DATA \t0x3F5\t/* command/data register */\n#define FDC_DIR\t\t0x3F7\t/* Digital Input Register */\n#define FDC_CCR\t\t0x3F7\t/* Configuration Control Register */\n\n#define FDC_ENABLE\t0x04\t/* bit #2 FDC enabled (normal op) */\n#define FDC_DMA_ENABLE\t0x08\t/* bit #3 DMA enabled */\n#define FDC_DRIVE0\t0x10\t/* motor on for the first drive, the rest will\n\t\t\t\t * be calculated by left-shifting this value\n\t\t\t\t * with 'current_fdd'.\n\t\t\t\t */\n\n#define FDC_DIO\t\t0x40\t/* bit #6 DIO I/O direction */\n#define FDC_RQM\t\t0x80\t/* bit #7 RQM is ready for I/O */\n\n#define MAX_FDC_RESULTS\t7\n#define MAX_FDC_ERR\t5\n\n#define FDC_RESET\t0xFF\t/* reset indicador */\n#define FDC_READ\t0xE6\n#define FDC_WRITE\t0xC5\n#define FDC_VERSION\t0x10\n#define FDC_FORMAT_TRK\t0x4D\n#define FDC_RECALIBRATE\t0x07\n#define FDC_SENSEI\t0x08\n#define FDC_SPECIFY\t0x03\n#define FDC_SEEK\t0x0F\n#define FDC_LOCK\t0x14\n#define FDC_PARTID\t0x18\n\n#define ST0\t\t0x00\t/* Status Register 0 */\n#define ST1\t\t0x01\t/* Status Register 1 */\n#define ST2\t\t0x02\t/* Status Register 2 */\n\n#define ST0_IC\t\t0xC0\t/* bits #7 and #6 interrupt code */\n#define ST0_SE\t\t0x20\t/* bit #5 successful implied seek */\n#define ST0_RECALIBRATE\tST0_SE\t/* bit #5 successful FDC_RECALIBRATE */\n#define ST0_SEEK\tST0_SE\t/* bit #5 successful FDC_SEEK */\n#define ST0_UC\t\t0x10\t/* bit #4 unit needs check (fault) */\n#define ST0_NR\t\t0x8\t/* bit #3 drive not ready */\n\n#define ST1_NW\t\t0x02\t/* bit #1 not writable */\n\n#define ST_PCN\t\t0x01\t/* present cylinder */\n#define ST_CYL\t\t0x03\t/* cylinder returned */\n#define ST_HEAD\t\t0x04\t/* head returned */\n#define ST_SECTOR\t0x05\t/* sector returned */\n\n/* floppy disk drive type */\nstruct fddt {\n\tshort int size;\t \t/* number of sectors */\n\tshort int sizekb;\t/* size in KB */\n\tchar tracks;\t\t/* number of tracks */\n\tchar spt;\t \t/* number of sectors per track */\n\tchar heads;\t \t/* number of heads */\n\tchar gpl1;\t\t/* GAP in READ/WRITE operations */\n\tchar gpl2;\t\t/* GAP in FORMAT TRACK operations */\n\tchar rate;\t\t/* data rate value */\n\tchar spec;\t\t/* SRT+HUT (StepRate + HeadUnload) Time */\n\tchar hlt;\t\t/* HLT (Head Load Time) */\n\tchar *name;\t\t/* unit name */\n};\n\nvoid irq_floppy(int, struct sigcontext *);\nvoid fdc_timer(unsigned int);\n\nint fdc_open(struct inode *, struct fd *);\nint fdc_close(struct inode *, struct fd *);\nint fdc_read(__dev_t, __blk_t, char *, int);\nint fdc_write(__dev_t, __blk_t, char *, int);\nint fdc_ioctl(struct inode *, struct fd *, int, unsigned int);\n__loff_t fdc_llseek(struct inode *, __loff_t);\n\nvoid floppy_init(void);\n\n#endif /* _FIWIX_FLOPPY_H */\n"
  },
  {
    "path": "include/fiwix/font.h",
    "content": "/*\n * fiwix/include/fiwix/font.h\n *\n * Copyright 2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_FONT_H\n#define _FIWIX_FONT_H\n\nstruct fbcon_font_desc {\n\tchar *name;\n\tint width;\n\tint height;\n\tvoid *data;\n\tvoid *cursorshape;\n};\n\nextern struct fbcon_font_desc font_vga_8x8;\nextern struct fbcon_font_desc font_vga_8x14;\nextern struct fbcon_font_desc font_vga_8x16;\n\nstruct fbcon_font_desc *fbcon_find_font(int);\n\n#endif /* _FIWIX_FONT_H */\n"
  },
  {
    "path": "include/fiwix/fs.h",
    "content": "/*\n * fiwix/include/fiwix/fs.h\n *\n * Copyright 2018-2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_FS_H\n#define _FIWIX_FS_H\n\n#include <fiwix/statfs.h>\n#include <fiwix/limits.h>\n#include <fiwix/process.h>\n#include <fiwix/dirent.h>\n#include <fiwix/fd.h>\n#include <fiwix/fs_minix.h>\n#include <fiwix/fs_ext2.h>\n#include <fiwix/fs_pipe.h>\n#include <fiwix/fs_iso9660.h>\n#include <fiwix/fs_proc.h>\n#include <fiwix/fs_sock.h>\n\n#define BPS\t\t\t512\t/* bytes per sector */\n#define BLKSIZE_1K\t\t1024\t/* 1KB block size */\n#define BLKSIZE_2K\t\t2048\t/* 2KB block size */\n#define SUPERBLOCK\t\t1\t/* block 1 is for superblock */\n\n#define MAJOR(dev)\t\t(((__dev_t) (dev)) >> 8)\n#define MINOR(dev)\t\t(((__dev_t) (dev)) & 0xFF)\n#define MKDEV(major, minor)\t(((major) << 8) | (minor))\n\n/* filesystem independent mount-flags */\n#define MS_RDONLY\t\t0x01\t/* mount read-only */\n#define MS_REMOUNT\t\t0x20\t/* alter flags of a mounted FS */\n\n/* old magic mount flag and mask */\n#define MS_MGC_VAL\t\t0xC0ED0000\n#define MS_MGC_MSK\t\t0xFFFF0000\n\n#define IS_RDONLY_FS(inode) (((inode)->sb) && ((inode)->sb->flags & MS_RDONLY))\n\n#define FOLLOW_LINKS\t1\n#define MAX_SYMLINKS\t8\t/* this prevents infinite loops in symlinks */\n\n#define SEEK_SET\t0\n#define SEEK_CUR\t1\n#define SEEK_END\t2\n\n#define FOR_READING\t0\n#define FOR_WRITING\t1\n\n#define VERIFY_READ\t1\n#define VERIFY_WRITE\t2\n\n#define SEL_R\t\t1\n#define SEL_W\t\t2\n#define SEL_E\t\t4\n\n#define CLEAR_BIT\t0\n#define SET_BIT\t\t1\n\n#define INODE_LOCKED\t0x01\n#define INODE_DIRTY\t0x02\n\nstruct inode {\n\t__mode_t\ti_mode;\t\t/* file mode */\n\t__u32\t\ti_uid;\t\t/* owner uid */\n\t__size_t\ti_size;\t\t/* size in bytes */\n\t__u32\t\ti_atime;\t/* access time */\n\t__u32\t\ti_ctime;\t/* creation time */\n\t__u32\t\ti_mtime;\t/* modification time */\n\t__u32\t\ti_gid;\t\t/* group id */\n\t__nlink_t\ti_nlink;\t/* links count */\n\t__blk_t\t\ti_blocks;\t/* blocks count */\n\t__u32\t\ti_flags;\t/* file flags */\n\tstruct inode *mount_point;\n\t__u32\t\tstate;\n\t__dev_t\t\tdev;\n\t__ino_t\t\tinode;\n\t__s16\t\tcount;\n\t__dev_t\t\trdev;\n\tstruct fs_operations *fsop;\n\tstruct superblock *sb;\n\tstruct inode *prev;\n\tstruct inode *next;\n\tstruct inode *prev_hash;\n\tstruct inode *next_hash;\n\tstruct inode *prev_free;\n\tstruct inode *next_free;\n\tunion {\n#ifdef CONFIG_FS_MINIX\n\t\tstruct minix_i_info minix;\n#endif /* CONFIG_FS_MINIX */\n\t\tstruct ext2_i_info ext2;\n\t\tstruct pipefs_inode pipefs;\n\t\tstruct iso9660_inode iso9660;\n\t\tstruct procfs_inode procfs;\n#ifdef CONFIG_NET\n\t\tstruct sockfs_inode sockfs;\n#endif /* CONFIG_NET */\n\t} u;\n};\nextern struct inode *inode_table;\nextern struct inode **inode_hash_table;\n\n/* values to be determined during system startup */\nextern unsigned int inode_hash_table_size;\t/* size in bytes */\n\n#define SUPERBLOCK_LOCKED\t0x01\n#define SUPERBLOCK_DIRTY\t0x02\n\nstruct superblock {\n\t__dev_t dev;\n\tunsigned int flags;\n\tunsigned int state;\n\tstruct inode *root;\t\t/* root inode of mounted fs */\n\tstruct inode *dir;\t\t/* inode on which the fs was mounted */\n\tstruct fs_operations *fsop;\n\t__u32 s_blocksize;\n\tunsigned char s_blocksize_bits;\n\tunion {\n#ifdef CONFIG_FS_MINIX\n\t\tstruct minix_sb_info minix;\n#endif /* CONFIG_FS_MINIX */\n\t\tstruct ext2_sb_info ext2;\n\t\tstruct iso9660_sb_info iso9660;\n\t} u;\n};\n\n\n#define FSOP_REQUIRES_DEV\t1\t/* requires a block device */\n#define FSOP_KERN_MOUNT\t\t2\t/* mounted by kernel */\n\nstruct fs_operations {\n\tint flags;\n\tint fsdev;\t\t\t/* internal filesystem (nodev) */\n\n/* file operations */\n\tint (*open)(struct inode *, struct fd *);\n\tint (*close)(struct inode *, struct fd *);\n\tint (*read)(struct inode *, struct fd *, char *, __size_t);\n\tint (*write)(struct inode *, struct fd *, const char *, __size_t);\n\tint (*ioctl)(struct inode *, struct fd *, int, unsigned int);\n\t__loff_t (*llseek)(struct inode *, __loff_t);\n\tint (*readdir)(struct inode *, struct fd *, struct dirent *, __size_t);\n\tint (*readdir64)(struct inode *, struct fd *, struct dirent64 *, __size_t);\n\tint (*mmap)(struct inode *, struct vma *);\n\tint (*select)(struct inode *, struct fd *, int);\n\n/* inode operations */\n\tint (*readlink)(struct inode *, char *, __size_t);\n\tint (*followlink)(struct inode *, struct inode *, struct inode **);\n\tint (*bmap)(struct inode *, __off_t, int);\n\tint (*lookup)(const char *, struct inode *, struct inode **);\n\tint (*rmdir)(struct inode *, struct inode *);\n\tint (*link)(struct inode *, struct inode *, char *);\n\tint (*unlink)(struct inode *, struct inode *, char *);\n\tint (*symlink)(struct inode *, char *, char *);\n\tint (*mkdir)(struct inode *, char *, __mode_t);\n\tint (*mknod)(struct inode *, char *, __mode_t, __dev_t);\n\tint (*truncate)(struct inode *, __off_t);\n\tint (*create)(struct inode *, char *, int, __mode_t, struct inode **);\n\tint (*rename)(struct inode *, struct inode *, struct inode *, struct inode *, char *, char *);\n\n/* block device I/O operations */\n\tint (*read_block)(__dev_t, __blk_t, char *, int);\n\tint (*write_block)(__dev_t, __blk_t, char *, int);\n\n/* superblock operations */\n\tint (*read_inode)(struct inode *);\n\tint (*write_inode)(struct inode *);\n\tint (*ialloc)(struct inode *, int);\n\tvoid (*ifree)(struct inode *);\n\tvoid (*statfs)(struct superblock *, struct statfs *);\n\tint (*read_superblock)(__dev_t, struct superblock *);\n\tint (*remount_fs)(struct superblock *, int);\n\tint (*write_superblock)(struct superblock *);\n\tvoid (*release_superblock)(struct superblock *);\n};\n\nextern struct fs_operations def_chr_fsop;\nextern struct fs_operations def_blk_fsop;\n\n/* fs_minix.h prototypes */\nextern struct fs_operations minix_fsop;\nextern struct fs_operations minix_file_fsop;\nextern struct fs_operations minix_dir_fsop;\nextern struct fs_operations minix_symlink_fsop;\nextern int minix_count_free_inodes(struct superblock *);\nextern int minix_count_free_blocks(struct superblock *);\nextern int minix_find_first_zero(struct superblock *, __blk_t, int, int);\nextern int minix_change_bit(int, struct superblock *, int, int);\nextern int minix_balloc(struct superblock *);\nextern void minix_bfree(struct superblock *, int);\n\n/* fs_ext2.h prototypes */\nextern struct fs_operations ext2_fsop;\nextern struct fs_operations ext2_file_fsop;\nextern struct fs_operations ext2_dir_fsop;\nextern struct fs_operations ext2_symlink_fsop;\nextern int ext2_balloc(struct superblock *);\nextern void ext2_bfree(struct superblock *, int);\n\n/* fs_proc.h prototypes */\nextern struct fs_operations procfs_fsop;\nextern struct fs_operations procfs_file_fsop;\nextern struct fs_operations procfs_dir_fsop;\nextern struct fs_operations procfs_symlink_fsop;\nstruct procfs_dir_entry *get_procfs_by_inode(struct inode *);\n\n/* fs_iso9660.h prototypes */\nextern int isonum_711(char *);\nextern int isonum_723(char *);\nextern int isonum_731(char *);\nextern int isonum_733(char *);\nextern unsigned int isodate(const char *);\nextern int iso9660_cleanfilename(char *, int);\nextern struct fs_operations iso9660_fsop;\nextern struct fs_operations iso9660_file_fsop;\nextern struct fs_operations iso9660_dir_fsop;\nextern struct fs_operations iso9660_symlink_fsop;\nvoid check_rrip_inode(struct iso9660_directory_record *, struct inode *);\nint get_rrip_filename(struct iso9660_directory_record *, struct inode *, char *);\nint get_rrip_symlink(struct inode *, char *);\n\n/* fs_devpts.h prototypes */\nextern struct fs_operations devpts_fsop;\nextern struct fs_operations devpts_dir_fsop;\n\n\n/* generic VFS function prototypes */\nvoid inode_lock(struct inode *);\nvoid inode_unlock(struct inode *);\nstruct inode *ialloc(struct superblock *, int);\nstruct inode *iget(struct superblock *, __ino_t);\nint bmap(struct inode *, __off_t, int);\nint check_fs_busy(__dev_t, struct inode *);\nvoid iput(struct inode *);\nvoid sync_inodes(__dev_t);\nvoid invalidate_inodes(__dev_t);\nvoid inode_init(void);\n\nint parse_namei(char *, struct inode *, struct inode **, struct inode **, int);\nint namei(char *, struct inode **, struct inode **, int);\n\nvoid superblock_lock(struct superblock *);\nvoid superblock_unlock(struct superblock *);\nstruct mount *add_mount_point(__dev_t, const char *, const char *);\nvoid del_mount_point(struct mount *);\nstruct mount *get_mount_point(struct inode *);\n\nint get_new_fd(struct inode *);\nvoid release_fd(unsigned int);\nint get_new_user_fd(int);\nvoid release_user_fd(int);\nvoid fd_init(void);\n\nvoid free_name(const char *);\nint malloc_name(const char *, char **);\nint check_user_permission(struct inode *);\nint check_group(struct inode *);\nint check_user_area(int, const void *, unsigned int);\nint check_permission(int, struct inode *);\n\nint do_mknod(char *, __mode_t, __dev_t);\nint do_select(int, fd_set *, fd_set *, fd_set *, fd_set *, fd_set *, fd_set *);\n\n#endif /* _FIWIX_FS_H */\n"
  },
  {
    "path": "include/fiwix/fs_devpts.h",
    "content": "/*\n * fiwix/include/fiwix/fs_devpts.h\n *\n * Copyright 2025, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifdef CONFIG_UNIX98_PTYS\n\n#ifndef _FIWIX_FS_DEVPTS_H\n#define _FIWIX_FS_DEVPTS_H\n\n#include <fiwix/types.h>\n\n#define DEVPTS_ROOT_INO\t\t1\t/* root inode */\n#define DEVPTS_SUPER_MAGIC\t0x1CD1\t/* same as in Linux */\n\n#define NR_PTYS\t\t\t64\n\nextern struct fs_operations devpts_fsop;\n\nstruct devpts_files {\n\tint count;\n\tstruct inode *inode;\n};\nextern struct devpts_files *devpts_list;\n\n#endif /* _FIWIX_FS_DEVPTS_H */\n\n#endif /* CONFIG_UNIX98_PTYS */\n"
  },
  {
    "path": "include/fiwix/fs_ext2.h",
    "content": "/*\n * fiwix/include/fiwix/fs_ext2.h\n *\n * This file from: Linux 2.0.40\n * Copyright (C) 1992, 1993, 1994, 1995\n * Remy Card (card@masi.ibp.fr)\n * Laboratoire MASI - Institut Blaise Pascal\n * Universite Pierre et Marie Curie (Paris VI)\n * Copyright (C) 1991, 1992  Linus Torvalds\n */\n\n#ifndef _FIWIX_FS_EXT2_H\n#define _FIWIX_FS_EXT2_H\n\n#include <fiwix/types.h>\n\n#define EXT2_ROOT_INO\t\t 2\t/* Root inode */\n#define EXT2_SUPER_MAGIC\t0xEF53\n\n/*\n * Macro-instructions used to manage several block sizes\n */\n#define EXT2_MIN_BLOCK_SIZE\t\t1024\n#define\tEXT2_MAX_BLOCK_SIZE\t\t4096\n#define EXT2_MIN_BLOCK_LOG_SIZE\t\t  10\n# define EXT2_BLOCK_SIZE(s)\t\t((s)->s_blocksize)\n# define EXT2_BLOCK_SIZE_BITS(s)\t((s)->s_blocksize_bits)\n\n/*\n * Structure of a blocks group descriptor\n */\nstruct ext2_group_desc\n{\n\t__u32\tbg_block_bitmap;\t/* Blocks bitmap block */\n\t__u32\tbg_inode_bitmap;\t/* Inodes bitmap block */\n\t__u32\tbg_inode_table;\t\t/* Inodes table block */\n\t__u16\tbg_free_blocks_count;\t/* Free blocks count */\n\t__u16\tbg_free_inodes_count;\t/* Free inodes count */\n\t__u16\tbg_used_dirs_count;\t/* Directories count */\n\t__u16\tbg_pad;\n\t__u32\tbg_reserved[3];\n};\n\n/*\n * Macro-instructions used to manage group descriptors\n */\n#define EXT2_BLOCKS_PER_GROUP(s)\t((s)->u.ext2.sb.s_blocks_per_group)\n#define EXT2_INODES_PER_GROUP(s)\t((s)->u.ext2.sb.s_inodes_per_group)\n# define EXT2_DESC_PER_BLOCK_BITS(s)\t((s)->u.ext2_sb.s_desc_per_block_bits)\n#define EXT2_DESC_PER_BLOCK(s)\t\t((s)->u.ext2.desc_per_block)\n\n/*\n * Constants relative to the data blocks\n */\n#define\tEXT2_NDIR_BLOCKS\t\t12\n#define\tEXT2_IND_BLOCK\t\t\tEXT2_NDIR_BLOCKS\n#define\tEXT2_DIND_BLOCK\t\t\t(EXT2_IND_BLOCK + 1)\n#define\tEXT2_TIND_BLOCK\t\t\t(EXT2_DIND_BLOCK + 1)\n#define\tEXT2_N_BLOCKS\t\t\t(EXT2_TIND_BLOCK + 1)\n\n/*\n * Structure of an inode on the disk\n */\nstruct ext2_inode {\n\t__u16\ti_mode;\t\t/* File mode */\n\t__u16\ti_uid;\t\t/* Low 16 bits of Owner Uid */\n\t__u32\ti_size;\t\t/* Size in bytes */\n\t__u32\ti_atime;\t/* Access time */\n\t__u32\ti_ctime;\t/* Creation time */\n\t__u32\ti_mtime;\t/* Modification time */\n\t__u32\ti_dtime;\t/* Deletion Time */\n\t__u16\ti_gid;\t\t/* Low 16 bits of Group Id */\n\t__u16\ti_links_count;\t/* Links count */\n\t__u32\ti_blocks;\t/* Blocks count */\n\t__u32\ti_flags;\t/* File flags */\n\tunion {\n\t\tstruct {\n\t\t\t__u32  l_i_reserved1;\n\t\t} linux1;\n\t\tstruct {\n\t\t\t__u32  h_i_translator;\n\t\t} hurd1;\n\t\tstruct {\n\t\t\t__u32  m_i_reserved1;\n\t\t} masix1;\n\t} osd1;\t\t\t\t/* OS dependent 1 */\n\t__u32\ti_block[EXT2_N_BLOCKS];/* Pointers to blocks */\n\t__u32\ti_generation;\t/* File version (for NFS) */\n\t__u32\ti_file_acl;\t/* File ACL */\n\t__u32\ti_dir_acl;\t/* Directory ACL */\n\t__u32\ti_faddr;\t/* Fragment address */\n\tunion {\n\t\tstruct {\n\t\t\t__u8\tl_i_frag;\t/* Fragment number */\n\t\t\t__u8\tl_i_fsize;\t/* Fragment size */\n\t\t\t__u16\ti_pad1;\n\t\t\t__u16\tl_i_uid_high;\t/* these 2 fields    */\n\t\t\t__u16\tl_i_gid_high;\t/* were reserved2[0] */\n\t\t\t__u32\tl_i_reserved2;\n\t\t} linux2;\n\t\tstruct {\n\t\t\t__u8\th_i_frag;\t/* Fragment number */\n\t\t\t__u8\th_i_fsize;\t/* Fragment size */\n\t\t\t__u16\th_i_mode_high;\n\t\t\t__u16\th_i_uid_high;\n\t\t\t__u16\th_i_gid_high;\n\t\t\t__u32\th_i_author;\n\t\t} hurd2;\n\t\tstruct {\n\t\t\t__u8\tm_i_frag;\t/* Fragment number */\n\t\t\t__u8\tm_i_fsize;\t/* Fragment size */\n\t\t\t__u16\tm_pad1;\n\t\t\t__u32\tm_i_reserved2[2];\n\t\t} masix2;\n\t} osd2;\t\t\t\t/* OS dependent 2 */\n};\n\n/*\n * File system states\n */\n#define\tEXT2_VALID_FS\t\t\t0x0001\t/* Unmounted cleanly */\n#define\tEXT2_ERROR_FS\t\t\t0x0002\t/* Errors detected */\n\n/*\n * Structure of the super block\n */\nstruct ext2_super_block {\n\t__u32\ts_inodes_count;\t\t/* Inodes count */\n\t__u32\ts_blocks_count;\t\t/* Blocks count */\n\t__u32\ts_r_blocks_count;\t/* Reserved blocks count */\n\t__u32\ts_free_blocks_count;\t/* Free blocks count */\n\t__u32\ts_free_inodes_count;\t/* Free inodes count */\n\t__u32\ts_first_data_block;\t/* First Data Block */\n\t__u32\ts_log_block_size;\t/* Block size */\n\t__s32\ts_log_frag_size;\t/* Fragment size */\n\t__u32\ts_blocks_per_group;\t/* # Blocks per group */\n\t__u32\ts_frags_per_group;\t/* # Fragments per group */\n\t__u32\ts_inodes_per_group;\t/* # Inodes per group */\n\t__u32\ts_mtime;\t\t/* Mount time */\n\t__u32\ts_wtime;\t\t/* Write time */\n\t__u16\ts_mnt_count;\t\t/* Mount count */\n\t__s16\ts_max_mnt_count;\t/* Maximal mount count */\n\t__u16\ts_magic;\t\t/* Magic signature */\n\t__u16\ts_state;\t\t/* File system state */\n\t__u16\ts_errors;\t\t/* Behaviour when detecting errors */\n\t__u16\ts_minor_rev_level; \t/* minor revision level */\n\t__u32\ts_lastcheck;\t\t/* time of last check */\n\t__u32\ts_checkinterval;\t/* max. time between checks */\n\t__u32\ts_creator_os;\t\t/* OS */\n\t__u32\ts_rev_level;\t\t/* Revision level */\n\t__u16\ts_def_resuid;\t\t/* Default uid for reserved blocks */\n\t__u16\ts_def_resgid;\t\t/* Default gid for reserved blocks */\n\t/*\n\t * These fields are for EXT2_DYNAMIC_REV superblocks only.\n\t *\n\t * Note: the difference between the compatible feature set and\n\t * the incompatible feature set is that if there is a bit set\n\t * in the incompatible feature set that the kernel doesn't\n\t * know about, it should refuse to mount the filesystem.\n\t * \n\t * e2fsck's requirements are more strict; if it doesn't know\n\t * about a feature in either the compatible or incompatible\n\t * feature set, it must abort and not try to meddle with\n\t * things it doesn't understand...\n\t */\n\t__u32\ts_first_ino; \t\t/* First non-reserved inode */\n\t__u16   s_inode_size; \t\t/* size of inode structure */\n\t__u16\ts_block_group_nr; \t/* block group # of this superblock */\n\t__u32\ts_feature_compat; \t/* compatible feature set */\n\t__u32\ts_feature_incompat; \t/* incompatible feature set */\n\t__u32\ts_feature_ro_compat; \t/* readonly-compatible feature set */\n\t__u8\ts_uuid[16];\t\t/* 128-bit uuid for volume */\n\tchar\ts_volume_name[16]; \t/* volume name */\n\tchar\ts_last_mounted[64]; \t/* directory where last mounted */\n\t__u32\ts_algorithm_usage_bitmap; /* For compression */\n\t/*\n\t * Performance hints.  Directory preallocation should only\n\t * happen if the EXT2_COMPAT_PREALLOC flag is on.\n\t */\n\t__u8\ts_prealloc_blocks;\t/* Nr of blocks to try to preallocate*/\n\t__u8\ts_prealloc_dir_blocks;\t/* Nr to preallocate for dirs */\n\t__u16\ts_padding1;\n\t/*\n\t * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.\n\t */\n\t__u8\ts_journal_uuid[16];\t/* uuid of journal superblock */\n\t__u32\ts_journal_inum;\t\t/* inode number of journal file */\n\t__u32\ts_journal_dev;\t\t/* device number of journal file */\n\t__u32\ts_last_orphan;\t\t/* start of list of inodes to delete */\n\t__u32\ts_hash_seed[4];\t\t/* HTREE hash seed */\n\t__u8\ts_def_hash_version;\t/* Default hash version to use */\n\t__u8\ts_reserved_char_pad;\n\t__u16\ts_reserved_word_pad;\n\t__u32\ts_default_mount_opts;\n \t__u32\ts_first_meta_bg; \t/* First metablock block group */\n\t__u32\ts_reserved[190];\t/* Padding to the end of the block */\n};\n\n/*\n * Structure of a directory entry\n */\n#define EXT2_NAME_LEN 255\n\nstruct ext2_dir_entry {\n\t__u32\tinode;\t\t\t/* Inode number */\n\t__u16\trec_len;\t\t/* Directory entry length */\n\t__u16\tname_len;\t\t/* Name length */\n\tchar\tname[EXT2_NAME_LEN];\t/* File name */\n};\n\n/*\n * EXT2_DIR_PAD defines the directory entries boundaries\n *\n * NOTE: It must be a multiple of 4\n */\n#define EXT2_DIR_PAD\t\t\t4\n#define EXT2_DIR_ROUND\t\t\t(EXT2_DIR_PAD - 1)\n#define EXT2_DIR_REC_LEN(name_len)\t(((name_len) + 8 + EXT2_DIR_ROUND) & \\\n\t\t\t\t\t~EXT2_DIR_ROUND)\n\n/*\n * The new version of the directory entry.  Since EXT2 structures are\n * stored in intel byte order, and the name_len field could never be\n * bigger than 255 chars, it's safe to reclaim the extra byte for the\n * file_type field.\n */\nstruct ext2_dir_entry_2 {\n\t__u32\tinode;\t\t\t/* Inode number */\n\t__u16\trec_len;\t\t/* Directory entry length */\n\t__u8\tname_len;\t\t/* Name length */\n\t__u8\tfile_type;\n\tchar\tname[EXT2_NAME_LEN];\t/* File name */\n};\n\n/*\n * Ext2 directory file types.  Only the low 3 bits are used.  The\n * other bits are reserved for now.\n */\n#define EXT2_FT_UNKNOWN\t\t0\n#define EXT2_FT_REG_FILE\t1\n#define EXT2_FT_DIR\t\t2\n#define EXT2_FT_CHRDEV\t\t3\n#define EXT2_FT_BLKDEV\t\t4\n#define EXT2_FT_FIFO\t\t5\n#define EXT2_FT_SOCK\t\t6\n#define EXT2_FT_SYMLINK\t\t7\n\n/* superblock in memory */\nstruct ext2_sb_info {\n\tunsigned int desc_per_block;\n\tunsigned int block_groups;\n\tstruct ext2_super_block sb;\n};\n\n/* inode in memory */\nstruct ext2_i_info {\n\t__u32\ti_data[EXT2_N_BLOCKS];\t/* Pointers to blocks */\n\t__u32\ti_dtime;\n};\n\n#endif\t/* _FIWIX_FS_EXT2_H */\n"
  },
  {
    "path": "include/fiwix/fs_iso9660.h",
    "content": "/*\n * fiwix/include/fiwix/fs_iso9660.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_FS_ISO9660_H\n#define _FIWIX_FS_ISO9660_H\n\n#include <fiwix/types.h>\n#include <fiwix/limits.h>\n\n#define ISO9660_SUPERBLOCK\t16\t/* ISO9660 superblock is in block 16 */\n#define ISO9660_STANDARD_ID\t\"CD001\"\t/* standard identification */\n#define ISO9660_SUPER_MAGIC\t0x9660\n\n#define ISO9660_VD_BOOT\t\t\t0\n#define ISO9660_VD_PRIMARY\t\t1\n#define ISO9660_VD_SUPPLEMENTARY\t2\n#define ISO9660_VD_PARTITION\t\t3\n#define ISO9660_VD_END\t\t\t255\n\n#define ISODCL(from, to)\t((to - from) + 1)\t/* descriptor length */\n\n#define ISO9660_MAX_VD\t\t10\t/* maximum number of VD per CDROM */\n\n/* inodes will have their directory block and their offset packed as follows:\n * 7FF7FF\n * \\-/\\-/\n *  ^  ^\n *  |  +----- offset value\t\t\t(11bit entries)\n *  +-------- directory block where to find it \t(11bit entries)\n */\n#define ISO9660_INODE_BITS\t11\t/* FIXME: it could be greater (16bit) */\n#define ISO9660_INODE_MASK\t0x7FF\n\n#define ISO9660_FILE_NOTEXIST\t0x01\t/* file shouldn't exists for the user */\n#define ISO9660_FILE_ISDIR\t0x02\t/* is a directory */\n#define ISO9660_FILE_ISASSOC\t0x04\t/* associated file */\n#define ISO9660_FILE_HASRECFMT\t0x08\t/* has a record format */\n#define ISO9660_FILE_HASOWNER\t0x10\t/* has owner and group defined */\n#define ISO9660_FILE_RESERVED5\t0x20\t/* reserved */\n#define ISO9660_FILE_RESERVED6\t0x40\t/* reserved */\n#define ISO9660_FILE_ISMULTIEXT\t0x80\t/* has more directory records */\n\n#define SP_MAGIC1\t\t0xBE\n#define SP_MAGIC2\t\t0xEF\n#define GET_SIG(s1, s2)\t\t((s1 << 8) | s2)\n\n#define SL_CURRENT\t\t0x02\n#define SL_PARENT\t\t0x04\n#define SL_ROOT\t\t\t0x08\n\n#define TF_CREATION\t\t0x01\n#define TF_MODIFY\t\t0x02\n#define TF_ACCESS\t\t0x04\n#define TF_ATTRIBUTES\t\t0x08\n#define TF_BACKUP\t\t0x10\n#define TF_EXPIRATION\t\t0x20\n#define TF_EFFECTIVE\t\t0x40\n#define TF_LONG_FORM\t\t0x80\n\n#define NM_CONTINUE\t\t0\n#define NM_CURRENT\t\t1\n#define NM_PARENT\t\t2\n\n/* Primary Volume Descriptor */\nstruct iso9660_super_block {\n\tchar type\t\t\t[ISODCL(  1,   1)];\t/* 7.1.1 */\n\tchar id\t\t\t\t[ISODCL(  2,   6)];\n\tchar version\t\t\t[ISODCL(  7,   7)];\t/* 7.1.1 */\n\tchar unused1\t\t\t[ISODCL(  8,   8)];\n\tchar system_id\t\t\t[ISODCL(  9,  40)];\t/* a-chars */\n\tchar volume_id\t\t\t[ISODCL( 41,  72)];\t/* d-chars */\n\tchar unused2\t\t\t[ISODCL( 73,  80)];\n\tchar volume_space_size\t\t[ISODCL( 81,  88)];\t/* 7.3.3 */\n\tchar unused3\t\t\t[ISODCL( 89, 120)];\n\tchar volume_set_size\t\t[ISODCL(121, 124)];\t/* 7.2.3 */\n\tchar volume_sequence_number\t[ISODCL(125, 128)];\t/* 7.2.3 */\n\tchar logical_block_size\t\t[ISODCL(129, 132)];\t/* 7.2.3 */\n\tchar path_table_size\t\t[ISODCL(133, 140)];\t/* 7.3.3 */\n\tchar type_l_path_table\t\t[ISODCL(141, 144)];\t/* 7.3.1 */\n\tchar opt_type_l_path_table\t[ISODCL(145, 148)];\t/* 7.3.1 */\n\tchar type_m_path_table\t\t[ISODCL(149, 152)];\t/* 7.3.2 */\n\tchar opt_type_m_path_table\t[ISODCL(153, 156)];\t/* 7.3.2 */\n\tchar root_directory_record\t[ISODCL(157, 190)];\t/* 9.1 */\n\tchar volume_set_id\t\t[ISODCL(191, 318)];\t/* d-chars */\n\tchar publisher_id\t\t[ISODCL(319, 446)];\t/* a-chars */\n\tchar preparer_id\t\t[ISODCL(447, 574)];\t/* a-chars */\n\tchar application_id\t\t[ISODCL(575, 702)];\t/* a-chars */\n\tchar copyright_file_id\t\t[ISODCL(703, 739)];\t/* 7.5 d-chars */\n\tchar abstract_file_id\t\t[ISODCL(740, 776)];\t/* 7.5 d-chars */\n\tchar bibliographic_file_id\t[ISODCL(777, 813)];\t/* 7.5 d-chars */\n\tchar creation_date\t\t[ISODCL(814, 830)];\t/* 8.4.26.1 */\n\tchar modification_date\t\t[ISODCL(831, 847)];\t/* 8.4.26.1 */\n\tchar expiration_date\t\t[ISODCL(848, 864)];\t/* 8.4.26.1 */\n\tchar effective_date\t\t[ISODCL(865, 881)];\t/* 8.4.26.1 */\n\tchar file_structure_version\t[ISODCL(882, 882)];\n\tchar unused4\t\t\t[ISODCL(883, 883)];\n\tchar application_data\t\t[ISODCL(884, 1395)];\n\tchar unused5\t\t\t[ISODCL(1396, 2048)];\n};\n\nstruct iso9660_directory_record\n{\n\tchar length\t\t\t[ISODCL( 1,  1)];\t/* 7.1.1 */\n\tchar ext_attr_length\t\t[ISODCL( 2,  2)];\t/* 7.1.1 */\n\tchar extent\t\t\t[ISODCL( 3, 10)];\t/* 7.3.3 */\n\tchar size\t\t\t[ISODCL(11, 18)];\t/* 7.3.3 */\n\tchar date\t\t\t[ISODCL(19, 25)];\t/* 7 by 7.1.1 */\n\tchar flags\t\t\t[ISODCL(26, 26)];\n\tchar file_unit_size\t\t[ISODCL(27, 27)];\t/* 7.1.1 */\n\tchar interleave\t\t\t[ISODCL(28, 28)];\t/* 7.1.1 */\n\tchar volume_sequence_number\t[ISODCL(29, 32)];\t/* 7.2.3 */\n\tchar name_len\t\t\t[ISODCL(33, 33)];\t/* 7.1.1 */\n\tchar name[0];\n};\n\nstruct iso9660_pathtable_record\n{\n\tchar length\t\t\t[ISODCL( 1,  1)];\t/* 7.1.1 */\n\tchar ext_attr_length\t\t[ISODCL( 2,  2)];\t/* 7.1.1 */\n\tchar extent\t\t\t[ISODCL( 3,  6)];\t/* 7.3 */\n\tchar parent\t\t\t[ISODCL( 7,  8)];\t/* 7.2 */\n\tchar name[0];\n};\n\nstruct susp_sp {\n\tunsigned char magic[2];\n\tchar len_skip;\n};\n\nstruct susp_ce {\n\tchar block[8];\n\tchar offset[8];\n\tchar size[8];\n};\n\nstruct susp_er {\n\tchar len_id;\n\tchar len_des;\n\tchar len_src;\n\tchar ext_ver;\n\tchar data[0];\n};\n\nstruct rrip_px {\n\tchar mode[8];\n\tchar nlink[8];\n\tchar uid[8];\n\tchar gid[8];\n\tchar sn[8];\n};\n\nstruct rrip_pn {\n\tchar dev_h[8];\n\tchar dev_l[8];\n};\n\nstruct rrip_sl_component {\n\tunsigned char flags;\n\tunsigned char len;\n\tchar name[0];\n};\n\nstruct rrip_sl {\n\tunsigned char flags;\n\tstruct rrip_sl_component area;\n};\n\nstruct rrip_nm {\n\tunsigned char flags;\n\tchar name[0];\n};\n\nstruct rrip_tf_timestamp {\n\tchar time[7];\t\t/* assumes LONG_FORM bit always set to zero */\n};\n\nstruct rrip_tf {\n\tchar flags;\n\tstruct rrip_tf_timestamp times[0];\n};\n\nstruct susp_rrip {\n\tchar signature[2];\n\tunsigned char len;\n\tunsigned char version;\n\tunion {\n\t\tstruct susp_sp sp;\n\t\tstruct susp_ce ce;\n\t\tstruct susp_er er;\n\t\tstruct rrip_px px;\n\t\tstruct rrip_pn pn;\n\t\tstruct rrip_sl sl;\n\t\tstruct rrip_nm nm;\n\t\tstruct rrip_tf tf;\n\t} u;\n};\n\nstruct iso9660_inode {\n\t__blk_t i_extent;\n\tstruct inode *i_parent;\t\t/* inode of its parent directory */\n};\n\nstruct iso9660_sb_info {\n\t__u32 s_root_inode;\n\tchar *pathtable_raw;\n\tstruct iso9660_pathtable_record **pathtable;\n\tint paths;\n\tunsigned char rrip;\n\tstruct iso9660_super_block *sb;\n};\n\n#endif /* _FIWIX_FS_ISO9660_H */\n"
  },
  {
    "path": "include/fiwix/fs_minix.h",
    "content": "/*\n * fiwix/include/fiwix/fs_minix.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifdef CONFIG_FS_MINIX\n\n#ifndef _FIWIX_FS_MINIX_H\n#define _FIWIX_FS_MINIX_H\n\n#include <fiwix/types.h>\n#include <fiwix/limits.h>\n\n#define MINIX_ROOT_INO\t\t1\t/* root inode */\n\n#define MINIX_SUPER_MAGIC\t0x137F\t/* Minix v1, 14 char names */\n#define MINIX_SUPER_MAGIC2\t0x138F\t/* Minix v1, 30 char names */\n#define MINIX2_SUPER_MAGIC\t0x2468\t/* Minix v2, 14 char names */\n#define MINIX2_SUPER_MAGIC2\t0x2478\t/* Minix v2, 30 char names */\n\n#define MINIX_VALID_FS\t\t1\t/* clean filesystem */\n#define MINIX_ERROR_FS\t\t2\t/* needs fsck */\n\n#define V1_MAX_BITMAP_BLOCKS\t8\t/* 64MB filesystem size */\n#define V2_MAX_BITMAP_BLOCKS\t128\t/* 1GB filesystem size */\n\n/*\n * Minix (v1 and v2) file system physical layout:\n *\n * \t\t +-----------------------------------------------\n * \t\t |   size in blocks of BLKSIZE_1K (1024 bytes)\t|\n * +-------------+----------------------------------------------+\n * | block 0     |\t\t\t\t\t      1 |\n * +-------------+----------------------------------------------+\n * | superblock  |\t\t\t\t\t      1 |\n * +-------------+----------------------------------------------+\n * | inode map   |\t    number of inodes / (BLKSIZE_1K * 8) | \n * +-------------+----------------------------------------------+\n * | zone map    |\t     number of zones / (BLKSIZE_1K * 8) | \n * +-------------+----------------------------------------------+\n * | inode table | ((32 or 64) * number of inodes) / BLKSIZE_1K |\n * +-------------+----------------------------------------------+\n * | data zones  |\t\t\t\t\t    ... | \n * +-------------+----------------------------------------------+\n *\n * The implementation of this filesystem in Fiwix might have slow disk writes\n * because I don't keep in memory the superblock, nor the blocks of the inode\n * map nor the blocks of the zone map. Keeping them in memory would be a waste\n * of 137KB per each mounted v2 filesystem (1GB of size).\n *\n * - superblock    ->   1KB\n * - inode map     ->   8KB (1KB (8192 bits) x   8 = 65536 inodes)\n * - zone map      -> 128KB (1KB (8192 bits) x 128 = 1048576 1k-blocks)\n *\n */\n\nstruct minix_super_block {\n\t__u16 s_ninodes;\t\t/* number of inodes */\n\t__u16 s_nzones;\t\t\t/* number of data zones */\n\t__u16 s_imap_blocks;\t\t/* blocks used by inode bitmap */\n\t__u16 s_zmap_blocks;\t\t/* blocks used by zone bitmap */\n\t__u16 s_firstdatazone;\t\t/* number of first data zone */\n\t__u16 s_log_zone_size;\t\t/* 1024 << s_log_zone_size */\n\t__u32 s_max_size;\t\t/* maximum file size (in bytes) */\n\t__u16 s_magic;\t\t\t/* magic number */\n\t__u16 s_state;\t\t\t/* filesystem state */\n\t__u32 s_zones;\t\t\t/* number of data zones (for v2 only) */\n};\n\nstruct minix_inode {\n\t__u16 i_mode;\n\t__u16 i_uid;\n\t__u32 i_size;\n\t__u32 i_time;\n\t__u8  i_gid;\n\t__u8  i_nlinks;\n\t__u16 i_zone[9];\n};\n\nstruct minix2_inode {\n\t__u16 i_mode;\n\t__u16 i_nlink;\n\t__u16 i_uid;\n\t__u16 i_gid;\n\t__u32 i_size;\n\t__u32 i_atime;\n\t__u32 i_mtime;\n\t__u32 i_ctime;\n\t__u32 i_zone[10];\n};\n\nstruct minix_dir_entry {\n\t__u16 inode;\n\tchar name[0];\n};\n\n/* super block in memory */\nstruct minix_sb_info {\n\tunsigned char namelen;\n\tunsigned char dirsize;\n\tunsigned short int version;\n\tunsigned int nzones;\n\tstruct minix_super_block sb;\n};\n\n/* inode in memory */\nstruct minix_i_info {\n\tunion {\n\t\t__u16 i1_zone[9];\n\t\t__u32 i2_zone[10];\n\t} u;\n};\n\nint v1_minix_read_inode(struct inode *);\nint v1_minix_write_inode(struct inode *);\nint v1_minix_ialloc(struct inode *, int);\nvoid v1_minix_ifree(struct inode *);\nint v1_minix_bmap(struct inode *, __off_t, int);\nint v1_minix_truncate(struct inode *, __off_t);\n\nint v2_minix_read_inode(struct inode *);\nint v2_minix_write_inode(struct inode *);\nint v2_minix_ialloc(struct inode *, int);\nvoid v2_minix_ifree(struct inode *);\nint v2_minix_bmap(struct inode *, __off_t, int);\nint v2_minix_truncate(struct inode *, __off_t);\n\n#endif /* _FIWIX_FS_MINIX_H */\n\n#endif /* CONFIG_FS_MINIX */\n"
  },
  {
    "path": "include/fiwix/fs_pipe.h",
    "content": "/*\n * fiwix/include/fiwix/fs_pipe.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_FS_PIPE_H\n#define _FIWIX_FS_PIPE_H\n\nextern struct fs_operations pipefs_fsop;\n\nstruct pipefs_inode {\n\tchar *i_data;\t\t\t/* buffer */\n\tunsigned int i_readoff;\t\t/* offset for reads */\n\tunsigned int i_writeoff;\t/* offset for writes */\n\tunsigned int i_readers;\t\t/* number of readers */\n\tunsigned int i_writers;\t\t/* number of writers */\n};\n\n#endif /* _FIWIX_FS_PIPE_H */\n"
  },
  {
    "path": "include/fiwix/fs_proc.h",
    "content": "/*\n * fiwix/include/fiwix/fs_proc.h\n *\n * Copyright 2018-2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_FS_PROC_H\n#define _FIWIX_FS_PROC_H\n\n#include <fiwix/types.h>\n\n#define PROC_ROOT_INO\t\t1\t/* root inode */\n#define PROC_KMSG_INO\t\t13\t/* /proc/kmsg inode */\n#define PROC_SUPER_MAGIC\t0x9FA0\t/* same as in Linux */\n\n#define PROC_PID_INO\t\t0x40000000\t/* base for PID inodes */\n#define PROC_PID_LEV\t\t1\t/* array level for PIDs */\n\n#define PROC_FD_INO\t\t0x50000000\t/* base for FD inodes */\n#define PROC_FD_LEV\t\t2\t/* array level for FDs */\n\n#define PROC_ARRAY_ENTRIES\t25\n\nenum pid_dir_inodes {\n\tPROC_PID_FD = PROC_PID_INO + 1001,\n\tPROC_PID_CMDLINE,\n\tPROC_PID_CWD,\n\tPROC_PID_ENVIRON,\n\tPROC_PID_EXE,\n\tPROC_PID_MAPS,\n\tPROC_PID_MOUNTINFO,\n\tPROC_PID_ROOT,\n\tPROC_PID_STAT,\n\tPROC_PID_STATM,\n\tPROC_PID_STATUS\n};\n\nstruct procfs_inode {\n\tunsigned int i_lev;\t\t/* array level (directory depth) */\n};\n\nstruct procfs_dir_entry {\n\t__ino_t inode;\n\t__mode_t mode;\n\t__nlink_t nlink;\n\tint lev;\t\t\t/* array level (directory depth) */\n\tunsigned short int name_len;\n\tchar *name;\n\tint (*data_fn)(char *, __pid_t);\n};\n\nextern struct procfs_dir_entry procfs_array[][PROC_ARRAY_ENTRIES + 1];\nextern struct fs_operations procfs_kmsg_fsop;\n\nint data_proc_buddyinfo(char *, __pid_t);\nint data_proc_cmdline(char *, __pid_t);\nint data_proc_cpuinfo(char *, __pid_t);\nint data_proc_devices(char *, __pid_t);\nint data_proc_dma(char *, __pid_t);\nint data_proc_filesystems(char *, __pid_t);\nint data_proc_interrupts(char *, __pid_t);\nint data_proc_loadavg(char *, __pid_t);\nint data_proc_locks(char *, __pid_t);\nint data_proc_meminfo(char *, __pid_t);\nint data_proc_mounts(char *, __pid_t);\nint data_proc_partitions(char *, __pid_t);\nint data_proc_pci(char *, __pid_t);\nint data_proc_rtc(char *, __pid_t);\nint data_proc_self(char *, __pid_t);\nint data_proc_stat(char *, __pid_t);\nint data_proc_uptime(char *, __pid_t);\nint data_proc_fullversion(char *, __pid_t);\nint data_proc_unix(char *, __pid_t);\nint data_proc_pci_devices(char *, __pid_t);\nint data_proc_buffernr(char *, __pid_t);\nint data_proc_domainname(char *, __pid_t);\nint data_proc_filemax(char *, __pid_t);\nint data_proc_filenr(char *, __pid_t);\nint data_proc_hostname(char *, __pid_t);\nint data_proc_inodemax(char *, __pid_t);\nint data_proc_inodenr(char *, __pid_t);\nint data_proc_osrelease(char *, __pid_t);\nint data_proc_ostype(char *, __pid_t);\nint data_proc_version(char *, __pid_t);\nint data_proc_dirty_background_ratio(char *, __pid_t);\n\n/* PID related functions */\nint data_proc_pid_fd(char *, __pid_t, __ino_t);\nint data_proc_pid_cmdline(char *, __pid_t);\nint data_proc_pid_cwd(char *, __pid_t);\nint data_proc_pid_environ(char *, __pid_t);\nint data_proc_pid_exe(char *, __pid_t);\nint data_proc_pid_maps(char *, __pid_t);\nint data_proc_pid_mountinfo(char *, __pid_t);\nint data_proc_pid_root(char *, __pid_t);\nint data_proc_pid_stat(char *, __pid_t);\nint data_proc_pid_statm(char *, __pid_t);\nint data_proc_pid_status(char *, __pid_t);\n\n#endif /* _FIWIX_FS_PROC_H */\n"
  },
  {
    "path": "include/fiwix/fs_sock.h",
    "content": "/*\n * fiwix/include/fiwix/fs_sock.h\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifdef CONFIG_NET\n\n#ifndef _FIWIX_FS_SOCK_H\n#define _FIWIX_FS_SOCK_H\n\n#include <fiwix/net.h>\n\nextern struct fs_operations sockfs_fsop;\n\nstruct sockfs_inode {\n\tstruct socket sock;\n};\n\n#endif /* _FIWIX_FS_SOCK_H */\n\n#endif /* CONFIG_NET */\n"
  },
  {
    "path": "include/fiwix/i386elf.h",
    "content": "/*\n * fiwix/include/fiwix/i386elf.h\n */\n\n#ifndef _FIWIX_ELF_H\n#define _FIWIX_ELF_H\n\ntypedef unsigned long\tElf32_Addr;\ntypedef unsigned short\tElf32_Half;\ntypedef unsigned long\tElf32_Off;\ntypedef long\t\tElf32_Sword;\ntypedef unsigned long\tElf32_Word;\n\n#define\tELFMAG0\t\t0x7f\t\t/* EI_MAG */\n#define\tELFMAG1\t\t'E'\n#define\tELFMAG2\t\t'L'\n#define\tELFMAG3\t\t'F'\n#define\tELFMAG\t\t\"\\177ELF\"\n#define\tSELFMAG\t\t4\n\n#define EI_NIDENT\t16\n\ntypedef struct elf32_hdr{\n  unsigned char\te_ident[EI_NIDENT];\t/* ELF \"magic number\" */\n  Elf32_Half\te_type;\t\t\t/* File type */\n  Elf32_Half\te_machine;\t\t/* Target machine */\n  Elf32_Word\te_version;\t\t/* File version */\n  Elf32_Addr\te_entry;  \t\t/* Entry point virtual address */\n  Elf32_Off\te_phoff;\t\t/* Program header table file offset */\n  Elf32_Off\te_shoff;\t\t/* Section header table file offset */\n  Elf32_Word\te_flags;\t\t/* File flags */\n  Elf32_Half\te_ehsize;\t\t/* Sizeof Ehdr (ELF header) */\n  Elf32_Half\te_phentsize;\t\t/* Sizeof Phdr (Program header) */\n  Elf32_Half\te_phnum;\t\t/* Number Phdrs (Program header) */\n  Elf32_Half\te_shentsize;\t\t/* Sizeof Shdr (Section header) */\n  Elf32_Half\te_shnum;\t\t/* Number Shdrs (Section header) */\n  Elf32_Half\te_shstrndx;\t\t/* Shdr string index */\n} Elf32_Ehdr;\n\n#define\tEI_MAG0\t\t0\t\t/* e_ident[] indexes */\n#define\tEI_MAG1\t\t1\n#define\tEI_MAG2\t\t2\n#define\tEI_MAG3\t\t3\n#define\tEI_CLASS\t4\n#define\tEI_DATA\t\t5\n#define\tEI_VERSION\t6\n#define\tEI_PAD\t\t7\n\n#define\tELFCLASSNONE\t0\t\t/* EI_CLASS */\n#define\tELFCLASS32\t1\n#define\tELFCLASS64\t2\n#define\tELFCLASSNUM\t3\n\n#define ELFDATANONE\t0\t\t/* e_ident[EI_DATA] */\n#define ELFDATA2LSB\t1\n#define ELFDATA2MSB\t2\n#define\tELFDATANUM\t3\n\n/* ELF file types */\n#define ET_NONE   0\n#define ET_REL    1\n#define ET_EXEC   2\n#define ET_DYN    3\n#define ET_CORE   4\n#define ET_LOPROC 5\n#define ET_HIPROC 6\n\n#define EM_386    3\n\n#define EV_NONE\t\t0\t\t/* e_version, EI_VERSION */\n#define EV_CURRENT\t1\n#define EV_NUM\t\t2\n\ntypedef struct elf32_phdr{\n  Elf32_Word\tp_type;\t\t\t/* Entry type */\n  Elf32_Off\tp_offset;\t\t/* File offset */\n  Elf32_Addr\tp_vaddr;\t\t/* Virtual address */\n  Elf32_Addr\tp_paddr;\t\t/* Physical address */\n  Elf32_Word\tp_filesz;\t\t/* File size */\n  Elf32_Word\tp_memsz;\t\t/* Memory size */\n  Elf32_Word\tp_flags;\t\t/* Entry flags */\n  Elf32_Word\tp_align;\t\t/* Memory & file alignment */\n} Elf32_Phdr;\n\n/* segment types stored in the image headers */\n#define PT_NULL    0\n#define PT_LOAD    1\n#define PT_DYNAMIC 2\n#define PT_INTERP  3\n#define PT_NOTE    4\n#define PT_SHLIB   5\n#define PT_PHDR    6\n#define PT_NUM     7\n#define PT_LOPROC  0x70000000\n#define PT_HIPROC  0x7fffffff\n\n/* permission types on sections in the program header, p_flags. */\n#define PF_R\t0x4\n#define PF_W\t0x2\n#define PF_X\t0x1\n\n#define PF_MASKPROC\t0xf0000000\n\ntypedef struct {\n  Elf32_Word\tsh_name;\t\t/* Section name, index in string tbl */\n  Elf32_Word\tsh_type;\t\t/* Type of section */\n  Elf32_Word\tsh_flags;\t\t/* Miscellaneous section attributes */\n  Elf32_Addr\tsh_addr;\t\t/* Section virtual addr at execution */\n  Elf32_Off\tsh_offset;\t\t/* Section file offset */\n  Elf32_Word\tsh_size;\t\t/* Size of section in bytes */\n  Elf32_Word\tsh_link;\t\t/* Index of another section */\n  Elf32_Word\tsh_info;\t\t/* Additional section information */\n  Elf32_Word\tsh_addralign;\t\t/* Section alignment */\n  Elf32_Word\tsh_entsize;\t\t/* Entry size if section holds table */\n} Elf32_Shdr;\n\n/* sh_type */\n#define SHT_NULL\t0\n#define SHT_PROGBITS\t1\n#define SHT_SYMTAB\t2\n#define SHT_STRTAB\t3\n#define SHT_RELA\t4\n#define SHT_HASH\t5\n#define SHT_DYNAMIC\t6\n#define SHT_NOTE\t7\n#define SHT_NOBITS\t8\n#define SHT_REL\t\t9\n#define SHT_SHLIB\t10\n#define SHT_DYNSYM\t11\n#define SHT_NUM\t\t12\n\n#define SHT_LOPROC\t0x70000000\n#define SHT_HIPROC\t0x7fffffff\n#define SHT_LOUSER\t0x80000000\n#define SHT_HIUSER\t0xffffffff\n\n/* sh_flags */\n#define SHF_WRITE\t0x1\n#define SHF_ALLOC\t0x2\n#define SHF_EXECINSTR\t0x4\n\n/* special section indexes */\n#define SHN_UNDEF\t0\n#define SHN_LORESERVE\t0xff00\n#define SHN_ABS\t\t0xfff1\n#define SHN_COMMON\t0xfff2\n#define SHN_HIRESERVE\t0xffff\n#define SHN_LOPROC\t0xff00\n#define SHN_HIPROC\t0xff1f\n \ntypedef struct elf32_sym{\n  Elf32_Word\tst_name;\t\t/* Symbol name, index in string tbl */\n  Elf32_Addr\tst_value;\t\t/* Value of the symbol */\n  Elf32_Word\tst_size;\t\t/* Associated symbol size */\n  unsigned char\tst_info;\t\t/* Type and binding attributes */\n  unsigned char\tst_other;\t\t/* No defined meaning, 0 */\n  Elf32_Half\tst_shndx;\t\t/* Associated section index */\n} Elf32_Sym;\n\n#define ELF32_ST_BIND(info) \t((info) >> 4)\n#define ELF32_ST_TYPE(info) \t(((unsigned int) info) & 0xf)\n\n/* This info is needed when parsing the symbol table */\n#define STB_LOCAL  0\n#define STB_GLOBAL 1\n#define STB_WEAK   2\n#define STB_NUM    3\n\n#define STT_NOTYPE  0\n#define STT_OBJECT  1\n#define STT_FUNC    2\n#define STT_SECTION 3\n#define STT_FILE    4\n#define STT_NUM     5\n\ntypedef struct elf32_rel {\n  Elf32_Addr\tr_offset;\t/* Location at which to apply the action */\n  Elf32_Word\tr_info;\t\t/* Index and type of relocation */\n} Elf32_Rel;\n\ntypedef struct elf32_rela{\n  Elf32_Addr\tr_offset;\t/* Location at which to apply the action */\n  Elf32_Word\tr_info;\t\t/* Index and type of relocation */\n  Elf32_Sword\tr_addend;\t/* Constant addend used to compute value */\n} Elf32_Rela;\n\n/* The following are used with relocations */\n#define ELF32_R_SYM(info)\t((info) >> 8)\n#define ELF32_R_TYPE(info) \t((info) & 0xff)\n\n/* This is the info that is needed to parse the dynamic section of the file */\n#define DT_NULL\t\t0\n#define DT_NEEDED\t1\n#define DT_PLTRELSZ\t2\n#define DT_PLTGOT\t3\n#define DT_HASH\t\t4\n#define DT_STRTAB\t5\n#define DT_SYMTAB\t6\n#define DT_RELA\t\t7\n#define DT_RELASZ\t8\n#define DT_RELAENT\t9\n#define DT_STRSZ\t10\n#define DT_SYMENT\t11\n#define DT_INIT\t\t12\n#define DT_FINI\t\t13\n#define DT_SONAME\t14\n#define DT_RPATH \t15\n#define DT_SYMBOLIC\t16\n#define DT_REL\t        17\n#define DT_RELSZ\t18\n#define DT_RELENT\t19\n#define DT_PLTREL\t20\n#define DT_DEBUG\t21\n#define DT_TEXTREL\t22\n#define DT_JMPREL\t23\n#define DT_LOPROC\t0x70000000\n#define DT_HIPROC\t0x7fffffff\n\n/* Symbolic values for the entries in the auxiliary table\n   put on the initial stack */\n#define AT_NULL   0\t/* end of vector */\n#define AT_IGNORE 1\t/* entry should be ignored */\n#define AT_EXECFD 2\t/* file descriptor of program */\n#define AT_PHDR   3\t/* program headers for program */\n#define AT_PHENT  4\t/* size of program header entry */\n#define AT_PHNUM  5\t/* number of program headers */\n#define AT_PAGESZ 6\t/* system page size */\n#define AT_BASE   7\t/* base address of interpreter */\n#define AT_FLAGS  8\t/* flags */\n#define AT_ENTRY  9\t/* entry point of program */\n#define AT_NOTELF 10\t/* program is not ELF */\n#define AT_UID    11\t/* real uid */\n#define AT_EUID   12\t/* effective uid */\n#define AT_GID    13\t/* real gid */\n#define AT_EGID   14\t/* effective gid */\n\n\ntypedef struct dynamic{\n  Elf32_Sword d_tag;\t\t\t/* entry tabg value */\n  union{\n    Elf32_Sword\td_val;\n    Elf32_Addr\td_ptr;\n  } d_un;\n} Elf32_Dyn;\n\n#define R_386_NONE\t0\n#define R_386_32\t1\n#define R_386_PC32\t2\n#define R_386_GOT32\t3\n#define R_386_PLT32\t4\n#define R_386_COPY\t5\n#define R_386_GLOB_DAT\t6\n#define R_386_JMP_SLOT\t7\n#define R_386_RELATIVE\t8\n#define R_386_GOTOFF\t9\n#define R_386_GOTPC\t10\n#define R_386_NUM\t11\n\n/* Notes used in ET_CORE */\n#define NT_PRSTATUS\t1\n#define NT_PRFPREG\t2\n#define NT_PRPSINFO\t3\n#define NT_TASKSTRUCT\t4\n\n/* Note header in a PT_NOTE section */\ntypedef struct elf32_note {\n  Elf32_Word\tn_namesz;\t/* Name size */\n  Elf32_Word\tn_descsz;\t/* Content size */\n  Elf32_Word\tn_type;\t\t/* Content type */\n} Elf32_Nhdr;\n\n#define ELF_START_MMAP 0x80000000\n\nextern Elf32_Dyn _DYNAMIC [];\n#define elfhdr\t\telf32_hdr\n#define elf_phdr\telf32_phdr\n#define elf_note\telf32_note\n\n\nint check_elf(struct elf32_hdr *);\n\n#endif /* _FIWIX_ELF_H */\n"
  },
  {
    "path": "include/fiwix/ioctl.h",
    "content": "/*\n * fiwix/include/fiwix/ioctl.h\n */\n\n#ifndef _FIWIX_IOCTL_H\n#define _FIWIX_IOCTL_H\n\n#define HDIO_GETGEO\t0x0301\t/* get device geometry */\n\n#define BLKROSET\t0x125D\t/* set device read-only (0 = read-write) */\n#define BLKROGET\t0x125E\t/* get read-only status (0 = read_write) */\n#define BLKRRPART\t0x125F\t/* re-read partition table */\n#define BLKGETSIZE\t0x1260\t/* return device size */\n#define BLKFLSBUF\t0x1261\t/* flush buffer cache */\n#define BLKSSZGET\t0x1268\t/* get block device sector size */\n#define BLKBSZGET       0x1270\t/* get device block size */\n#define BLKBSZSET       0x1271\t/* set device block size */\n\n/* 0x54 is just a magic number to make these relatively unique ('T') */\n#define TCGETS\t\t0x5401\n#define TCSETS\t\t0x5402\n#define TCSETSW\t\t0x5403\n#define TCSETSF\t\t0x5404\n#define TCGETA\t\t0x5405\n#define TCSETA\t\t0x5406\n#define TCSETAW\t\t0x5407\n#define TCSETAF\t\t0x5408\n#define TCSBRK\t\t0x5409\n#define TCXONC\t\t0x540A\n#define TCFLSH\t\t0x540B\n#define TIOCEXCL\t0x540C\n#define TIOCNXCL\t0x540D\n#define TIOCSCTTY\t0x540E\n#define TIOCGPGRP\t0x540F\n#define TIOCSPGRP\t0x5410\n#define TIOCOUTQ\t0x5411\n#define TIOCSTI\t\t0x5412\n#define TIOCGWINSZ\t0x5413\n#define TIOCSWINSZ\t0x5414\n#define TIOCMGET\t0x5415\n#define TIOCMBIS\t0x5416\n#define TIOCMBIC\t0x5417\n#define TIOCMSET\t0x5418\n#define TIOCGSOFTCAR\t0x5419\n#define TIOCSSOFTCAR\t0x541A\n#define FIONREAD\t0x541B\n#define TIOCINQ\t\tFIONREAD\n#define TIOCLINUX\t0x541C\n#define TIOCCONS\t0x541D\n#define TIOCGSERIAL\t0x541E\n#define TIOCSSERIAL\t0x541F\n#define TIOCPKT\t\t0x5420\n#define FIONBIO\t\t0x5421\n#define TIOCNOTTY\t0x5422\n#define TIOCSETD\t0x5423\n#define TIOCGETD\t0x5424\n#define TCSBRKP\t\t0x5425\t/* Needed for POSIX tcsendbreak() */\n#define TIOCTTYGSTRUCT\t0x5426  /* For debugging only */\n#define TIOCSBRK\t0x5427  /* BSD compatibility */\n#define TIOCCBRK\t0x5428  /* BSD compatibility */\n#define TIOCGSID\t0x5429  /* Return the session ID of FD */\n#define TIOCGPTN\t0x80045430 /* Get Pty Number (of pty-mux device) */\n#define TIOCSPTLCK\t0x40045431 /* Lock/unlock Pty */\n\n#define FIONCLEX\t0x5450  /* these numbers need to be adjusted. */\n#define FIOCLEX\t\t0x5451\n#define FIOASYNC\t0x5452\n#define TIOCSERCONFIG\t0x5453\n#define TIOCSERGWILD\t0x5454\n#define TIOCSERSWILD\t0x5455\n#define TIOCGLCKTRMIOS\t0x5456\n#define TIOCSLCKTRMIOS\t0x5457\n#define TIOCSERGSTRUCT\t0x5458\t/* For debugging only */\n#define TIOCSERGETLSR   0x5459\t/* Get line status register */\n#define TIOCSERGETMULTI 0x545A\t/* Get multiport config  */\n#define TIOCSERSETMULTI 0x545B\t/* Set multiport config */\n\n#define TIOCMIWAIT\t0x545C\t/* wait for a change on serial input line(s) */\n#define TIOCGICOUNT\t0x545D\t/* read serial port inline interrupt counts */\n#define TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */\n#define TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */\n\n/* Used for packet mode */\n#define TIOCPKT_DATA\t\t 0\n#define TIOCPKT_FLUSHREAD\t 1\n#define TIOCPKT_FLUSHWRITE\t 2\n#define TIOCPKT_STOP\t\t 4\n#define TIOCPKT_START\t\t 8\n#define TIOCPKT_NOSTOP\t\t16\n#define TIOCPKT_DOSTOP\t\t32\n\n#define TIOCSER_TEMT    0x01\t/* Transmitter physically empty */\n\n#endif /* _FIWIX_IOCTL_H */\n"
  },
  {
    "path": "include/fiwix/ipc.h",
    "content": "/*\n * fiwix/include/fiwix/ipc.h\n */\n\n#ifdef CONFIG_SYSVIPC\n\n#ifndef _FIWIX_IPC_H\n#define _FIWIX_IPC_H\n\n#include <fiwix/types.h>\n#include <fiwix/sleep.h>\n\n#define IPC_CREAT\t01000\t\t/* create if key doesn't exist */\n#define IPC_EXCL\t02000\t\t/* fail if key exists */\n#define IPC_NOWAIT\t04000\t\t/* return error on wait */\n\n#define IPC_PRIVATE\t((key_t)0)\t/* private key */\n\n#define IPC_RMID\t0\t\t/* remove identifier */\n#define IPC_SET\t\t1\t\t/* set options */\n#define IPC_STAT\t2\t\t/* get options */\n#define IPC_INFO\t3\t\t/* get system-wide limits */\n\n#define IPC_R\t\t0400\t\t/* read or receive permission */\n#define IPC_W\t\t0200\t\t/* write or send permission */\n\n#define SEMOP\t\t1\n#define SEMGET\t\t2\n#define SEMCTL\t\t3\n#define MSGSND\t\t11\n#define MSGRCV\t\t12\n#define MSGGET\t\t13\n#define MSGCTL\t\t14\n#define SHMAT\t\t21\n#define SHMDT\t\t22\n#define SHMGET\t\t23\n#define SHMCTL\t\t24\n\n#define IPC_UNUSED\t((void *) -1)\n\ntypedef int key_t;\n\nstruct sysvipc_args {\n\tint arg1;\n\tint arg2;\n\tint arg3;\n\tvoid *ptr;\n\tint arg5;\n};\n\n/* IPC data structure */\nstruct ipc_perm {\n\tkey_t key;\t\t\t/* key */\n\t__uid_t uid;\t\t\t/* effective UID of owner */\n\t__gid_t gid;\t\t\t/* effective UID of owner */\n\t__uid_t cuid;\t\t\t/* effective UID of creator */\n\t__gid_t cgid;\t\t\t/* effective UID of creator */\n\tunsigned short int mode;\t/* access modes */\n\tunsigned short int seq;\t\t/* slot sequence number */\n};\n\nextern struct resource ipcmsg_resource;\n\nvoid ipc_init(void);\nint ipc_has_perms(struct ipc_perm *, int);\n\n#endif /* _FIWIX_IPC_H */\n\n#endif /* CONFIG_SYSVIPC */\n"
  },
  {
    "path": "include/fiwix/irq.h",
    "content": "/*\n * fiwix/include/fiwix/irq.h\n *\n * Copyright 2021-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_IRQ_H\n#define _FIWIX_IRQ_H\n\n#include <fiwix/sigcontext.h>\n\n#define NR_IRQS\t\t16\t/* hardware interrupts */\n\nstruct interrupt {\n\tunsigned int ticks;\n\tchar *name;\n\tvoid (*handler)(int, struct sigcontext *);\n\tstruct interrupt *next;\n};\nextern struct interrupt *irq_table[NR_IRQS];\n\n\n#define BH_ACTIVE\t0x01\n\nstruct bh {\n\tint flags;\n\tvoid (*fn)(struct sigcontext *);\n\tstruct bh *next;\n};\n\nvoid add_bh(struct bh *);\nint register_irq(int, struct interrupt *);\nint unregister_irq(int, const struct interrupt *);\nvoid irq_handler(int, struct sigcontext);\nvoid unknown_irq_handler(void);\nvoid do_bh(struct sigcontext);\nvoid irq_init(void);\n\n#endif /* _FIWIX_IRQ_H */\n"
  },
  {
    "path": "include/fiwix/kd.h",
    "content": "/*\n * fiwix/include/fiwix/kd.h\n */\n\n#ifndef _LINUX_KD_H\n#define _LINUX_KD_H\n\n/* Prefix 0x4B is 'K', to avoid collision with termios and vt */\n\n#define GIO_FONT\t0x4B60\t/* gets font in expanded form */\n#define PIO_FONT\t0x4B61\t/* use font in expanded form */\n\n#define GIO_FONTX\t0x4B6B\t/* get font using struct consolefontdesc */\n#define PIO_FONTX\t0x4B6C\t/* set font using struct consolefontdesc */\nstruct consolefontdesc {\n\tunsigned short int charcount;\t/* characters in font (256 or 512) */\n\tunsigned short int charheight;\t/* scan lines per character (1-32) */\n\tchar *chardata;\t\t\t/* font data in expanded form */\n};\n\n#define PIO_FONTRESET   0x4B6D\t/* reset to default font */\n\n#define GIO_CMAP\t0x4B70\t/* gets colour palette on VGA+ */\n#define PIO_CMAP\t0x4B71\t/* sets colour palette on VGA+ */\n\n#define KIOCSOUND\t0x4B2F\t/* start sound generation (0 for off) */\n#define KDMKTONE\t0x4B30\t/* generate tone */\n\n#define KDGETLED\t0x4B31\t/* return current led state */\n#define KDSETLED\t0x4B32\t/* set led state [lights, not flags] */\n#define LED_SCR\t\t0x01\t/* scroll lock led */\n#define LED_NUM\t\t0x02\t/* num lock led */\n#define LED_CAP\t\t0x04\t/* caps lock led */\n\n#define KDGKBTYPE\t0x4B33\t/* get keyboard type */\n#define KB_84\t\t0x01\n#define KB_101\t\t0x02 \t/* this is what we always answer */\n#define KB_OTHER\t0x03\n\n#define KDADDIO\t\t0x4B34\t/* add i/o port as valid */\n#define KDDELIO\t\t0x4B35\t/* del i/o port as valid */\n#define KDENABIO\t0x4B36\t/* enable i/o to video board */\n#define KDDISABIO\t0x4B37\t/* disable i/o to video board */\n\n#define KDSETMODE\t0x4B3A\t/* set text/graphics mode */\n#define KD_TEXT\t\t0x00\n#define KD_GRAPHICS\t0x01\n#define KD_TEXT0\t0x02\t/* obsolete */\n#define KD_TEXT1\t0x03\t/* obsolete */\n#define KDGETMODE\t0x4B3B\t/* get current mode */\n\n#define KDMAPDISP\t0x4B3C\t/* map display into address space */\n#define KDUNMAPDISP\t0x4B3D\t/* unmap display from address space */\n\ntypedef char scrnmap_t;\n#define E_TABSZ\t\t256\n#define GIO_SCRNMAP\t0x4B40\t/* get screen mapping from kernel */\n#define PIO_SCRNMAP\t0x4B41\t/* put screen mapping table in kernel */\n#define GIO_UNISCRNMAP  0x4B69\t/* get full Unicode screen mapping */\n#define PIO_UNISCRNMAP  0x4B6A  /* set full Unicode screen mapping */\n\n#define GIO_UNIMAP\t0x4B66\t/* get unicode-to-font mapping from kernel */\nstruct unipair {\n\tunsigned short int unicode;\n\tunsigned short int fontpos;\n};\nstruct unimapdesc {\n\tunsigned short int entry_ct;\n\tstruct unipair *entries;\n};\n#define PIO_UNIMAP\t0x4B67\t/* put unicode-to-font mapping in kernel */\n#define PIO_UNIMAPCLR\t0x4B68\t/* clear table, possibly advise hash algorithm */\nstruct unimapinit {\n\tunsigned short int advised_hashsize;  /* 0 if no opinion */\n\tunsigned short int advised_hashstep;  /* 0 if no opinion */\n\tunsigned short int advised_hashlevel; /* 0 if no opinion */\n};\n\n#define UNI_DIRECT_BASE 0xF000\t/* start of Direct Font Region */\n#define UNI_DIRECT_MASK 0x01FF\t/* Direct Font Region bitmask */\n\n#define K_RAW\t\t0x00\n#define K_XLATE\t\t0x01\n#define K_MEDIUMRAW\t0x02\n#define K_UNICODE\t0x03\n#define KDGKBMODE\t0x4B44\t/* gets current keyboard mode */\n#define KDSKBMODE\t0x4B45\t/* sets current keyboard mode */\n\n#define K_METABIT\t0x03\n#define K_ESCPREFIX\t0x04\n#define KDGKBMETA\t0x4B62\t/* gets meta key handling mode */\n#define KDSKBMETA\t0x4B63\t/* sets meta key handling mode */\n\n#define K_SCROLLLOCK\t0x01\n#define K_NUMLOCK\t0x02\n#define K_CAPSLOCK\t0x04\n#define KDGKBLED\t0x4B64\t/* get led flags (not lights) */\n#define KDSKBLED\t0x4B65\t/* set led flags (not lights) */\n\nstruct kbentry {\n\tunsigned char kb_table;\n\tunsigned char kb_index;\n\tunsigned short int kb_value;\n};\n#define K_NORMTAB\t0x00\n#define K_SHIFTTAB\t0x01\n#define K_ALTTAB\t0x02\n#define K_ALTSHIFTTAB\t0x03\n\n#define KDGKBENT\t0x4B46\t/* gets one entry in translation table */\n#define KDSKBENT\t0x4B47\t/* sets one entry in translation table */\n\nstruct kbsentry {\n\tunsigned char kb_func;\n\tunsigned char kb_string[512];\n};\n#define KDGKBSENT\t0x4B48\t/* gets one function key string entry */\n#define KDSKBSENT\t0x4B49\t/* sets one function key string entry */\n\nstruct kbdiacr {\n\tunsigned char diacr, base, result;\n};\nstruct kbdiacrs {\n\tunsigned int kb_cnt;    /* number of entries in following array */\n\tstruct kbdiacr kbdiacr[256];    /* MAX_DIACR from keyboard.h */\n};\n#define KDGKBDIACR      0x4B4A  /* read kernel accent table */\n#define KDSKBDIACR      0x4B4B  /* write kernel accent table */\n\nstruct kbkeycode {\n\tunsigned int scancode, keycode;\n};\n#define KDGETKEYCODE\t0x4B4C\t/* read kernel keycode table entry */\n#define KDSETKEYCODE\t0x4B4D\t/* write kernel keycode table entry */\n\n#define KDSIGACCEPT\t0x4B4E\t/* accept kbd generated signals */\n\nstruct kbd_repeat {\n\tint delay;\t/* in msec; <= 0: don't change */\n\tint rate;\t/* in msec; <= 0: don't change */\n};\n\n#define KDKBDREP        0x4B52  /* set keyboard delay/repeat rate;\n\t\t\t\t * actually used values are returned */\n\n#define KDFONTOP\t0x4B72\t/* font operations */\n\nstruct console_font_op {\n\tunsigned int op;\t/* operation code KD_FONT_OP_* */\n\tunsigned int flags;\t/* KD_FONT_FLAG_* */\n\tunsigned int width, height;\t/* font size */\n\tunsigned int charcount;\n\tunsigned char *data;\t/* font data with height fixed to 32 */\n};\n\n#define KD_FONT_OP_SET\t\t0\t/* Set font */\n#define KD_FONT_OP_GET\t\t1\t/* Get font */\n#define KD_FONT_OP_SET_DEFAULT\t2\t/* Set font to default, data points to name / NULL */\n#define KD_FONT_OP_COPY\t\t3\t/* Copy from another console */\n\n#define KD_FONT_FLAG_DONT_RECALC \t1\t/* Don't recalculate hw charcell size [compat] */\n\n/* note: 0x4B00-0x4B4E all have had a value at some time;\n   don't reuse for the time being */\n/* note: 0x4B60-0x4B6D, 0x4B70-0x4B72 used above */\n\n#endif /* _LINUX_KD_H */\n"
  },
  {
    "path": "include/fiwix/kernel.h",
    "content": "/*\n * fiwix/include/fiwix/kernel.h\n *\n * Copyright 2018-2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_KERNEL_H\n#define _FIWIX_KERNEL_H\n\n#include <fiwix/limits.h>\n#include <fiwix/i386elf.h>\n\n#define QEMU_DEBUG_PORT\t\t0xE9\t/* for Bochs-style debug console */\n#define BUDDY_MAX_LEVEL\t\t7\n\n#define KERN_EMERG\t\"<0>\"\t\t/* system is unusable */\n#define KERN_ALERT\t\"<1>\"\t\t/* action must be taken immediately */\n#define KERN_CRIT\t\"<2>\"\t\t/* critical conditions */\n#define KERN_ERROR\t\"<3>\"\t\t/* error conditions */\n#define KERN_WARNING\t\"<4>\"\t\t/* warning conditions */\n#define KERN_NOTICE\t\"<5>\"\t\t/* normal but significant condition */\n#define KERN_INFO\t\"<6>\"\t\t/* informational */\n#define KERN_DEBUG\t\"<7>\"\t\t/* debug-level messages */\n\n#define PANIC(format, args...)\t\t\t\t\t\t\\\n{\t\t\t\t\t\t\t\t\t\\\n\tprintk(\"\\nPANIC: in %s()\", __FUNCTION__);\t\t\t\\\n\tprintk(\"\\n\");\t\t\t\t\t\t\t\\\n\tprintk(format, ## args);\t\t\t\t\t\\\n\tkstat.flags |= KF_HAS_PANICKED;\t\t\t\t\t\\\n\tstop_kernel();\t\t\t\t\t\t\t\\\n}\n\n#define CURRENT_TIME\t(kstat.system_time)\n#define CURRENT_TICKS\t(kstat.ticks)\n#define INIT_PROGRAM\t\"/sbin/init\"\n\n/* kernel flags */\n#define KF_HAS_PANICKED\t\t0x01\t/* the kernel has panic'ed */\n#define KF_HAS_DEBUGCON\t\t0x02\t/* QEMU debug console support */\n\nextern char *init_argv[];\nextern char *init_envp[];\nextern char *init_args;\n\nextern Elf32_Shdr *symtab, *strtab;\nextern unsigned int _last_data_addr;\n\nextern int kexec_proto;\nextern int kexec_size;\nextern char kexec_cmdline[NAME_MAX + 1];\n\nextern int _cputype;\nextern int _cpusignature;\nextern int _cpuflags;\nextern int _brandid;\nextern char _vendorid[12];\nextern char _brandstr[48];\nextern unsigned int _tlbinfo_eax;\nextern unsigned int _tlbinfo_ebx;\nextern unsigned int _tlbinfo_ecx;\nextern unsigned int _tlbinfo_edx;\nextern char _etext[], _edata[], _end[];\n\nextern char kernel_cmdline[NAME_MAX + 1];\n\nstruct kernel_stat {\n\tint flags;\t\t\t/* kernel flags */\n\tunsigned int cpu_user;\t\t/* ticks in user-mode */\n\tunsigned int cpu_nice;\t\t/* ticks in user-mode (with priority) */\n\tunsigned int cpu_system;\t/* ticks in kernel-mode */\n\tunsigned int irqs;\t\t/* irq counter */\n\tunsigned int sirqs;\t\t/* spurious irq counter */\n\tunsigned int ctxt;\t\t/* context switches */\n\tunsigned int ticks;\t\t/* ticks (1/HZths of sec) since boot */\n\tunsigned int system_time;\t/* current system time (since the Epoch) */\n\tunsigned int boot_time;\t\t/* boot time (since the Epoch) */\n\tint tz_minuteswest;\t\t/* minutes west of GMT */\n\tint tz_dsttime;\t\t\t/* type of DST correction */\n\tunsigned int uptime;\t\t/* seconds since boot */\n\tunsigned int processes;\t\t/* number of forks since boot */\n\tint physical_pages;\t\t/* physical memory (in pages) */\n\tint kernel_reserved;\t\t/* kernel memory reserved (in KB) */\n\tint physical_reserved;\t\t/* physical memory reserved (in KB) */\n\tint total_mem_pages;\t\t/* total memory (in pages) */\n\tint free_pages;\t\t\t/* pages on free list */\n\tint min_free_pages;\t\t/* minimal free pages in system */\n\tint max_inodes;\t\t\t/* max. number of allocated inodes */\n\tint nr_inodes;\t\t\t/* current allocated inodes */\n\tint max_buffers_size;\t\t/* max. allocated buffers (in KB) */\n\tint buffers_size;\t\t/* current allocated buffers (in KB) */\n\tint nr_buffers;\t\t\t/* number of buffers created */\n\tint cached;\t\t\t/* memory used to cache file pages */\n\tint shared;\t\t\t/* pages with count > 1 */\n\tint max_dirty_buffers;\t\t/* max. number of dirty buffers */\n\tint dirty_buffers;\t\t/* dirty buffers (in KB) */\n\tint nr_dirty_buffers;\t\t/* current dirty buffers */\n\tunsigned int random_seed;\t/* next random seed */\n\tint pages_reclaimed;\t\t/* last pages reclaimed from buffer */\n\tint nr_flocks;\t\t\t/* current allocated file locks */\n\n\t/* buddy_low algorithm statistics */\n\tint buddy_low_count[BUDDY_MAX_LEVEL + 1];\n\tint buddy_low_num_pages;\t/* number of pages used */\n\tint buddy_low_mem_requested;\t/* total memory requested (in bytes) */\n\n\tint mount_points;\t\t/* number of fs currently mounted */\n};\nextern struct kernel_stat kstat;\n\nunsigned int get_last_boot_addr(unsigned int, unsigned int);\nvoid multiboot(unsigned int, unsigned int);\nvoid start_kernel(unsigned int, unsigned int, unsigned int);\nvoid stop_kernel(void);\nvoid init_init(void);\nvoid cpu_idle(void);\n\n\n#ifdef CUSTOM_KERNEL_H\n#include <fiwix/custom_kernel.h>\n#endif\n\n#endif /* _FIWIX_KERNEL_H */\n"
  },
  {
    "path": "include/fiwix/kexec.h",
    "content": "/*\n * fiwix/include/fiwix/kexec.h\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifdef CONFIG_KEXEC\n\n#ifndef _FIWIX_KEXEC_H\n#define _FIWIX_KEXEC_H\n\n#define KEXEC_MULTIBOOT1\t0x01\n#define KEXEC_LINUX\t\t0x02\n\n#define KEXEC_BOOT_ADDR\t\t0x9D000\n\nvoid kexec_multiboot1(void);\nvoid kexec_linux(void);\n\n#endif /* _FIWIX_KEXEC_H */\n\n#endif /* CONFIG_KEXEC */\n"
  },
  {
    "path": "include/fiwix/keyboard.h",
    "content": "/*\n * fiwix/include/fiwix/keyboard.h\n *\n * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_KEYBOARD_H\n#define _FIWIX_KEYBOARD_H\n\n#define KEYBOARD_IRQ\t1\n\n#define NR_MODIFIERS\t16\t/* max. number of modifiers per keymap */\n#define NR_SCODES\t128\t/* max. number of scancodes */\n#define NR_DIACR\t10\n\n#define SCRLBIT\t\t0x01\t/* scroll lock led */\n#define NUMSBIT\t\t0x02\t/* num lock led */\n#define CAPSBIT\t\t0x04\t/* caps lock led */\n\n#define C(ch)\t\t((ch) & 0x1F)\n#define A(ch)\t\t((ch) | META_KEYS)\n#define L(ch)\t\t((ch) | LETTER_KEYS)\n\n#define SLASH_NPAD\t53\n\n#define E0ENTER\t\t96\n#define RCTRL\t\t97\n#define E0SLASH\t\t98\n#define ALTGR\t\t100\n#define E0HOME\t\t102\n#define E0UP\t\t103\n#define E0PGUP\t\t104\n#define E0LEFT\t\t105\n#define E0RIGHT\t\t106\n#define E0END\t\t107\n#define E0DOWN\t\t108\n#define E0PGDN\t\t109\n#define E0INS\t\t110\n#define E0DEL\t\t111\n\n#define MOD_BASE\t0\n#define MOD_SHIFT\t1\n#define MOD_ALTGR\t2\n#define MOD_CTRL\t3\n#define MOD_ALT\t\t4\n#define MOD_SHIFTL\t5\n#define MOD_SHIFTR\t6\n#define MOD_CTRLL\t7\n#define MOD_CTRLR\t8\n\n#define FN_KEYS\t\t0x100\n#define SPEC_KEYS\t0x200\n#define PAD_KEYS\t0x300\n#define DEAD_KEYS\t0x400\n#define CONS_KEYS\t0x500\n#define SHIFT_KEYS\t0x700\n#define META_KEYS\t0x800\n#define LETTER_KEYS\t0xB00\n\n#define CR\t\t(0x01 + SPEC_KEYS)\n#define SCRL2\t\t(0x02 + SPEC_KEYS)\t/* SH_REGS (show registers) */\n#define SCRL3\t\t(0x03 + SPEC_KEYS)\t/* SH_MEM (show memory) */\n#define SCRL4\t\t(0x04 + SPEC_KEYS)\t/* SH_STAT (show status) */\n#define SYSRQ\t\t(0x06 + SPEC_KEYS)\n#define CAPS\t\t(0x07 + SPEC_KEYS)\n#define NUMS\t\t(0x08 + SPEC_KEYS)\n#define SCRL\t\t(0x09 + SPEC_KEYS)\n\n#define INS\t\t(0x00 + PAD_KEYS)\n#define END\t\t(0x01 + PAD_KEYS)\n#define DOWN\t\t(0x02 + PAD_KEYS)\n#define PGDN\t\t(0x03 + PAD_KEYS)\n#define LEFT\t\t(0x04 + PAD_KEYS)\n#define MID\t\t(0x05 + PAD_KEYS)\n#define RIGHT\t\t(0x06 + PAD_KEYS)\n#define HOME\t\t(0x07 + PAD_KEYS)\n#define UP\t\t(0x08 + PAD_KEYS)\n#define PGUP\t\t(0x09 + PAD_KEYS)\n#define PLUS\t\t(0x0A + PAD_KEYS)\n#define MINUS\t\t(0x0B + PAD_KEYS)\n#define ASTSK\t\t(0x0C + PAD_KEYS)\n#define SLASH\t\t(0x0D + PAD_KEYS)\n#define ENTER\t\t(0x0E + PAD_KEYS)\n#define DEL\t\t(0x10 + PAD_KEYS)\n\n#define GRAVE\t\t(0x00 + DEAD_KEYS)\n#define ACUTE\t\t(0x01 + DEAD_KEYS)\n#define CIRCM\t\t(0x02 + DEAD_KEYS)\n#define TILDE\t\t(0x03 + DEAD_KEYS)\n#define DIERE\t\t(0x04 + DEAD_KEYS)\n\n#define SHIFT\t\t(0x00 + SHIFT_KEYS)\n#define CTRL\t\t(0x02 + SHIFT_KEYS)\n#define ALT\t\t(0x03 + SHIFT_KEYS)\n#define LSHIFT\t\t(0x04 + SHIFT_KEYS)\n#define RSHIFT\t\t(0x05 + SHIFT_KEYS)\n#define LCTRL\t\t(0x06 + SHIFT_KEYS)\n\n#define F1\t\t(0x00 + FN_KEYS)\n#define F2\t\t(0x01 + FN_KEYS)\n#define F3\t\t(0x02 + FN_KEYS)\n#define F4\t\t(0x03 + FN_KEYS)\n#define F5\t\t(0x04 + FN_KEYS)\n#define F6\t\t(0x05 + FN_KEYS)\n#define F7\t\t(0x06 + FN_KEYS)\n#define F8\t\t(0x07 + FN_KEYS)\n#define F9\t\t(0x08 + FN_KEYS)\n#define F10\t\t(0x09 + FN_KEYS)\n#define F11\t\t(0x0A + FN_KEYS)\n#define F12\t\t(0x0B + FN_KEYS)\n\n#define SF1\t\t(0x0A + FN_KEYS)\n#define SF2\t\t(0x0B + FN_KEYS)\n#define SF3\t\t(0x0C + FN_KEYS)\n#define SF4\t\t(0x0D + FN_KEYS)\n#define SF5\t\t(0x0E + FN_KEYS)\n#define SF6\t\t(0x0F + FN_KEYS)\n#define SF7\t\t(0x10 + FN_KEYS)\n#define SF8\t\t(0x11 + FN_KEYS)\n#define SF9\t\t(0x12 + FN_KEYS)\n#define SF10\t\t(0x13 + FN_KEYS)\n#define SF11\t\t(0x0A + SHIFT)\n#define SF12\t\t(0x0B + SHIFT)\n\n#define AF1\t\t(0x00 + CONS_KEYS)\n#define AF2\t\t(0x01 + CONS_KEYS)\n#define AF3\t\t(0x02 + CONS_KEYS)\n#define AF4\t\t(0x03 + CONS_KEYS)\n#define AF5\t\t(0x04 + CONS_KEYS)\n#define AF6\t\t(0x05 + CONS_KEYS)\n#define AF7\t\t(0x06 + CONS_KEYS)\n#define AF8\t\t(0x07 + CONS_KEYS)\n#define AF9\t\t(0x08 + CONS_KEYS)\n#define AF10\t\t(0x09 + CONS_KEYS)\n#define AF11\t\t(0x0A + CONS_KEYS)\n#define AF12\t\t(0x0B + CONS_KEYS)\n\n#ifdef __KERNEL__\n\n#include <fiwix/types.h>\n#include <fiwix/sigcontext.h>\n\nstruct diacritic {\n\tunsigned char letter;\n\tunsigned char code;\n};\n\nextern __key_t keymap[NR_MODIFIERS * NR_SCODES];\n\nvoid set_leds(unsigned char);\nvoid irq_keyboard(int num, struct sigcontext *);\nvoid irq_keyboard_bh(struct sigcontext *);\nvoid keyboard_init(void);\n\n#endif /* __KERNEL__ */\n\n#endif /* _FIWIX_KEYBOARD_H */\n"
  },
  {
    "path": "include/fiwix/kparms.h",
    "content": "/*\n * fiwix/include/fiwix/kparms.h\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_KPARMS_H\n#define _FIWIX_KPARMS_H\n\n#include <fiwix/limits.h>\n\n#define CMDL_ARG_LEN\t100\t/* max. length of cmdline argument */\n#define CMDL_NUM_VALUES\t30\t/* max. values of cmdline parameter */\n\n#define KPARMS_IDE_NODMA\t0x01\t/* disable DMA in all ATA drives */\n#define KPARMS_PS2_NORESET\t0x02\t/* disable PS/2 controller reset */\n\nstruct kernel_params {\n\tint flags;\n\tchar bgaresolution[15 + 1];\n\tchar initrd[DEVNAME_MAX + 1];\n\tint memsize;\n\tint extmemsize;\n\tint ramdisksize;\n\tint ro;\n\tint rootdev;\n\tchar rootfstype[10 + 1];\n\tchar rootdevname[DEVNAME_MAX + 1];\n\tint syscondev;\n};\n\nextern struct kernel_params kparms;\n\nstruct kernel_params_value {\n\tchar *name;\n\tchar *value[CMDL_NUM_VALUES];\n\tunsigned int sysval[CMDL_NUM_VALUES];\n};\n\n#endif /* _FIWIX_KPARMS_H */\n"
  },
  {
    "path": "include/fiwix/limits.h",
    "content": "/*\n * fiwix/include/fiwix/limits.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_LIMITS_H\n#define _FIWIX_LIMITS_H\n\n#define DEVNAME_MAX\t50\t/* device name length in mount table */\n#define ARG_MAX\t\t32\t/* length (in pages) of argv+env in 'execve' */\n#define CHILD_MAX\t64\t/* simultaneous processes per real user ID */\n#define LINK_MAX\t255\t/* maximum number of links to a file */\n#define MAX_CANON\t255\t/* bytes in a terminal canonical input queue */\n#define MAX_INPUT\t255\t/* bytes for which space will be available in a\n\t\t\t\t   terminal input queue */\n#define NGROUPS_MAX\t32\t/* simultaneous supplementary group IDs */\n#define OPEN_MAX\t256\t/* files one process can have opened at once */\n#define FD_SETSIZE\tOPEN_MAX /* descriptors that a process may examine with\n\t\t\t\t    'pselect' or 'select' */\n#define NAME_MAX\t255\t/* bytes in a filename */\n#define PATH_MAX\t1024\t/* bytes in a pathname */\n#define PIPE_BUF\t4096\t/* bytes than can be written atomically to a\n\t\t\t\t   pipe (cannot be bigger than PAGE_SIZE) */\n#define UIO_MAXIOV\t16\t/* maximum number of scatter/gather elements\n\t\t\t\t   that can be processed in one call */\n\n#ifdef CUSTOM_LIMITS_H\n#include <fiwix/custom_limits.h>\n#endif\n\n#endif /* _FIWIX_LIMITS_H */\n"
  },
  {
    "path": "include/fiwix/linker.h",
    "content": "/*\n * fiwix/include/fiwix/linker.h\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_LINKER_H\n#define _FIWIX_LINKER_H\n\n#include <fiwix/config.h>\n\n#ifdef CONFIG_VM_SPLIT22\n#define PAGE_OFFSET\t0x80000000\t/* VM split: 2GB user / 2GB kernel */\n#else\n#define PAGE_OFFSET\t0xC0000000\t/* VM split: 3GB user / 1GB kernel */\n#endif /* CONFIG_VM_SPLIT22 */\n\n#define KERNEL_ADDR\t0x100000\n#define KERNEL_STACK\t4096\n#define GDT_BASE\t(0xFFFFFFFF - (PAGE_OFFSET - 1))\n\n#endif /* _FIWIX_LINKER_H */\n"
  },
  {
    "path": "include/fiwix/linuxboot.h",
    "content": "/*\n * include/fiwix/linuxboot.h\n *\n * Copyright 2024, Richard R. Masters.\n * Distributed under the terms of the Fiwix License.\n */\n\n#define IS_VGA_VGA_COLOR\t0x22\n\nstruct screen_info {\n\t__u8  unused1[6];\n\t__u8  mode;\n\t__u8  cols;\n\t__u8  unused2[2];\n\t__u16 ega_bx;\n\t__u8  unused3[2];\n\t__u8  lines;\n\t__u8  is_vga;\n\t__u16 points;\n\t__u8  unused4[46];\n} __attribute__((packed));\n\n\nstruct setup_header {\n\t__u8  unused1[9];\n\t__u16 video_mode;\n\t__u8  unused2[10];\n\t__u16 version;\n\t__u8  unused3[8];\n\t__u8  loader_type;\n\t__u8  load_flags;\n\t__u8  unused4[6];\n\t__u32 initramfs_addr;\n\t__u32 initramfs_size;\n\t__u8  unused5[8];\n\t__u32 cmdline_addr;\n\t__u32 initramfs_addr_max;\n\t__u8  unused6[60];\n} __attribute__((packed));\n\n\nstruct bios_mem_entry {\n\t__u64 addr;\n\t__u64 size;\n\t__u32 type;\n} __attribute__((packed));\n\n\n#define MAX_BIOS_MEM_ENTRIES 128\n\nstruct boot_params {\n\tstruct screen_info screen_info;\n\t__u8   unused1[424];\n\t__u8   num_bios_mem_entries;\n\t__u8   unused2[8];\n\tstruct setup_header hdr;\n\t__u8   unused3[100];\n\tstruct bios_mem_entry bios_mem_table[MAX_BIOS_MEM_ENTRIES];\n\t__u8   unused4[816];\n} __attribute__((packed));\n\n/* End of Linux code */\n"
  },
  {
    "path": "include/fiwix/locks.h",
    "content": "/*\n * fiwix/include/fiwix/locks.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_LOCKS_H\n#define _FIWIX_LOCKS_H\n\n#include <fiwix/config.h>\n#include <fiwix/fs.h>\n#include <fiwix/fcntl.h>\n\nstruct flock_file {\n\tstruct inode *inode;\t\t/* file */\n\tunsigned char type;\t\t/* type of lock */\n\tstruct proc *proc;\t\t/* owner */\n\tstruct flock_file *prev;\n\tstruct flock_file *next;\n};\n\nextern struct flock_file *flock_file_table;\n\nint posix_lock(int, int, struct flock *);\nvoid flock_release_inode(struct inode *);\nint flock_inode(struct inode *, int);\n\n#endif /* _FIWIX_LOCKS_H */\n"
  },
  {
    "path": "include/fiwix/lp.h",
    "content": "/*\n * fiwix/include/fiwix/lp.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_LP_H\n#define _FIWIX_LP_H\n\n#include <fiwix/fs.h>\n\n#define LP_MAJOR\t6\t/* major number for /dev/lp[n] */\n#define LP_MINORS\t1\n\n/*#define LP0_ADDR\t0x3BC */\n#define LP0_ADDR\t0x378\n/*#define LP2_ADDR\t0x278 */\n\n#define LP_STAT_ERR\t0x08\t/* printer error */\n#define LP_STAT_SEL\t0x10\t/* select in */\n#define LP_STAT_PE\t0x20\t/* paper empty or no paper */\n#define LP_STAT_ACK\t0x40\t/* ack */\n#define LP_STAT_BUS\t0x80\t/* printer busy */\n\n#define LP_CTRL_STR\t0x01\t/* strobe */\n#define LP_CTRL_AUT\t0x02\t/* auto line feed */\n#define LP_CTRL_INI\t0x04\t/* initialize printer (reset) */\n#define LP_CTRL_SEL\t0x08\t/* select printer */\n#define LP_CTRL_IRQ\t0x10\t/* enable IRQ */\n#define LP_CTRL_BID\t0x20\t/* bidireccional (on PS/2 ports) */\n\n#define LP_RDY_RETR\t100\t/* retries before timeout */\n\nstruct lp {\n\tint data;\t/* data port address */\n\tint stat;\t/* status port address */\n\tint ctrl;\t/* control port address */\n\tchar flags;\t/* flags */\n};\n\nint lp_open(struct inode *, struct fd *);\nint lp_close(struct inode *, struct fd *);\nint lp_write(struct inode *, struct fd *, const char *, __size_t);\n\nvoid lp_init(void);\n\n#endif /* _FIWIX_LP_H */\n"
  },
  {
    "path": "include/fiwix/memdev.h",
    "content": "/*\n * fiwix/include/fiwix/memdev.h\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_MEMDEV_H\n#define _FIWIX_MEMDEV_H\n\n#include <fiwix/fs.h>\n\n#define MEMDEV_MAJOR\t1\t/* major number */\n\n#define MEMDEV_MEM\t1\t/* minor for /dev/mem */\n#define MEMDEV_KMEM\t2\t/* minor for /dev/kmem */\n#define MEMDEV_NULL\t3\t/* minor for /dev/null */\n#define MEMDEV_PORT\t4\t/* minor for /dev/port */\n#define MEMDEV_ZERO\t5\t/* minor for /dev/zero */\n#define MEMDEV_FULL\t7\t/* minor for /dev/full */\n#define MEMDEV_RANDOM\t8\t/* minor for /dev/random */\n#define MEMDEV_URANDOM\t9\t/* minor for /dev/urandom */\n\nint mem_open(struct inode *, struct fd *);\nint mem_close(struct inode *, struct fd *);\nint mem_read(struct inode *, struct fd *, char *, __size_t);\nint mem_write(struct inode *, struct fd *, const char *, __size_t);\n__loff_t mem_llseek(struct inode *, __loff_t);\n\nint kmem_open(struct inode *, struct fd *);\nint kmem_close(struct inode *, struct fd *);\nint kmem_read(struct inode *, struct fd *, char *, __size_t);\nint kmem_write(struct inode *, struct fd *, const char *, __size_t);\n__loff_t kmem_llseek(struct inode *, __loff_t);\n\nint null_open(struct inode *, struct fd *);\nint null_close(struct inode *, struct fd *);\nint null_read(struct inode *, struct fd *, char *, __size_t);\nint null_write(struct inode *, struct fd *, const char *, __size_t);\n__loff_t null_llseek(struct inode *, __loff_t);\n\nint port_open(struct inode *, struct fd *);\nint port_close(struct inode *, struct fd *);\nint port_read(struct inode *, struct fd *, char *, __size_t);\nint port_write(struct inode *, struct fd *, const char *, __size_t);\n__loff_t port_llseek(struct inode *, __loff_t);\n\nint zero_open(struct inode *, struct fd *);\nint zero_close(struct inode *, struct fd *);\nint zero_read(struct inode *, struct fd *, char *, __size_t);\nint zero_write(struct inode *, struct fd *, const char *, __size_t);\n__loff_t zero_llseek(struct inode *, __loff_t);\n\nint full_open(struct inode *, struct fd *);\nint full_close(struct inode *, struct fd *);\nint full_read(struct inode *, struct fd *, char *, __size_t);\nint full_write(struct inode *, struct fd *, const char *, __size_t);\n__loff_t full_llseek(struct inode *, __loff_t);\n\nint urandom_open(struct inode *, struct fd *);\nint urandom_close(struct inode *, struct fd *);\nint urandom_read(struct inode *, struct fd *, char *, __size_t);\nint urandom_write(struct inode *, struct fd *, const char *, __size_t);\n__loff_t urandom_llseek(struct inode *, __loff_t);\n\nint memdev_open(struct inode *, struct fd *);\nint mem_mmap(struct inode *, struct vma *);\nvoid memdev_init(void);\n\n#endif /* _FIWIX_MEMDEV_H */\n"
  },
  {
    "path": "include/fiwix/mm.h",
    "content": "/*\n * fiwix/include/fiwix/mm.h\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_MEMORY_H\n#define _FIWIX_MEMORY_H\n\n#include <fiwix/types.h>\n#include <fiwix/segments.h>\n#include <fiwix/process.h>\n\n/* convert from physical to virtual the addresses below PAGE_OFFSET only */\n#define P2V(addr)\t\t(addr < PAGE_OFFSET ? addr + PAGE_OFFSET : addr)\n\n#define V2P(addr)\t\t(addr - PAGE_OFFSET)\n\n#define PAGE_SIZE\t\t4096\n#define PAGE_SHIFT\t\t0x0C\n#define PAGE_MASK\t\t~(PAGE_SIZE - 1)\t/* 0xFFFFF000 */\n#define PAGE_ALIGN(addr)\t(((addr) + (PAGE_SIZE - 1)) & PAGE_MASK)\n#define PT_ENTRIES\t\t(PAGE_SIZE / sizeof(unsigned int))\n#define PD_ENTRIES\t\t(PAGE_SIZE / sizeof(unsigned int))\n\n#define PAGE_LOCKED\t\t0x001\n#define PAGE_BUDDYLOW\t\t0x010\t/* page belongs to buddy_low */\n#define PAGE_RESERVED\t\t0x100\t/* kernel, BIOS address, ... */\n#define PAGE_COW\t\t0x200\t/* marked for Copy-On-Write */\n\n#define PFAULT_V\t\t0x01\t/* protection violation */\n#define PFAULT_W\t\t0x02\t/* during write */\n#define PFAULT_U\t\t0x04\t/* in user mode */\n\n#define GET_PGDIR(address)\t((unsigned int)((address) >> 22) & 0x3FF)\n#define GET_PGTBL(address)\t((unsigned int)((address) >> 12) & 0x3FF)\n\nstruct page {\n\tint page;\t\t/* page number */\n\tint count;\t\t/* usage counter */\n\tint flags;\n\t__ino_t inode;\t\t/* inode of the file */\n\t__off_t offset;\t\t/* file offset */\n\t__dev_t dev;\t\t/* device where file resides */\n\tchar *data;\t\t/* page contents */\n\tstruct page *prev_hash;\n\tstruct page *next_hash;\n\tstruct page *prev_free;\n\tstruct page *next_free;\n};\n\nextern struct page *page_table;\nextern struct page **page_hash_table;\n\n/* values to be determined during system startup */\nextern unsigned int page_table_size;\t\t/* size in bytes */\nextern unsigned int page_hash_table_size;\t/* size in bytes */\n\nextern unsigned int *kpage_dir;\n\n\n/* buddy_low.c */\nstatic const unsigned int bl_blocksize[] = {\n\t32,\n\t64,\n\t128,\n\t256,\n\t512,\n\t1024,\n\t2048,\n\t4096\n};\n\nstruct bl_head {\n\tunsigned char level;\t/* size class (exponent of the power of 2) */\n\tstruct bl_head *prev;\n\tstruct bl_head *next;\n};\n\nunsigned int bl_malloc(__size_t);\nvoid bl_free(unsigned int);\nvoid buddy_low_init(void);\n\n/* alloc.c */\nunsigned int kmalloc(__size_t);\nvoid kfree(unsigned int);\n\n/* page.c */\nvoid page_lock(struct page *);\nvoid page_unlock(struct page *);\nstruct page *get_free_page(void);\nstruct page *search_page_hash(struct inode *, __off_t);\nvoid release_page(struct page *);\nint is_valid_page(int);\nvoid invalidate_inode_pages(struct inode *);\nvoid update_page_cache(struct inode *, __off_t, const char *, int);\nint write_page(struct page *, struct inode *, __off_t, unsigned int);\nint bread_page(struct page *, struct inode *, __off_t, char, char);\nint file_read(struct inode *, struct fd *, char *, __size_t);\nvoid reserve_pages(unsigned int, unsigned int);\nvoid page_init(int);\n\n/* memory.c */\nunsigned int map_kaddr(unsigned int *,unsigned int, unsigned int, unsigned int, int);\nvoid bss_init(void);\nunsigned int setup_tmp_pgdir(unsigned int, unsigned int);\nunsigned int get_mapped_addr(struct proc *, unsigned int);\nint clone_pages(struct proc *);\nint free_page_tables(struct proc *);\nunsigned int map_page(struct proc *, unsigned int, unsigned int, unsigned int);\nunsigned int map_page_flags(struct proc *, unsigned int, unsigned int, unsigned int, int);\nint unmap_page(unsigned int);\nvoid mem_init(void);\nvoid mem_stats(void);\n\n/* swapper.c */\nint kswapd(void);\n\n#endif /* _FIWIX_MEMORY_H */\n"
  },
  {
    "path": "include/fiwix/mman.h",
    "content": "/*\n * fiwix/include/fiwix/mman.h\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_MMAN_H\n#define _FIWIX_MMAN_H\n\n#include <fiwix/fs.h>\n\n#define PROT_READ\t0x1\t\t/* page can be read */\n#define PROT_WRITE\t0x2\t\t/* page can be written */\n#define PROT_EXEC\t0x4\t\t/* page can be executed */\n#define PROT_NONE\t0x0\t\t/* page cannot be accessed */\n\n#define MAP_SHARED\t0x01\t\t/* share changes */\n#define MAP_PRIVATE\t0x02\t\t/* changes are private */\n#define MAP_TYPE\t0x0f\t\t/* mask for type of mapping */\n#define MAP_FIXED\t0x10\t\t/* interpret address exactly */\n#define MAP_ANONYMOUS\t0x20\t\t/* don't use the file descriptor */\n\n#define MAP_GROWSDOWN\t0x0100\t\t/* stack-like segment */\n#define MAP_DENYWRITE\t0x0800\t\t/* -ETXTBSY */\n#define MAP_EXECUTABLE\t0x1000\t\t/* mark it as a executable */\n#define MAP_LOCKED\t0x2000\t\t/* pages are locked */\n\n#define ZERO_PAGE\t0x80000000\t/* this page must be zero-filled */\n\n\n#define MS_ASYNC\t0x1\t/* sync memory asynchronously */\n#define MS_INVALIDATE\t0x2\t/* invalidate the caches */\n#define MS_SYNC\t\t0x4\t/* synchronous memory sync */\n\n#define MCL_CURRENT\t1\t/* lock all current mappings */\n#define MCL_FUTURE\t2\t/* lock all future mappings */\n\n#define P_TEXT\t\t1\t/* text section */\n#define P_DATA\t\t2\t/* data section */\n#define P_BSS\t\t3\t/* BSS section */\n#define P_HEAP\t\t4\t/* heap section (sys_brk()) */\n#define P_STACK\t\t5\t/* stack section */\n#define P_MMAP\t\t6\t/* mmap() section */\n#define P_SHM\t\t7\t/* shared memory section */\n\n/* compatibility flags */\n#define MAP_ANON\tMAP_ANONYMOUS\n#define MAP_FILE\t0\n\nstruct mmap {\n\tunsigned int start;\n\tunsigned int length;\n\tunsigned int prot;\n\tunsigned int flags;\n\tint fd;\n\tunsigned int offset;\n};\n\nvoid show_vma_regions(struct proc *);\nvoid free_vma_pages(struct vma *, unsigned int, __size_t);\nvoid release_binary(void);\nstruct vma *find_vma_region(unsigned int);\nstruct vma *find_vma_intersection(unsigned int, unsigned int);\nint expand_heap(unsigned int);\nunsigned int get_unmapped_vma_region(unsigned int);\nint do_mmap(struct inode *, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, char, char, void *);\nint do_munmap(unsigned int, __size_t);\nint do_mprotect(struct vma *, unsigned int, __size_t, int);\n\n#endif /* _FIWIX_MMAN_H */\n"
  },
  {
    "path": "include/fiwix/msg.h",
    "content": "/*\n * fiwix/include/fiwix/msg.h\n */\n\n#ifdef CONFIG_SYSVIPC\n\n#ifndef _FIWIX_MSG_H\n#define _FIWIX_MSG_H\n\n#include <fiwix/types.h>\n#include <fiwix/ipc.h>\n\n#define MSG_NOERROR\t010000\t\t/* no error if message is too big */\n#define MSG_EXCEPT\t020000\t\t/* recv any msg except of specified type */\n\n/* system-wide limits */\n#define MSGMAX\t\t4096\t\t/* max. size of a message */\n#define MSGMNI\t\t128\t\t/* max. number of message queues */\n#define MSGMNB\t\t16384\t\t/* total size of message queue */\n#define MSGTQL\t\t1024\t\t/* max. number of messages */\n\n#define MSG_STAT\t11\n#define MSG_INFO\t12\n\nstruct msqid_ds {\n\tstruct ipc_perm msg_perm;\t/* access permissions */\n\tstruct msg *msg_first;\t\t/* ptr to the first message in queue */\n\tstruct msg *msg_last;\t\t/* ptr to the last message in queue */\n\t__time_t msg_stime;\t\t/* time of the last msgsnd() */\n\t__time_t msg_rtime;\t\t/* time of the last msgrcv() */\n\t__time_t msg_ctime;\t\t/* time of the last change */\n\tunsigned int unused1;\n\tunsigned int unused2;\n\tunsigned short int msg_cbytes;\t/* number of bytes in queue */\n\tunsigned short int msg_qnum;\t/* number of messages in queue */\n\tunsigned short int msg_qbytes;\t/* max. number of bytes in queue */\n\tunsigned short int msg_lspid;\t/* PID of last msgsnd() */\n\tunsigned short int msg_lrpid;\t/* PID of last msgrcv() */\n};\n\n/* message buffer for msgsnd() and msgrcv() */\nstruct msgbuf {\n\tint mtype;\t\t\t/* type of message */\n\tchar mtext[1];      \t\t/* message text */\n};\n\n/* buffer for msgctl() with IPC_INFO and MSG_INFO commands */\nstruct msginfo {\n\tint msgpool;\n\tint msgmap;\n\tint msgmax;\t\t\t/* MSGMAX */\n\tint msgmnb;\t\t\t/* MSGMNB */\n\tint msgmni;\t\t\t/* MSGMNI */\n\tint msgssz;\n\tint msgtql;\t\t\t/* MSGTQL */\n\tunsigned short int msgseg;\n};\n\n/* one msg structure for each message */\nstruct msg {\n\tstruct msg *msg_next;\t\t/* next message on queue */\n\tint msg_type;\n\tchar *msg_spot;\t\t\t/* message text address */\n\t__time_t msg_stime;\t\t/* msgsnd time */\n\tshort int msg_ts;\t\t/* message text size */\n};\n\nextern struct msqid_ds *msgque[];\nextern unsigned int num_queues;\nextern unsigned int num_msgs;\nextern unsigned int max_mqid;\nextern unsigned int msg_seq;\n\nvoid msg_init(void);\nstruct msqid_ds *msg_get_new_mq(void);\nvoid msg_release_mq(struct msqid_ds *);\nstruct msg *msg_get_new_md(void);\nvoid msg_release_md(struct msg *);\nint sys_msgsnd(int, const void *, __size_t, int);\nint sys_msgrcv(int, void *, __size_t, int, int);\nint sys_msgget(key_t, int);\nint sys_msgctl(int, int, struct msqid_ds *);\n\n#endif /* _FIWIX_MSG_H */\n\n#endif /* CONFIG_SYSVIPC */\n"
  },
  {
    "path": "include/fiwix/multiboot1.h",
    "content": "/* multiboot.h - Multiboot header file. */\n/* Copyright (C) 1999,2003,2007,2008,2009,2010  Free Software Foundation, Inc.\n *\n *  Permission is hereby granted, free of charge, to any person obtaining a copy\n *  of this software and associated documentation files (the \"Software\"), to\n *  deal in the Software without restriction, including without limitation the\n *  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n *  sell copies of the Software, and to permit persons to whom the Software is\n *  furnished to do so, subject to the following conditions:\n *\n *  The above copyright notice and this permission notice shall be included in\n *  all copies or substantial portions of the Software.\n *\n *  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL ANY\n *  DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n *  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\n *  IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n#ifndef MULTIBOOT_HEADER\n#define MULTIBOOT_HEADER 1\n\n/* How many bytes from the start of the file we search for the header. */\n#define MULTIBOOT_SEARCH                        8192\n#define MULTIBOOT_HEADER_ALIGN                  4\n\n/* The magic field should contain this. */\n#define MULTIBOOT_HEADER_MAGIC                  0x1BADB002\n\n/* This should be in %eax. */\n#define MULTIBOOT_BOOTLOADER_MAGIC              0x2BADB002\n\n/* Alignment of multiboot modules. */\n#define MULTIBOOT_MOD_ALIGN                     0x00001000\n\n/* Alignment of the multiboot info structure. */\n#define MULTIBOOT_INFO_ALIGN                    0x00000004\n\n/* Flags set in the ’flags’ member of the multiboot header. */\n\n/* Align all boot modules on i386 page (4KB) boundaries. */\n#define MULTIBOOT_PAGE_ALIGN                    0x00000001\n\n/* Must pass memory information to OS. */\n#define MULTIBOOT_MEMORY_INFO                   0x00000002\n\n/* Must pass video information to OS. */\n#define MULTIBOOT_VIDEO_MODE                    0x00000004\n\n/* This flag indicates the use of the address fields in the header. */\n#define MULTIBOOT_AOUT_KLUDGE                   0x00010000\n\n/* Flags to be set in the ’flags’ member of the multiboot info structure. */\n\n/* is there basic lower/upper memory information? */\n#define MULTIBOOT_INFO_MEMORY                   0x00000001\n/* is there a boot device set? */\n#define MULTIBOOT_INFO_BOOTDEV                  0x00000002\n/* is the command-line defined? */\n#define MULTIBOOT_INFO_CMDLINE                  0x00000004\n/* are there modules to do something with? */\n#define MULTIBOOT_INFO_MODS                     0x00000008\n\n/* These next two are mutually exclusive */\n\n/* is there a symbol table loaded? */\n#define MULTIBOOT_INFO_AOUT_SYMS                0x00000010\n/* is there an ELF section header table? */\n#define MULTIBOOT_INFO_ELF_SHDR                 0X00000020\n\n/* is there a full memory map? */\n#define MULTIBOOT_INFO_MEM_MAP                  0x00000040\n\n/* Is there drive info? */\n#define MULTIBOOT_INFO_DRIVE_INFO               0x00000080\n\n/* Is there a config table? */\n#define MULTIBOOT_INFO_CONFIG_TABLE             0x00000100\n\n/* Is there a boot loader name? */\n#define MULTIBOOT_INFO_BOOT_LOADER_NAME         0x00000200\n\n/* Is there a APM table? */\n#define MULTIBOOT_INFO_APM_TABLE                0x00000400\n\n/* Is there video information? */\n#define MULTIBOOT_INFO_VBE_INFO                 0x00000800\n#define MULTIBOOT_INFO_FRAMEBUFFER_INFO         0x00001000\n\n#ifndef ASM_FILE\n\ntypedef unsigned char           multiboot_uint8_t;\ntypedef unsigned short          multiboot_uint16_t;\ntypedef unsigned int            multiboot_uint32_t;\ntypedef unsigned long long      multiboot_uint64_t;\n\nstruct multiboot_header\n{\n  /* Must be MULTIBOOT_MAGIC - see above. */\n  multiboot_uint32_t magic;\n\n  /* Feature flags. */\n  multiboot_uint32_t flags;\n\n  /* The above fields plus this one must equal 0 mod 2^32. */\n  multiboot_uint32_t checksum;\n\n  /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */\n  multiboot_uint32_t header_addr;\n  multiboot_uint32_t load_addr;\n  multiboot_uint32_t load_end_addr;\n  multiboot_uint32_t bss_end_addr;\n  multiboot_uint32_t entry_addr;\n\n  /* These are only valid if MULTIBOOT_VIDEO_MODE is set. */\n  multiboot_uint32_t mode_type;\n  multiboot_uint32_t width;\n  multiboot_uint32_t height;\n  multiboot_uint32_t depth;\n};\n\n/* The symbol table for a.out. */\nstruct multiboot_aout_symbol_table\n{\n  multiboot_uint32_t tabsize;\n  multiboot_uint32_t strsize;\n  multiboot_uint32_t addr;\n  multiboot_uint32_t reserved;\n};\ntypedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t;\n\n/* The section header table for ELF. */\nstruct multiboot_elf_section_header_table\n{\n  multiboot_uint32_t num;\n  multiboot_uint32_t size;\n  multiboot_uint32_t addr;\n  multiboot_uint32_t shndx;\n};\ntypedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t;\n\nstruct multiboot_info\n{\n  /* Multiboot info version number */\n  multiboot_uint32_t flags;\n\n  /* Available memory from BIOS */\n  multiboot_uint32_t mem_lower;\n  multiboot_uint32_t mem_upper;\n\n  /* \"root\" partition */\n  multiboot_uint32_t boot_device;\n\n  /* Kernel command line */\n  multiboot_uint32_t cmdline;\n\n  /* Boot-Module list */\n  multiboot_uint32_t mods_count;\n  multiboot_uint32_t mods_addr;\n\n  union\n  {\n    multiboot_aout_symbol_table_t aout_sym;\n    multiboot_elf_section_header_table_t elf_sec;\n  } u;\n\n  /* Memory Mapping buffer */\n  multiboot_uint32_t mmap_length;\n  multiboot_uint32_t mmap_addr;\n\n  /* Drive Info buffer */\n  multiboot_uint32_t drives_length;\n  multiboot_uint32_t drives_addr;\n\n  /* ROM configuration table */\n  multiboot_uint32_t config_table;\n\n  /* Boot Loader Name */\n  multiboot_uint32_t boot_loader_name;\n\n  /* APM table */\n  multiboot_uint32_t apm_table;\n\n  /* Video */\n  multiboot_uint32_t vbe_control_info;\n  multiboot_uint32_t vbe_mode_info;\n  multiboot_uint16_t vbe_mode;\n  multiboot_uint16_t vbe_interface_seg;\n  multiboot_uint16_t vbe_interface_off;\n  multiboot_uint16_t vbe_interface_len;\n\n  multiboot_uint64_t framebuffer_addr;\n  multiboot_uint32_t framebuffer_pitch;\n  multiboot_uint32_t framebuffer_width;\n  multiboot_uint32_t framebuffer_height;\n  multiboot_uint8_t framebuffer_bpp;\n#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0\n#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB     1\n#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT     2\n  multiboot_uint8_t framebuffer_type;\n  union\n  {\n    struct\n    {\n      multiboot_uint32_t framebuffer_palette_addr;\n      multiboot_uint16_t framebuffer_palette_num_colors;\n    };\n    struct\n    {\n      multiboot_uint8_t framebuffer_red_field_position;\n      multiboot_uint8_t framebuffer_red_mask_size;\n      multiboot_uint8_t framebuffer_green_field_position;\n      multiboot_uint8_t framebuffer_green_mask_size;\n      multiboot_uint8_t framebuffer_blue_field_position;\n      multiboot_uint8_t framebuffer_blue_mask_size;\n    };\n  };\n};\ntypedef struct multiboot_info multiboot_info_t;\n\nstruct multiboot_color\n{\n  multiboot_uint8_t red;\n  multiboot_uint8_t green;\n  multiboot_uint8_t blue;\n};\n\nstruct multiboot_mmap_entry\n{\n  multiboot_uint32_t size;\n  multiboot_uint64_t addr;\n  multiboot_uint64_t len;\n#define MULTIBOOT_MEMORY_AVAILABLE              1\n#define MULTIBOOT_MEMORY_RESERVED               2\n#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE       3\n#define MULTIBOOT_MEMORY_NVS                    4\n#define MULTIBOOT_MEMORY_BADRAM                 5\n  multiboot_uint32_t type;\n} __attribute__((packed));\ntypedef struct multiboot_mmap_entry multiboot_memory_map_t;\n\nstruct multiboot_mod_list\n{\n  /* the memory used goes from bytes ’mod_start’ to ’mod_end-1’ inclusive */\n  multiboot_uint32_t mod_start;\n  multiboot_uint32_t mod_end;\n\n  /* Module command line */\n  multiboot_uint32_t cmdline;\n\n  /* padding to take it to 16 bytes (must be zero) */\n  multiboot_uint32_t pad;\n};\ntypedef struct multiboot_mod_list multiboot_module_t;\n\n/* APM BIOS info. */\nstruct multiboot_apm_info\n{\n  multiboot_uint16_t version;\n  multiboot_uint16_t cseg;\n  multiboot_uint32_t offset;\n  multiboot_uint16_t cseg_16;\n  multiboot_uint16_t dseg;\n  multiboot_uint16_t flags;\n  multiboot_uint16_t cseg_len;\n  multiboot_uint16_t cseg_16_len;\n  multiboot_uint16_t dseg_len;\n};\n\n/* VBE controller information. */\nstruct vbe_controller\n{\n  unsigned char signature[4];\n  unsigned short version;\n  unsigned long oem_string;\n  unsigned long capabilities;\n  unsigned long video_mode;\n  unsigned short total_memory;\n  unsigned short oem_software_rev;\n  unsigned long oem_vendor_name;\n  unsigned long oem_product_name;\n  unsigned long oem_product_rev;\n  unsigned char reserved[222];\n  unsigned char oem_data[256];\n} __attribute__ ((packed));\n\n/* VBE mode information.  */\nstruct vbe_mode\n{\n  unsigned short mode_attributes;\n  unsigned char win_a_attributes;\n  unsigned char win_b_attributes;\n  unsigned short win_granularity;\n  unsigned short win_size;\n  unsigned short win_a_segment;\n  unsigned short win_b_segment;\n  unsigned long win_func;\n  unsigned short bytes_per_scanline;\n\n  /* >=1.2 */\n  unsigned short x_resolution;\n  unsigned short y_resolution;\n  unsigned char x_char_size;\n  unsigned char y_char_size;\n  unsigned char number_of_planes;\n  unsigned char bits_per_pixel;\n  unsigned char number_of_banks;\n  unsigned char memory_model;\n  unsigned char bank_size;\n  unsigned char number_of_image_pages;\n  unsigned char reserved0;\n\n  /* direct color */\n  unsigned char red_mask_size;\n  unsigned char red_field_position;\n  unsigned char green_mask_size;\n  unsigned char green_field_position;\n  unsigned char blue_mask_size;\n  unsigned char blue_field_position;\n  unsigned char reserved_mask_size;\n  unsigned char reserved_field_position;\n  unsigned char direct_color_mode_info;\n\n  /* >=2.0 */\n  unsigned long phys_base;\n  unsigned long reserved1;\n  unsigned short reversed2;\n\n  /* >=3.0 */\n  unsigned short linear_bytes_per_scanline;\n  unsigned char banked_number_of_image_pages;\n  unsigned char linear_number_of_image_pages;\n  unsigned char linear_red_mask_size;\n  unsigned char linear_red_field_position;\n  unsigned char linear_green_mask_size;\n  unsigned char linear_green_field_position;\n  unsigned char linear_blue_mask_size;\n  unsigned char linear_blue_field_position;\n  unsigned char linear_reserved_mask_size;\n  unsigned char linear_reserved_field_position;\n  unsigned long max_pixel_clock;\n\n  unsigned char reserved3[190];\n} __attribute__ ((packed));\n\n\n#endif /* ! ASM_FILE */\n\n#endif /* ! MULTIBOOT_HEADER */\n"
  },
  {
    "path": "include/fiwix/net/ipv4.h",
    "content": "/*\n * fiwix/include/fiwix/net/ipv4.h\n *\n * Copyright 2025, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifdef CONFIG_NET\n\n#ifndef _FIWIX_NET_IPV4_H\n#define _FIWIX_NET_IPV4_H\n\n#include <fiwix/types.h>\n\n/* AF_INET */\nstruct ipv4_info {\n\tint count;\n\tstruct socket *socket;\n\tstruct ipv4_info *next;\n};\n\nextern struct ipv4_info *ipv4_socket_head;\n\nextern struct proto_ops ipv4_ops;\n\nint ipv4_create(struct socket *, int, int, int);\nvoid ipv4_free(struct socket *);\nint ipv4_bind(struct socket *, const struct sockaddr *, int);\nint ipv4_listen(struct socket *, int);\nint ipv4_connect(struct socket *, const struct sockaddr *, int);\nint ipv4_accept(struct socket *, struct sockaddr *, unsigned int *);\nint ipv4_getname(struct socket *, struct sockaddr *, unsigned int *, int);\nint ipv4_socketpair(struct socket *, struct socket *);\nint ipv4_send(struct socket *, struct fd *, const char *, __size_t, int);\nint ipv4_recv(struct socket *, struct fd *, char *, __size_t, int);\nint ipv4_sendto(struct socket *, struct fd *, const char *, __size_t, int, const struct sockaddr *, int);\nint ipv4_recvfrom(struct socket *, struct fd *, char *, __size_t, int, struct sockaddr *, int *);\nint ipv4_read(struct socket *, struct fd *, char *, __size_t);\nint ipv4_write(struct socket *, struct fd *, const char *, __size_t);\nint ipv4_ioctl(struct socket *, struct fd *, int, unsigned int);\nint ipv4_select(struct socket *, int);\nint ipv4_shutdown(struct socket *, int);\nint ipv4_setsockopt(struct socket *, int, int, const void *, unsigned int);\nint ipv4_getsockopt(struct socket *, int, int, void *, unsigned int *);\nint ipv4_init(void);\n\n#endif /* _FIWIX_NET_IPV4_H */\n\n#endif /* CONFIG_NET */\n"
  },
  {
    "path": "include/fiwix/net/packet.h",
    "content": "/*\n * fiwix/include/fiwix/net/packet.h\n *\n * Copyright 2024, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifdef CONFIG_NET\n\n#ifndef _FIWIX_NET_PACKET_H\n#define _FIWIX_NET_PACKET_H\n\n#include <fiwix/types.h>\n\nstruct packet {\n\tchar *data;\n\tint len;\n\t__off_t offset;\n\tstruct socket *socket;\n\tstruct packet *prev;\n\tstruct packet *next;\n};\n\nstruct packet *peek_packet(struct packet *);\nstruct packet *remove_packet_from_queue(struct packet **);\nvoid append_packet_to_queue(struct packet *, struct packet **);\n\n#endif /* _FIWIX_NET_PACKET_H */\n\n#endif /* CONFIG_NET */\n"
  },
  {
    "path": "include/fiwix/net/unix.h",
    "content": "/*\n * fiwix/include/fiwix/net/unix.h\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifdef CONFIG_NET\n\n#ifndef _FIWIX_NET_UNIX_H\n#define _FIWIX_NET_UNIX_H\n\n#include <fiwix/types.h>\n#include <fiwix/net/packet.h>\n\n/* AF_UNIX */\nstruct unix_info {\n\tint count;\n\tchar *data;\n\tint readoff;\n\tint writeoff;\n\tint size;\n\tstruct sockaddr_un *sun;\n\tshort int sun_len;\n\tstruct inode *inode;\n\tstruct socket *socket;\n\tstruct packet *packet_queue;\n\tstruct unix_info *peer;\n\tstruct unix_info *next;\n};\n\nextern struct unix_info *unix_socket_head;\n\nextern struct proto_ops unix_ops;\n\nint unix_create(struct socket *, int, int, int);\nvoid unix_free(struct socket *);\nint unix_bind(struct socket *, const struct sockaddr *, int);\nint unix_listen(struct socket *, int);\nint unix_connect(struct socket *, const struct sockaddr *, int);\nint unix_accept(struct socket *, struct sockaddr *, unsigned int *);\nint unix_getname(struct socket *, struct sockaddr *, unsigned int *, int);\nint unix_socketpair(struct socket *, struct socket *);\nint unix_send(struct socket *, struct fd *, const char *, __size_t, int);\nint unix_recv(struct socket *, struct fd *, char *, __size_t, int);\nint unix_sendto(struct socket *, struct fd *, const char *, __size_t, int, const struct sockaddr *, int);\nint unix_recvfrom(struct socket *, struct fd *, char *, __size_t, int, struct sockaddr *, int *);\nint unix_read(struct socket *, struct fd *, char *, __size_t);\nint unix_write(struct socket *, struct fd *, const char *, __size_t);\nint unix_ioctl(struct socket *, struct fd *, int, unsigned int);\nint unix_select(struct socket *, int);\nint unix_shutdown(struct socket *, int);\nint unix_setsockopt(struct socket *, int, int, const void *, unsigned int);\nint unix_getsockopt(struct socket *, int, int, void *, unsigned int *);\nint unix_init(void);\n\n#endif /* _FIWIX_NET_UNIX_H */\n\n#endif /* CONFIG_NET */\n"
  },
  {
    "path": "include/fiwix/net.h",
    "content": "/*\n * fiwix/include/fiwix/net.h\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifdef CONFIG_NET\n\n#ifndef _FIWIX_NET_H\n#define _FIWIX_NET_H\n\n#include <fiwix/types.h>\n#include <fiwix/socket.h>\n#include <fiwix/fd.h>\n#include <fiwix/net/unix.h>\n#include <fiwix/net/ipv4.h>\n\n#define SYS_SOCKET\t1\n#define SYS_BIND\t2\n#define SYS_CONNECT\t3\n#define SYS_LISTEN\t4\n#define SYS_ACCEPT\t5\n#define SYS_GETSOCKNAME\t6\n#define SYS_GETPEERNAME\t7\n#define SYS_SOCKETPAIR\t8\n#define SYS_SEND\t9\n#define SYS_RECV\t10\n#define SYS_SENDTO\t11\n#define SYS_RECVFROM\t12\n#define SYS_SHUTDOWN\t13\n#define SYS_SETSOCKOPT\t14\n#define SYS_GETSOCKOPT\t15\n\ntypedef unsigned int\tsocklen_t;\n\nstruct socket {\n\tshort int state;\n\tint flags;\n\tstruct fd *fd;\n\tint fd_ext;\t\t\t/* fd of external TCP/IP API */\n\tshort int type;\n\tstruct proto_ops *ops;\n\tint queue_len;\t\t\t/* number of connections in queue */\n\tint queue_limit;\t\t/* max. number of pending connections */\n\tstruct socket *queue_head;\t/* first connection in queue */\n\tstruct socket *next_queue;\t/* next connection in queue */\n\tunion {\n\t\tstruct unix_info unix_info;\n\t\tstruct ipv4_info ipv4_info;\n\t} u;\n};\n\nstruct domain_table {\n\tint family;\n\tchar *name;\n\tstruct proto_ops *ops;\n};\n\nstruct proto_ops {\n\tint (*create)(struct socket *, int, int, int);\n\tvoid (*free)(struct socket *);\n\tint (*bind)(struct socket *, const struct sockaddr *, int);\n\tint (*listen)(struct socket *, int);\n\tint (*connect)(struct socket *, const struct sockaddr *, int);\n\tint (*accept)(struct socket *, struct sockaddr *, unsigned int *);\n\tint (*getname)(struct socket *, struct sockaddr *, unsigned int *, int);\n\tint (*socketpair)(struct socket *, struct socket *);\n\tint (*send)(struct socket *, struct fd *, const char *, __size_t, int);\n\tint (*recv)(struct socket *, struct fd *, char *, __size_t, int);\n\tint (*sendto)(struct socket *, struct fd *, const char *, __size_t, int, const struct sockaddr *, int);\n\tint (*recvfrom)(struct socket *, struct fd *, char *, __size_t, int, struct sockaddr *, int *);\n\tint (*read)(struct socket *, struct fd *, char *, __size_t);\n\tint (*write)(struct socket *, struct fd *, const char *, __size_t);\n\tint (*ioctl)(struct socket *, struct fd *, int, unsigned int);\n\tint (*select)(struct socket *, int);\n\tint (*shutdown)(struct socket *, int);\n\tint (*setsockopt)(struct socket *, int, int, const void *, unsigned int);\n\tint (*getsockopt)(struct socket *, int, int, void *, unsigned int *);\n\tint (*init)(void);\n};\n\nint assign_proto(struct socket *, int);\n\nstruct socket *get_socket_from_queue(struct socket *);\nint insert_socket_to_queue(struct socket *, struct socket *);\nint sock_alloc(struct socket **);\nvoid sock_free(struct socket *);\nint socket(int, int, int);\nint bind(int, struct sockaddr *, int);\nint listen(int, int);\nint connect(int, struct sockaddr *, int);\nint accept(int, struct sockaddr *, unsigned int *);\nint getname(int, struct sockaddr *, unsigned int *, int);\nint socketpair(int, int, int, int [2]);\nint send(int, const void *, __size_t, int);\nint recv(int, void *, __size_t, int);\nint sendto(int, const void *, __size_t, int, const struct sockaddr *, int);\nint recvfrom(int, void *, __size_t, int, struct sockaddr *, int *);\nint shutdown(int, int);\nint setsockopt(int, int, int, const void *, socklen_t);\nint getsockopt(int, int, int, void *, socklen_t *);\n\nvoid net_init(void);\n\n#endif /* _FIWIX_NET_H */\n\n#endif /* CONFIG_NET */\n"
  },
  {
    "path": "include/fiwix/netdevice.h",
    "content": "/*\n * fiwix/include/fiwix/netdevice.h\n *\n * Copyright 2026, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifdef CONFIG_NET\n\n#ifndef _FIWIX_NETDEVICE_H\n#define _FIWIX_NETDEVICE_H\n\nint dev_ioctl(int, void *);\n\n#endif /* _FIWIX_NETDEVICE_H */\n\n#endif /* CONFIG_NET */\n"
  },
  {
    "path": "include/fiwix/part.h",
    "content": "/*\n * fiwix/include/fiwix/part.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_PART_H\n#define _FIWIX_PART_H\n\n#define PARTITION_BLOCK\t\t0\n#define NR_PARTITIONS\t\t4\t/* partitions in the MBR */\n#define MBR_CODE_SIZE\t\t446\n#define ACTIVE_PART\t\t0x80\n\nstruct hd_geometry {\n\tunsigned char heads;\n\tunsigned char sectors;\n\tunsigned short int cylinders;\n\tunsigned int start;\n};\n\nstruct partition {\n\tunsigned char status;\n\tunsigned char head;\n\tunsigned char sector;\n\tunsigned char cyl;\n\tunsigned char type;\n\tunsigned char endhead;\n\tunsigned char endsector;\n\tunsigned char endcyl;\n\tunsigned int startsect;\n\tunsigned int nr_sects;\n};\n\nint read_msdos_partition(__dev_t, struct partition *);\n\n#endif /* _FIWIX_PART_H */\n"
  },
  {
    "path": "include/fiwix/pci.h",
    "content": "/*\n * fiwix/include/fiwix/pci.h\n *\n * Copyright 2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifdef CONFIG_PCI\n\n#ifndef _FIWIX_PCI_H\n#define _FIWIX_PCI_H\n\n#include <fiwix/pci_ids.h>\n\n#define PCI_ADDRESS\t0x0CF8\n#define PCI_DATA\t0x0CFC\n\n#define PCI_MAX_BUS\t16\t/* 256 buses maximum */\n#define PCI_MAX_DEV\t32\n#define PCI_MAX_FUNC\t8\n\n#define PCI_VENDOR_ID\t\t0x00\t/* 16 bits */\n#define PCI_DEVICE_ID\t\t0x02\t/* 16 bits */\n\n#define PCI_COMMAND\t\t0x04\t/* 16 bits */\n#define PCI_COMMAND_IO\t\t0x1\t/* enable response in I/O space */\n#define PCI_COMMAND_MEMORY\t0x2\t/* enable response in memory space */\n#define PCI_COMMAND_MASTER\t0x4\t/* enable bus mastering */\n\n#define PCI_STATUS\t\t0x06\t/* 16 bits */\n#define PCI_REVISION_ID\t\t0x08\t/*  8 bits */\n#define PCI_PROG_IF\t\t0x09\t/*  8 bits */\n#define PCI_CLASS_DEVICE\t0x0A\t/* 16 bits (class + subclass) */\n#define PCI_CACHE_LINE_SIZE\t0x0C\t/*  8 bits */\n#define PCI_LATENCY_TIMER\t0x0D\t/*  8 bits */\n\n#define PCI_HEADER_TYPE\t\t0x0E\t/*  8 bits */\n#define PCI_HEADER_TYPE_NORMAL\t0x00\t/* standard header */\n\n#define PCI_BIST\t\t0x0F\t/*  8 bits */\n#define PCI_BASE_ADDR_0\t\t0x10\t/* 32 bits */\n#define PCI_BASE_ADDR_1\t\t0x14\t/* 32 bits (header 0 and 1 only) */\n#define PCI_BASE_ADDR_2\t\t0x18\t/* 32 bits (header 0 only) */\n#define PCI_BASE_ADDR_3\t\t0x1C\t/* 32 bits */\n#define PCI_BASE_ADDR_4\t\t0x20\t/* 32 bits */\n#define PCI_BASE_ADDR_5\t\t0x24\t/* 32 bits */\n\n#define PCI_BASE_ADDR_SPACE\t0x01\t/* 0 = memory, 1 = I/O */\n#define PCI_BASE_ADDR_SPACE_MEM\t0x00\n#define PCI_BASE_ADDR_SPACE_IO\t0x01\n#define PCI_BASE_ADDR_TYPE_MASK\t0x06\t/* base register size (32bit/64bit) */\n#define PCI_BASE_ADDR_TYPE_32\t0x00\t/* 32 bit address */\n#define PCI_BASE_ADDR_TYPE_64\t0x04\t/* 64 bit address */\n#define PCI_BASE_ADDR_MEM_PREF\t0x08\t/* prefetchable memory */\n#define PCI_BASE_ADDR_MEM_MASK\t0xFFFFFFF0\n#define PCI_BASE_ADDR_IO_MASK\t0xFFFFFFFC\n\n#define PCI_INTERRUPT_LINE\t0x3C\t/*  8 bits */\n#define PCI_INTERRUPT_PIN\t0x3D\t/*  8 bits */\n#define PCI_MIN_GRANT\t\t0x3E\t/*  8 bits */\n#define PCI_MAX_LATENCY\t\t0x3F\t/*  8 bits */\n\n/* bus mastering */\n#define BM_COMMAND\t\t0x00\t/* command register primary */\n#define BM_STATUS\t\t0x02\t/* status register primary */\n#define BM_PRD_ADDRESS\t\t0x04\t/* PRD table address primary */\n\n#define BM_COMMAND_START\t0x01\t/* start */\n#define BM_COMMAND_READ\t\t0x08\t/* read from disk and write to memory */\n#define BM_COMMAND_WRITE\t0x00\t/* read from memory and write to disk */\n\n#define BM_STATUS_ACTIVE\t0x01\t/* active */\n#define BM_STATUS_ERROR\t\t0x02\t/* error */\n#define BM_STATUS_INTR\t\t0x04\t/* IDE interrupt */\n#define BM_STATUS_DRVDMA\t0x20\t/* drive 0 is DMA capable */\n\t\t\t\t\t/* 0x40: drive 1 is DMA capable */\n#define BM_STATUS_SIMPLEX\t0x80\t/* simplex only */\n\n/* flags */\n#define PCI_F_ADDR_SPACE_IO\t0x01\n#define PCI_F_ADDR_SPACE_MEM\t0x02\n#define PCI_F_ADDR_MEM_32\t0x04\t/* 32 bit address */\n#define PCI_F_ADDR_MEM_64\t0x08\t/* 64 bit address */\n#define PCI_F_ADDR_SPACE_PREFET\t0x10\t/* prefetchable memory */\n\n#define PCI_DEVFN(dev,func)\t((((dev) & 0x1f) << 3) | ((func) & 0x07))\n\nstruct pci_supported_devices {\n\tunsigned short int vendor_id;\n\tunsigned short int device_id;\n};\n\nstruct pci_device {\n\tunsigned char bus;\n\tunsigned char dev;\n\tunsigned char func;\n\tunsigned short int vendor_id;\n\tunsigned short int device_id;\n\tunsigned short int command;\n\tunsigned short int status;\n\tunsigned char rev;\n\tunsigned char prog_if;\n\tunsigned short int class;\n\tunsigned char cline_size;\n\tunsigned char latency;\n\tunsigned char hdr_type;\n\tunsigned char bist;\n\tunsigned int obar[6];\t/* original address */\n\tunsigned int bar[6];\n\tunsigned char irq;\n\tunsigned char pin;\n\tunsigned char min_gnt;\n\tunsigned char max_lat;\n\tchar size[6];\n\tchar flags[6];\n\tconst char *name;\n\tstruct pci_device *prev;\n\tstruct pci_device *next;\n};\nextern struct pci_device *pci_device_table;\n\nunsigned char pci_read_char(struct pci_device *, int);\nunsigned short int pci_read_short(struct pci_device *, int);\nunsigned int pci_read_long(struct pci_device *, int);\nvoid pci_write_char(struct pci_device *, int, unsigned char);\nvoid pci_write_short(struct pci_device *, int, unsigned short int);\nvoid pci_write_long(struct pci_device *, int, unsigned int);\nvoid pci_show_desc(struct pci_device *);\nvoid pci_init(void);\n\n#endif /* _FIWIX_PCI_H */\n\n#endif /* CONFIG_PCI */\n"
  },
  {
    "path": "include/fiwix/pci_ids.h",
    "content": "/*\n * fiwix/include/fiwix/pci_ids.h\n *\n * Copyright 2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_PCI_IDS_H\n#define _FIWIX_PCI_IDS_H\n\n/* device classes and subclasses */\n#define PCI_CLASS_NOT_DEFINED\t\t0x0000\n#define PCI_CLASS_NOT_DEFINED_VGA\t0x0001\n\n#define PCI_CLASS_STORAGE_IDE\t\t0x0101\n\n#define PCI_CLASS_NETWORK_ETHERNET\t0x0200\n\n#define PCI_CLASS_DISPLAY_VGA\t\t0x0300\n\n#define PCI_CLASS_MULTIMEDIA_VIDEO\t0x0400\n#define PCI_CLASS_MULTIMEDIA_AUDIO\t0x0401\n#define PCI_CLASS_MULTIMEDIA_OTHER\t0x0480\n\n#define PCI_CLASS_BRIDGE_HOST\t\t0x0600\n#define PCI_CLASS_BRIDGE_ISA\t\t0x0601\n#define PCI_CLASS_BRIDGE_PCI\t\t0x0604\n#define PCI_CLASS_BRIDGE_OTHER\t\t0x0680\n\n#define PCI_CLASS_COMMUNICATION_SERIAL\t0x0700\n\n#define PCI_CLASS_SYSTEM_PIC\t\t0x0800\n\n#define PCI_CLASS_SERIAL_FIREWIRE\t0x0c00\n#define PCI_CLASS_SERIAL_USB\t\t0x0c03\n\n\n/* supported vendor and device ids */\n#define PCI_VENDOR_ID_BOCHS\t\t0x1234\n#define PCI_DEVICE_ID_BGA\t\t0x1111\n\n#endif /* _FIWIX_PCI_IDS_H */\n"
  },
  {
    "path": "include/fiwix/pic.h",
    "content": "/*\n * fiwix/include/fiwix/pic.h\n *\n * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_PIC_H\n#define _FIWIX_PIC_H\n\n#define PIC_MASTER\t0x20\t/* I/O base address for master PIC */\n#define PIC_SLAVE\t0xA0\t/* I/O base address for slave PIC */\n\n#define DATA\t\t0x01\t/* offset to data port */\n#define EOI\t\t0x20\t/* End-Of-Interrupt command code */\n\n/* Inicialization Command Words */\n#define ICW1_RESET\t0x11\t/* ICW1_INIT + ICW1_ICW4 */\n#define CASCADE_IRQ\t0x02\n#define ICW4_8086EOI\t0x01\n\n#define PIC_READ_IRR\t0x0A\t/* OCW3 irq ready */\n#define PIC_READ_ISR\t0x0B\t/* OCW3 irq service */\n\n/* Operational Command Words */\n#define OCW1\t\t0xFF\t/* mask (disable) all IRQs */\n\nvoid enable_irq(int);\nvoid disable_irq(int);\nvoid spurious_interrupt(int);\nvoid ack_pic_irq(int);\nvoid pic_init(void);\n\n#endif /* _FIWIX_PIC_H */\n"
  },
  {
    "path": "include/fiwix/pit.h",
    "content": "/*\n * fiwix/include/fiwix/pit.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_PIT_H\n#define _FIWIX_PIT_H\n\n/* Intel 8253/82c54 Programmable Interval Timer */\n\n#define OSCIL\t\t1193182\t/* oscillator frequency */\n\n#define MODEREG\t\t0x43\t/* mode/command register (w) */\n#define CHANNEL0\t0x40\t/* channel 0 data port (rw) */\n#define CHANNEL2\t0x42\t/* channel 2 data port (rw) */\n\n#define BINARY_CTR\t0x00\t/* 16bit binary mode counter */\n#define TERM_COUNT\t0x00\t/* mode 0 (Terminal Count) */\n#define RATE_GEN\t0x04\t/* mode 2 (Rate Generator) */\n#define SQUARE_WAVE\t0x06\t/* mode 3 (Square Wave) */\n#define LSB_MSB\t\t0x30\t/* LSB then MSB */\n#define SEL_CHAN0\t0x00\t/* select channel 0 */\n#define SEL_CHAN2\t0x80\t/* select channel 2 */\n\n/*\n * PS/2 System Control Port B bits\n * ---------------------------------------------------------------------\n * #7 R:system board RAM parity\t\tW:IRQ=1, 0=reset\n * #6 R:channel check\t\t\tW:reserved\n * #5 R:timer 2 (speaker time) output\tW:reserved\n * #4 R:refresh request (toggle)\tW:reserved\n * #3 R:channel check status\t\tW:channel check enable\n * #2 R:parity check status\t\tW:parity check enable\n * #1 R:speaker data status\t\tW:speaker data enable\n * #0 R:timer 2 gate to speaker status\tW:timer 2 gate to speaker enable\n */\n#define PS2_SYSCTRL_B\t0x61\t/* PS/2 system control port B (R/W) */\n\n#define ENABLE_TMR2G\t0x01\t/* timer 2 gate to speaker enable */\n#define ENABLE_SDATA\t0x02\t/* speaker data enable */\n\n#define BEEP_FREQ\t900\t/* 900Hz */\n\nvoid pit_beep_on(void);\nvoid pit_beep_off(unsigned int);\nint pit_getcounter0(void);\nvoid pit_init(unsigned short int);\n\n#endif /* _FIWIX_PIT_H */\n"
  },
  {
    "path": "include/fiwix/process.h",
    "content": "/*\n * fiwix/include/fiwix/process.h\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_PROCESS_H\n#define _FIWIX_PROCESS_H\n\nstruct vma {\n\tunsigned int start;\n\tunsigned int end;\n\tchar prot;\t\t/* PROT_READ, PROT_WRITE, ... */\n\tunsigned int flags;\t/* MAP_SHARED, MAP_PRIVATE, ... */\n\tunsigned int offset;\n\tchar s_type;\t\t/* segment type (P_TEXT, P_DATA, ...) */\n\tstruct inode *inode;\t/* file inode */\n\tchar o_mode;\t\t/* open mode (O_RDONLY, O_RDWR, ...) */\n\tvoid *object;\t\t/* generic pointer (currently only for shm) */\n\tstruct vma *prev;\n\tstruct vma *next;\n};\n\n#include <fiwix/config.h>\n#include <fiwix/types.h>\n#include <fiwix/signal.h>\n#include <fiwix/limits.h>\n#include <fiwix/sigcontext.h>\n#include <fiwix/time.h>\n#include <fiwix/resource.h>\n#include <fiwix/tty.h>\n\n#define IDLE\t\t0\t\t/* PID of idle */\n#define INIT\t\t1\t\t/* PID of /sbin/init */\n#define SAFE_SLOTS\t2\t\t/* process slots reserved for root */\n#define SLOT(p)\t\t((p) - (&proc_table[0]))\n\n/* bits in flags */\n#define PF_KPROC\t0x00000001\t/* kernel internal process */\n#define PF_PEXEC\t0x00000002\t/* has performed a sys_execve() */\n#define PF_USEREAL\t0x00000004\t/* use real UID in permission checks */\n#define PF_NOTINTERRUPT\t0x00000008\t/* non-interruptible sleeping */\n\n#define MMAP_START\t0x40000000\t/* mmap()s start at 1GB */\n#define IS_SUPERUSER\t(current->euid == 0)\n\n#define IO_BITMAP_SIZE\t8192\t\t/* 8192*8bit = all I/O address space */\n\n#define PG_LEADER(p)\t((p)->pid == (p)->pgid)\n#define SESS_LEADER(p)\t((p)->pid == (p)->pgid && (p)->pid == (p)->sid)\n\n#define FOR_EACH_PROCESS(p)\t\tp = proc_table_head->next ; while(p)\n#define FOR_EACH_PROCESS_RUNNING(p)\tp = proc_run_head ; while(p)\n\n/* value to be determined during system startup */\nextern unsigned int proc_table_size;\t/* size in bytes */\n\nextern char any_key_to_reboot;\nextern int nr_processes;\nextern __pid_t lastpid;\nextern struct proc *proc_table_head;\n\nstruct binargs {\n\tunsigned int page[ARG_MAX];\n\tint argc;\n\tint argv_len;\n\tint envc;\n\tint envp_len;\n\tint offset;\n};\n\n/* Intel 386 Task Switch State */\nstruct i386tss {\n\tunsigned int prev_tss;\n\tunsigned int esp0;\n\tunsigned int ss0;\n\tunsigned int esp1;\n\tunsigned int ss1;\n\tunsigned int esp2;\n\tunsigned int ss2;\n\tunsigned int cr3;\n\tunsigned int eip;\n\tunsigned int eflags;\n\tunsigned int eax;\n\tunsigned int ecx;\n\tunsigned int edx;\n\tunsigned int ebx;\n\tunsigned int esp;\n\tunsigned int ebp;\n\tunsigned int esi;\n\tunsigned int edi;\n\tunsigned int es;\n\tunsigned int cs;\n\tunsigned int ss;\n\tunsigned int ds;\n\tunsigned int fs;\n\tunsigned int gs;\n\tunsigned int ldt;\n\tunsigned short int debug_trap;\n\tunsigned short int io_bitmap_addr;\n\tunsigned char io_bitmap[IO_BITMAP_SIZE + 1];\n};\n\nstruct proc {\n\tstruct i386tss tss;\n\tstruct proc *ppid;\t\t/* pointer to parent process */\n\t__pid_t pid;\t\t\t/* process ID */\n\t__pid_t pgid;\t\t\t/* process group ID */\n\t__pid_t sid;\t\t\t/* session ID */\n\tint flags;\n\tint groups[NGROUPS_MAX];\n\tint children;\t\t\t/* number of children */\n\tstruct tty *ctty;\t\t/* controlling terminal */\n\tint state;\t\t\t/* process state */\n\tint priority;\n\tint cpu_count;\t\t\t/* time of process running */\n\t__time_t start_time;\n\tint exit_code;\t\n\tvoid *sleep_address;\n\tunsigned short int uid;\t\t/* real user ID */\n\tunsigned short int gid;\t\t/* real group ID */\n\tunsigned short int euid;\t/* effective user ID */\n\tunsigned short int egid;\t/* effective group ID */\n\tunsigned short int suid;\t/* saved user ID */\n\tunsigned short int sgid;\t/* saved group ID */\n\tunsigned short int fd[OPEN_MAX];\n\tunsigned char fd_flags[OPEN_MAX];\n\tstruct inode *root;\n\tstruct inode *pwd;\t\t/* process working directory */\n\tunsigned int entry_address;\n\tunsigned int end_code;\n\tchar argv0[NAME_MAX + 1];\n\tint argc;\n\tchar **argv;\n\tint envc;\n\tchar **envp;\n\tchar pidstr[5];\t\t\t/* PID number converted to string */\n\tstruct vma *vma_table;\t\t/* virtual memory-map addresses */\n\tunsigned int brk_lower;\t\t/* lower limit of the heap section */\n\tunsigned int brk;\t\t/* current limit of the heap */\n\t__sigset_t sigpending;\n\t__sigset_t sigblocked;\n\t__sigset_t sigexecuting;\n\tstruct sigaction sigaction[NSIG];\n\tstruct sigcontext sc[NSIG];\t/* each signal has its own context */\n\tunsigned int sp;\t\t/* current process' stack frame */\n\tstruct rusage usage;\t\t/* process resource usage */\n\tstruct rusage cusage;\t\t/* children resource usage */\n\tunsigned int it_real_interval, it_real_value;\n\tunsigned int it_virt_interval, it_virt_value;\n\tunsigned int it_prof_interval, it_prof_value;\n\tunsigned int timeout;\n\tstruct rlimit rlim[RLIM_NLIMITS];\n\tunsigned int rss;\n\t__mode_t umask;\n\tunsigned char loopcnt;\t\t/* nested symlinks counter */\n#ifdef CONFIG_SYSVIPC\n\tstruct sem_undo *semundo;\n#endif /* CONFIG_SYSVIPC */\n\tstruct proc *prev;\n\tstruct proc *next;\n\tstruct proc *prev_sleep;\n\tstruct proc *next_sleep;\n\tstruct proc *prev_run;\n\tstruct proc *next_run;\n};\n\nextern struct proc *current;\nextern struct proc *proc_table;\n\nint can_signal(struct proc *);\nint send_sig(struct proc *, __sigset_t);\n\nvoid add_crusage(struct proc *, struct rusage *);\nvoid get_rusage(struct proc *, struct rusage *);\nvoid add_rusage(struct proc *);\nstruct proc *get_next_zombie(struct proc *);\n__pid_t remove_zombie(struct proc *);\nint is_orphaned_pgrp(__pid_t);\nstruct proc *get_proc_free(void);\nvoid release_proc(struct proc *);\nint get_unused_pid(void);\nstruct proc *get_proc_by_pid(__pid_t);\n\nstruct proc *kernel_process(const char *, int (*fn)(void));\nvoid proc_slot_init(struct proc *);\nvoid proc_init(void);\n\nint elf_load(struct inode *, struct binargs *, struct sigcontext *, char *);\nint script_load(char *, char *, char *);\n\n#endif /* _FIWIX_PROCESS_H */\n"
  },
  {
    "path": "include/fiwix/ps2.h",
    "content": "/*\n * fiwix/include/fiwix/ps2.h\n *\n * Copyright 2024, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_PS2_H\n#define _FIWIX_PS2_H\n\n#define PS2_DATA\t0x60\t/* I/O data port */\n#define PS2_STATUS\t0x64\t/* status register port */\n#define PS2_COMMAND\t0x64\t/* command/control port */\n\n/* status register */\n#define PS2_STAT_OUTBUSY\t0x01\t/* output buffer full, don't read yet */\n#define PS2_STAT_INBUSY\t\t0x02\t/* input buffer full, don't write yet */\n#define PS2_STAT_TXTMOUT\t0x20\t/* transmit time-out error */\n#define PS2_STAT_RXTMOUT\t0x40\t/* receive time-out error */\n#define PS2_STAT_PARERR\t\t0x80\t/* parity error */\n#define PS2_STAT_COMMERR\t(PS2_STAT_TXTMOUT | PS2_STAT_RXTMOUT)\n\n/* controller commands */\n#define PS2_CMD_RECV_CONFIG\t0x20\t/* read controller's config byte */\n#define PS2_CMD_SEND_CONFIG\t0x60\t/* write controller's config byte */\n#define PS2_CMD_DISABLE_CH2\t0xA7\t/* disable second channel (if any) */\n#define PS2_CMD_ENABLE_CH2\t0xA8\t/* enable second channel (if any) */\n#define PS2_CMD_TEST_CH2\t0xA9\t/* test interface second channel */\n#define PS2_CMD_SELF_TEST\t0xAA\t/* self-test command */\n#define PS2_CMD_TEST_CH1\t0xAB\t/* test interface first channel */\n#define PS2_CMD_DISABLE_CH1\t0xAD\t/* disable first channel */\n#define PS2_CMD_ENABLE_CH1\t0xAE\t/* enable first channel */\n#define PS2_CMD_CH2_PREFIX\t0xD4\t/* second channel (mouse) prefix */\n#define PS2_CMD_HOTRESET\t0xFE\t/* Hot Reset */\n\n/* device commands */\n#define PS2_DEV_GETINFO\t\t0xE9\t/* get current status information */\n#define PS2_KB_SETLED\t\t0xED\t/* set/reset status indicators (LEDs) */\n#define PS2_KB_ECHO\t\t0xEE\t/* echo (for diagnostics only) */\n#define PS2_KB_GETSETSCAN\t0xF0\t/* keyboard get/set scan code */\n#define PS2_DEV_IDENTIFY\t0xF2\t/* device identify (for PS/2 only) */\n#define PS2_DEV_RATE\t\t0xF3\t/* set typematic rate/delay */\n#define PS2_DEV_ENABLE\t\t0xF4\t/* keyboard enable scanning */\n#define PS2_KB_DISABLE\t\t0xF5\t/* keyboard disable scanning */\n#define PS2_AUX_DISABLE\t\t0xF6\t/* mouse disable scanning */\n#define PS2_DEV_RESET\t\t0xFF\t/* device reset */\n\n#define DEV_RESET_OK\t\t0xAA\t/* self-test passed */\n#define DEV_ACK\t\t\t0xFA\t/* acknowledge */\n\n#define PS2_TIMEOUT\t\t600000\n\nextern volatile unsigned char ack;\n\nint ps2_wait_ack(void);\nvoid ps2_write(const unsigned char, const unsigned char);\nunsigned char ps2_read(const unsigned char);\nvoid ps2_clear_buffer(void);\nvoid ps2_init(void);\n\n#endif /* _FIWIX_PS2_H */\n"
  },
  {
    "path": "include/fiwix/psaux.h",
    "content": "/*\n * fiwix/include/fiwix/psaux.h\n *\n * Copyright 2024, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifdef CONFIG_PSAUX\n\n#ifndef _FIWIX_PSAUX_H\n#define _FIWIX_PSAUX_H\n\n#include <fiwix/fs.h>\n#include <fiwix/charq.h>\n#include <fiwix/sigcontext.h>\n\n#define PSAUX_IRQ\t12\n\n#define PSAUX_MAJOR\t10\t/* major number for /dev/psaux */\n#define PSAUX_MINOR\t1\t/* minor number for /dev/psaux */\n\nstruct psaux {\n\tint count;\n\tstruct clist read_q;\n\tstruct clist write_q;\n};\nextern struct psaux psaux_table;\n\nint psaux_open(struct inode *, struct fd *);\nint psaux_close(struct inode *, struct fd *);\nint psaux_read(struct inode *, struct fd *, char *, __size_t);\nint psaux_write(struct inode *, struct fd *, const char *, __size_t);\nint psaux_select(struct inode *, struct fd *, int);\n\nvoid irq_psaux(int num, struct sigcontext *);\nvoid psaux_init(void);\n\n#endif /* _FIWIX_PSAUX_H */\n\n#endif /* CONFIG_PSAUX */\n"
  },
  {
    "path": "include/fiwix/pty.h",
    "content": "/*\n * fiwix/include/fiwix/pty.h\n *\n * Copyright 2025, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifdef CONFIG_UNIX98_PTYS\n\n#ifndef _FIWIX_PTY_H\n#define _FIWIX_PTY_H\n\n#define PTY_MASTER_MAJOR\t5\t/* major number for /dev/ptmx */\n#define PTY_MASTER_MINOR\t2\t/* minor number for /dev/ptmx */\n#define PTY_SLAVE_MAJOR\t\t136\t/* major number for PTY slaves */\n\n#define PTMX_DEV\t\tMKDEV(PTY_MASTER_MAJOR, PTY_MASTER_MINOR)\n\nvoid pty_wakeup_read(struct tty *);\nint pty_open(struct tty *);\nint pty_close(struct tty *);\nint pty_read(struct inode *, struct fd *, char *, __size_t);\nint pty_write(struct inode *, struct fd *, const char *, __size_t);\nint pty_ioctl(struct tty *, struct fd *, int, unsigned int);\nint pty_select(struct inode *, struct fd *, int);\nvoid pty_init(void);\n\n#endif /* _FIWIX_PTY_H */\n\n#endif /* CONFIG_UNIX98_PTYS */\n"
  },
  {
    "path": "include/fiwix/ramdisk.h",
    "content": "/*\n * fiwix/include/fiwix/ramdisk.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_RAMDISK_H\n#define _FIWIX_RAMDISK_H\n\n#include <fiwix/fs.h>\n\n#define RAMDISK_MAJOR\t1\t/* ramdisk device major number */\n#define RAMDISK_TOTAL\t10\t/* total number of ramdisk drives */\n\nstruct ramdisk {\n\tchar *addr;\t\t/* ramdisk memory address */\n\tint size;\t\t/* in KB */\n};\n\nextern int ramdisk_minors;\t/* initrd + RAMDISK_DRIVES + kexec */\nextern struct ramdisk ramdisk_table[RAMDISK_TOTAL];\n\nint ramdisk_open(struct inode *, struct fd *);\nint ramdisk_close(struct inode *, struct fd *);\nint ramdisk_read(__dev_t, __blk_t, char *, int);\nint ramdisk_write(__dev_t, __blk_t, char *, int);\nint ramdisk_ioctl(struct inode *, struct fd *, int, unsigned int);\n__loff_t ramdisk_llseek(struct inode *, __loff_t);\n\nvoid ramdisk_init(void);\n\n#endif /* _FIWIX_RAMDISK_H */\n"
  },
  {
    "path": "include/fiwix/reboot.h",
    "content": "/*\n * fiwix/include/fiwix/reboot.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_REBOOT_H\n#define _FIWIX_REBOOT_H\n\n#define BMAGIC_HARD\t0x89ABCDEF\n#define BMAGIC_SOFT\t0\n#define BMAGIC_REBOOT\t0x01234567\n#define BMAGIC_HALT\t0xCDEF0123\n#define BMAGIC_POWEROFF\t0x4321FEDC\n\n#define BMAGIC_1\t0xFEE1DEAD\n#define BMAGIC_2\t672274793\n\nextern char ctrl_alt_del;\nvoid reboot(void);\n\n#endif /* _FIWIX_REBOOT_H */\n"
  },
  {
    "path": "include/fiwix/resource.h",
    "content": "/*\n * fiwix/include/fiwix/resource.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_RESOURCE_H\n#define _FIWIX_RESOURCE_H\n\n#include <fiwix/time.h>\n\n#define RLIMIT_INFINITY\t0x7FFFFFFF\t/* value to indicate \"no limit\" */\n#define RLIM_INFINITY\tRLIMIT_INFINITY\t/* traditional name */\n\n#define RUSAGE_SELF\t0\t\t/* the calling process */\n#define RUSAGE_CHILDREN\t(-1)\t\t/* all of its termin. child processes */\n\n#define RLIMIT_CPU\t0\t\t/* per-process CPU limit (secs) */\n#define RLIMIT_FSIZE\t1\t\t/* largest file that can be created\n\t\t\t\t\t   (bytes */\n#define RLIMIT_DATA\t2\t\t/* maximum size of data segment\n\t\t\t\t\t   (bytes) */\n#define RLIMIT_STACK\t3\t\t/* maximum size of stack segment\n\t\t\t\t\t   (bytes) */\n#define RLIMIT_CORE\t4\t\t/* largest core file that can be created\n\t\t\t\t\t   (bytes) */\n#define RLIMIT_RSS\t5\t\t/* largest resident set size (bytes) */\n#define RLIMIT_NPROC\t6\t\t/* number of processes */\n#define RLIMIT_NOFILE\t7\t\t/* number of open files */\n#define RLIMIT_MEMLOCK\t8\t\t/* locked-in-memory address space */\n#define RLIMIT_AS\t9\t\t/* address space limit */\n\n#define RLIM_NLIMITS\t10\n\nstruct rusage {\n\tstruct timeval ru_utime;\t/* total amount of user time used */\n\tstruct timeval ru_stime;\t/* total amount of system time used */\n\tlong ru_maxrss;\t\t\t/* maximum resident set size (KB) */\n\tlong ru_ixrss;\t\t\t/* amount of sharing of text segment\n\t\t\t\t\t   memory with other processes\n\t\t\t\t\t   (KB-secs) */\n\tlong ru_idrss;\t\t\t/* amount of data segment memory used\n\t\t\t\t\t   (KB-secs) */\n\tlong ru_isrss;\t\t\t/* amount of stack memory used\n\t\t\t\t\t   (KB-secs) */\n\tlong ru_minflt;\t\t\t/* number of soft page faults (i.e.\n\t\t\t\t\t   those serviced by reclaiming a page\n\t\t\t\t\t   from the list of pages awaiting\n\t\t\t\t\t   rellocation) */\n\tlong ru_majflt;\t\t\t/* number of hard page faults (i.e.\n\t\t\t\t\t   those that required I/O) */\n\tlong ru_nswap;\t\t\t/* number of times a process was swapped\n\t\t\t\t\t   out of physical memory */\n\tlong ru_inblock;\t\t/* number of input operations via the\n\t\t\t\t\t   file system. Note this and\n\t\t\t\t\t   'ru_outblock' do not include\n\t\t\t\t\t   operations with the cache */\n\tlong ru_oublock;\t\t/* number of output operations via the\n\t\t\t\t\t   file system */\n\tlong ru_msgsnd;\t\t\t/* number of IPC messages sent */\n\tlong ru_msgrcv;\t\t\t/* number of IPC messages received */\n\tlong ru_nsignals;\t\t/* number of signals delivered */\n\tlong ru_nvcsw;\t\t\t/* number of voluntary context switches,\n\t\t\t\t\t   i.e. because the process gave up the\n\t\t\t\t\t   process before it had to (usually to\n\t\t\t\t\t   wait for some resouce to be\n\t\t\t\t\t   availabe */\n\tlong ru_nivcsw;\t\t\t/* number of involuntary context\n\t\t\t\t\t   switches. i.e. a higher priority\n\t\t\t\t\t   process became runnable or the\n\t\t\t\t\t   current process used up its time\n\t\t\t\t\t   slice */\n};\n\nstruct rlimit {\n\tint rlim_cur;\t\t\t/* the current (soft) limit */\n\tint rlim_max;\t\t\t/* the maximum (hard) limit */\n};\n\n#endif /* _FIWIX_RESOURCE_H */\n"
  },
  {
    "path": "include/fiwix/sched.h",
    "content": "/*\n * fiwix/include/fiwix/sched.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_SCHED_H\n#define _FIWIX_SCHED_H\n\n#include <fiwix/process.h>\n\n#define PRIO_PROCESS\t0\n#define PRIO_PGRP\t1\n#define PRIO_USER\t2\n\n#define PROC_RUNNING\t1\n#define PROC_SLEEPING\t2\n#define PROC_ZOMBIE\t3\n#define PROC_STOPPED\t4\n#define PROC_IDLE\t5\n\n#define PROC_INTERRUPTIBLE\t1\n#define PROC_UNINTERRUPTIBLE\t2\n\n#define DEF_PRIORITY\t(20 * HZ / 100)\t/* 200ms of time slice */\n\nextern int need_resched;\n\n#define SI_LOAD_SHIFT   16\n\n/*\n * This was brougth from Linux 2.0.30 (sched.h).\n * Copyright Linus Torvalds et al.\n */\nextern unsigned int avenrun[3];\t\t/* Load averages */\n#define FSHIFT\t\t11\t\t/* nr of bits of precision */\n#define FIXED_1\t\t(1<<FSHIFT)\t/* 1.0 as fixed-point */\n#define LOAD_FREQ\t(5*HZ)\t\t/* 5 sec intervals */\n#define EXP_1\t\t1884\t\t/* 1/exp(5sec/1min) as fixed-point */\n#define EXP_5\t\t2014\t\t/* 1/exp(5sec/5min) */\n#define EXP_15\t\t2037\t\t/* 1/exp(5sec/15min) */\n\n#define CALC_LOAD(load,exp,n) \\\n\tload *= exp; \\\n\tload += n*(FIXED_1-exp); \\\n\tload >>= FSHIFT;\n/* ------------------------------------------------------------------------ */\n\n\nvoid do_sched(void);\nvoid set_tss(struct proc *);\nvoid sched_init(void);\n\n#endif /* _FIWIX_SCHED_H */\n"
  },
  {
    "path": "include/fiwix/segments.h",
    "content": "/*\n * fiwix/include/fiwix/segments.h\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_SEGMENTS_H\n#define _FIWIX_SEGMENTS_H\n\n#include <fiwix/linker.h>\n\n#define KERNEL_CS\t0x08\t/* kernel code segment */\n#define KERNEL_DS\t0x10\t/* kernel data segment */\n#define USER_CS\t\t0x18\t/* user code segment */\n#define USER_DS\t\t0x20\t/* user data segment */\n#define TSS\t\t0x28\t/* TSS segment */\n\n#define USER_PL\t\t0x03\t/* User Privilege Level 3 */\n\n/* flags for memory pages */\n#define PAGE_PRESENT\t0x001\t/* Present */\n#define PAGE_RW\t\t0x002\t/* Read/Write */\n#define PAGE_USER\t0x004\t/* User */\n#define PAGE_NOALLOC\t0x200\t/* No Page Allocated (OS managed) */\n\n#ifndef ASM_FILE\n\n#include <fiwix/types.h>\n\n#define NR_GDT_ENTRIES\t6\t/* entries in GDT descriptor */\n#define NR_IDT_ENTRIES\t256\t/* entries in IDT descriptor */\n\n/* low flags of Segment Descriptors */\n#define SD_CODE\t\t0x0A\t/* CODE Exec/Read */\n#define SD_DATA\t\t0x02\t/* DATA Read/Write */\n\n#define SD_32INTRGATE\t0x0E\t/* 32-bit Interrupt Gate (0D110) */\n#define SD_32TRAPGATE\t0x0F\t/* 32-bit Trap Gate (0D111) */\n\n#define SD_CD \t\t0x10\t/* 0 = system / 1 = code/data */\n#define SD_DPL0\t\t0x00\t/* priority level 0 (kernel) */\n#define SD_DPL3\t\t0x60\t/* priority level 3 (user) */\n#define SD_PRESENT\t0x80\t/* segment present or valid */\n\n/* high flags Segment Descriptors */\n#define SD_OPSIZE32\t0x04\t/* 32-bit code and data segments */\n#define SD_PAGE4KB\t0x08\t/* page granularity (4KB) */\n\n/* low flags of the TSS Descriptors */\n#define SD_TSSPRESENT\t0x89\t/* TSS present and not busy flag */\n\n/* EFLAGS */\n#define EF_IOPL\t\t12\t/* IOPL bit */\n\nstruct desc_r {\n\t__u16 limit;\n\t__u32 base_addr;\n} __attribute__((packed));\n\nstruct seg_desc {\n\tunsigned sd_lolimit : 16;\t/* segment limit 0-15 bits */\n\tunsigned sd_lobase  : 24;\t/* base address 0-23 bits */\n\tunsigned sd_loflags :  8;\t/* flags (P, DPL, S and TYPE) */\n\tunsigned sd_hilimit :  4;\t/* segment limit 16-19 bits */\n\tunsigned sd_hiflags :  4;\t/* flags (G, DB, 0 and AVL) */\n\tunsigned sd_hibase  :  8;\t/* base address 24-31 bits */\n} __attribute__((packed));\n\nstruct gate_desc {\n\tunsigned gd_looffset: 16;\t/* offset 0-15 bits */\n\tunsigned gd_selector: 16;\t/* segment selector */\n\tunsigned gd_flags   : 16;\t/* flags (P, DPL, TYPE, 0 and NULL) */\n\tunsigned gd_hioffset: 16;\t/* offset 16-31 bits */\n} __attribute__((packed));\n\nvoid gdt_init(void);\nvoid idt_init(void);\n\n#endif /* ! ASM_FILE */\n\n#endif /* _FIWIX_SEGMENTS_H */\n"
  },
  {
    "path": "include/fiwix/sem.h",
    "content": "/*\n * fiwix/include/fiwix/sem.h\n */\n\n#ifdef CONFIG_SYSVIPC\n\n#ifndef _FIWIX_SEM_H\n#define _FIWIX_SEM_H\n\n#include <fiwix/types.h>\n#include <fiwix/ipc.h>\n\n#define SEM_UNDO\t0x1000\t\t/* undo the operation on exit */\n\n/* semctl() command definitions */\n#define GETPID\t\t11\t\t/* get sempid */\n#define GETVAL\t\t12\t\t/* get semval */\n#define GETALL\t\t13\t\t/* get all semval's */\n#define GETNCNT\t\t14\t\t/* get semncnt */\n#define GETZCNT\t\t15\t\t/* get semzcnt */\n#define SETVAL\t\t16\t\t/* set semval */\n#define SETALL\t\t17\t\t/* set all semval's */\n\n/* system-wide limits */\n#define SEMMNI\t\t128\t\t/* number of semaphores sets */\n#define SEMMSL\t\t32\t\t/* max. number of semaphores per id */\n#define SEMMNS\t\t(SEMMNI*SEMMSL)\t/* max. number of messages in system */\n#define SEMOPM\t\t32\t\t/* max. number of ops. per semop() */\n#define SEMVMX\t\t32767\t\t/* semaphore maximum value */\n\n#define SEM_STAT\t18\n#define SEM_INFO\t19\n\nstruct semid_ds {\n\tstruct ipc_perm sem_perm;\t/* access permissions */\n\t__time_t sem_otime;\t\t/* time of the last semop() */\n\t__time_t sem_ctime;\t\t/* time of the last change */\n\tstruct sem *sem_base;\t\t/* ptr to the first semaphore in set */\n\tunsigned int unused1;\n\tunsigned int unused2;\n\tstruct sem_undo *undo;\t\t/* list of undo requests */\n\tunsigned short int sem_nsems;\t/* number of semaphores in set */\n};\n\n/* semaphore buffer for semop() */\nstruct sembuf {\n\tunsigned short int sem_num;\t/* semaphore number */\n\tshort int sem_op;\t\t/* semaphore operation */\n\tshort int sem_flg;\t\t/* operation flags */\n};\n\n/* arg for semctl() */\nunion semun {\n\tint val;\t\t\t/* value for SETVAL */\n\tstruct semid_ds *buf;\t\t/* buffer for IPC_STAT & IPC_SET */\n\tunsigned short int *array;\t/* array for GETALL & SETALL */\n\tstruct seminfo *__buf;\t\t/* buffer for IPC_INFO */\n};\n\n/* semaphore information structure */\nstruct seminfo {\n\tint semmap;\n\tint semmni;\n\tint semmns;\n\tint semmnu;\n\tint semmsl;\n\tint semopm;\n\tint semume;\n\tint semusz;\n\tint semvmx;\n\tint semaem;\n};\n\n/* one semaphore structure for each semaphore in the system */\nstruct sem {\n\tshort int semval;\t\t/* current value */\n\tshort int sempid;\t\t/* pid of last operation */\n\tshort int semncnt;\t\t/* nprocs awaiting increase in semval */\n\tshort int semzcnt;\t\t/* nprocs awaiting semval = 0 */\n};\n\n/* list of undo requests executed automatically when the process exits */\nstruct sem_undo {\n\tstruct sem_undo *proc_next;\t/* next entry on this process */\n\tstruct sem_undo *id_next;\t/* next entry on this semaphore set */\n\tint semid;\t\t\t/* semaphore set identifier */\n\tshort int semadj;\t\t/* adjustment during exit() */\n\tunsigned short int sem_num;\t/* semaphore number */\n};\n\n\nextern struct semid_ds *semset[];\nextern unsigned int num_semsets;\nextern unsigned int num_sems;\nextern unsigned int max_semid;\nextern unsigned int sem_seq;\n\nvoid sem_init(void);\nstruct semid_ds *sem_get_new_ss(void);\nvoid sem_release_ss(struct semid_ds *);\nstruct sem *sem_get_new_sma(void);\nvoid sem_release_sma(struct sem *);\nstruct sem_undo *sem_get_new_su(void);\nvoid sem_release_su(struct sem_undo *);\nvoid semexit(void);\nint sys_semop(int, struct sembuf *, int);\nint sys_semget(key_t, int, int);\nint sys_semctl(int, int, int, void *);\n\n#endif /* _FIWIX_SEM_H */\n\n#endif /* CONFIG_SYSVIPC */\n"
  },
  {
    "path": "include/fiwix/serial.h",
    "content": "/*\n * fiwix/include/fiwix/serial.h\n *\n * Copyright 2020-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_SERIAL_H\n#define _FIWIX_SERIAL_H\n\n#define SERIAL4_IRQ\t4\t/* IRQ for serial ports 1 and 3 */\n#define SERIAL3_IRQ\t3\t/* IRQ for serial ports 2 and 4 */\n\n#define NR_SERIAL\t5\t/* maximum number of serial ttys */\n#define SERIAL_MAJOR\t4\t/* major number for /dev/ttyS[n] */\n#define SERIAL_MINORS\tNR_SERIAL\n#define SERIAL_MSF\t6\t/* serial minor shift factor */\n\n/* UART registers */\n#define UART_TD\t\t0\t/* W:  Transmitter Holding Buffer */\n#define UART_RD\t\t0\t/* R:  Receiver Buffer */\n#define UART_DLL\t0\t/* RW: Divisor Latch Low Byte */\n#define UART_DLH\t1\t/* RW: Divisor Latch High Byte */\n#define UART_IER\t1\t/* RW: Interrupt Enable Register */\n#define UART_IIR\t2\t/* R:  Interrupt Identification Register */\n#define UART_FCR\t2\t/* W:  FIFO Control Register */\n#define UART_LCR\t3\t/* RW: Line Control Register */\n#define UART_MCR\t4\t/* RW: Modem Control Register */\n#define UART_LSR\t5\t/* R:  Line Status Register */\n#define UART_MSR\t6\t/* R:  Modem Status Register */\n#define UART_SR\t\t7\t/* RW: Scratch Register */\n\n/* Interrupt Enable Register */\n#define UART_IER_RDAI\t0x1\t/* enable Received Data Available Interrupt  */\n#define UART_IER_THREI\t0x2\t/* enable Transmitter Holding Register Empty Interrupt */\n#define UART_IER_RLSI\t0x4\t/* enable Receiver Line Status Interrupt */\n#define UART_IER_MSI\t0x8\t/* enable Modem Status Interrupt */\n\n/* Interrupt Identification Register */\n#define UART_IIR_NOINT\t0x01\t/* no interrupts pending */\n#define UART_IIR_MKINT\t0x06\t/* mask all interrupt flags */\n#define UART_IIR_MSI\t0x00\t/* Modem Status Interrupt */\n#define UART_IIR_THREI\t0x02\t/* Transmitter Holding Register Empty Interrupt */\n#define UART_IIR_RDAI\t0x04\t/* Received Data Available Interrupt */\n#define UART_IIR_RLSI\t0x06\t/* Receiver Line Status Interrupt */\n#define UART_IIR_FIFOTO\t0xC0\t/* FIFO TimeOut interrupt */\n#define UART_IIR_FIFO64\t0x20\t/* 64 byte FIFO enabled (16750 only) */\n#define UART_IIR_FIFO\t0x40\t/* FIFO is enabled (still needs bit #7 on) */\n#define UART_IIR_FIFOKO\t0x80\t/* FIFO is enabled, but unusable */\n\n/* FIFO Control Register */\n#define UART_FCR_FIFO\t0x07\t/* enable FIFO (clear receive and transmit) */\n#define UART_FCR_CRCVR\t0x02\t/* clear receiver */\n#define UART_FCR_CXMTR\t0x04\t/* clear transmitter */\n#define UART_FCR_DMA\t0x08\t/* DMA mode select */\n#define UART_FCR_FIFO64\t0x20\t/* enable 64 byte FIFO (16750 only) */\n#define UART_FCR_FIFO14\t0xC0\t/* set to 14 bytes 'trigger level' FIFO */\n\n/* Line Control Register */\n#define UART_LCR_WL5\t0x00\t/* word length 5 bits */\n#define UART_LCR_WL6\t0x01\t/* word length 6 bits */\n#define UART_LCR_WL7\t0x02\t/* word length 7 bits */\n#define UART_LCR_WL8\t0x03\t/* word length 8 bits */\n#define UART_LCR_2STB\t0x04\t/* 2 stop bits */\n#define UART_LCR_1STB\t0x00\t/* 1 stop bit */\n#define UART_LCR_NP\t0x00\t/* no parity */\n#define UART_LCR_OP\t0x08\t/* odd parity */\n#define UART_LCR_EP\t0x18\t/* even parity */\n#define UART_LCR_SBRK\t0x40\t/* Set Break enable */\n#define UART_LCR_DLAB\t0x80\t/* Divisor Latch Access Bit */\n\n/* Modem Control Register */\n#define UART_MCR_DTR\t0x1\t/* Data Terminal Ready */\n#define UART_MCR_RTS\t0x2\t/* Request To Send */\n#define UART_MCR_OUT2\t0x8\t/* Auxiliary Output 2 */\n\n/* Line Status Register */\n#define UART_LSR_RDA\t0x01\t/* Received Data Available */\n#define UART_LSR_OE\t0x02\t/* Overrun Error */\n#define UART_LSR_PE\t0x04\t/* Parity Error */\n#define UART_LSR_FE\t0x08\t/* Framing Error */\n#define UART_LSR_BI\t0x10\t/* Break Interrupt */\n#define UART_LSR_THRE\t0x20\t/* Transmitter Holding Register Empty */\n#define UART_LSR_EDHR\t0x40\t/* Empty Data Holding Registers TD and SH */\n#define UART_LSR_EFIFO\t0x80\t/* Error in Received FIFO */\n\n\n#define UART_FIFO_SIZE\t16\t/* 16 bytes */\n#define UART_HAS_FIFO\t0x02\t/* has FIFO working */\n#define UART_IS_8250\t0x04\t/* is a 8250 chip */\n#define UART_IS_16450\t0x08\t/* is a 16450 chip */\n#define UART_IS_16550\t0x10\t/* is a 16550 chip */\n#define UART_IS_16550A\t0x20\t/* is a 16550A chip */\n\n#define UART_ACTIVE\t0x80\n\nstruct serial {\n\tunsigned short int ioaddr;\t/* port I/O address */\n\tint iosize;\n\tchar irq;\n\tint baud;\n\tchar *name;\n\tshort int lctrl;\t/* line control flags (8N1, 7E2, ...) */\n\tint flags;\n\tstruct tty *tty;\n\tstruct serial *next;\n};\n\nint serial_open(struct tty *);\nint serial_close(struct tty *);\nint serial_ioctl(struct tty *, int, unsigned int);\nvoid serial_write(struct tty *);\nvoid irq_serial(int, struct sigcontext *);\nvoid irq_serial_bh(struct sigcontext *);\nvoid serial_init(void);\n\n#endif /* _FIWIX_SERIAL_H */\n"
  },
  {
    "path": "include/fiwix/shm.h",
    "content": "/*\n * fiwix/include/fiwix/shm.h\n */\n\n#ifdef CONFIG_SYSVIPC\n\n#ifndef _FIWIX_SHM_H\n#define _FIWIX_SHM_H\n\n#include <fiwix/types.h>\n#include <fiwix/ipc.h>\n\n#define SHM_DEST\t01000\t\t/* destroy segment on last detach */\n#define\tSHM_RDONLY\t010000\t\t/* attach a read-only segment */\n#define\tSHM_RND\t\t020000\t\t/* round attach address to SHMLBA */\n#define\tSHM_REMAP\t040000\t\t/* take-over region on attach */\n\n/* super user shmctl commands */\n#define SHM_LOCK \t11\n#define SHM_UNLOCK \t12\n\n/* system-wide limits */\n/*\n * Since the current kernel memory allocator has a granularity of page size,\n * it's not possible to go beyond 4096 pages in the array of pointers to page\n * frames (*shm_pages). Hence SHMMAX must stay to 0x1000000 (4096 * 4096).\n *\n * It will be 0x2000000 (or more) when the new kernel memory allocator be\n * implemented.\n */\n#define SHMMAX\t\t0x1000000\t/* max. segment size (in bytes) */\n\n#define SHMMIN\t\t1\t\t/* min. segment size (in bytes) */\n#define SHMMNI\t\t128\t\t/* max. number of shared segments */\n#define SHMSEG\t\tSHMMNI\t\t/* max. segments per process */\n#define SHMLBA\t\tPAGE_SIZE\t/* low boundary address (in bytes) */\n#define SHMALL\t\t524288\t\t/* max. total segments (in pages) */\n\n#define SHM_STAT \t13\n#define SHM_INFO \t14\n\n#define NUM_ATTACHES_PER_SEG\t(PAGE_SIZE / sizeof(struct vma))\n\nstruct shmid_ds {\n\tstruct ipc_perm shm_perm;\t/* access permissions */\n\t__size_t shm_segsz;\t\t/* size of segment (in bytes) */\n\t__time_t shm_atime;\t\t/* time of the last shmat() */\n\t__time_t shm_dtime;\t\t/* time of the last shmdt() */\n\t__time_t shm_ctime;\t\t/* time of the last change */\n\tunsigned short shm_cpid;\t/* pid of creator */\n\tunsigned short shm_lpid;\t/* pid of last shm operation */\n\tunsigned short shm_nattch;\t/* num. of current attaches */\n\t/* the following are for kernel only */\n\tunsigned short shm_npages;\t/* size of segment (in pages) */\n\tunsigned int *shm_pages;\t/* array of ptrs to frames -> SHMMAX */\n\tstruct vma *shm_attaches;\t/* ptr to array of attached regions */\n};\n\nstruct shminfo {\n\tint shmmax;\n\tint shmmin;\n\tint shmmni;\n\tint shmseg;\n\tint shmall;\n};\n\nstruct shm_info {\n\tint used_ids;\n\tunsigned int shm_tot;\t\t/* total allocated shm */\n\tunsigned int shm_rss;\t\t/* total resident shm */\n\tunsigned int shm_swp;\t\t/* total swapped shm */\n\tunsigned int swap_attempts;\n\tunsigned int swap_successes;\n};\n\nextern struct shmid_ds *shmseg[];\nextern unsigned int num_segs;\nextern unsigned int max_segid;\nextern unsigned int shm_seq;\nextern unsigned int shm_tot;\nextern unsigned int shm_rss;\n\nvoid shm_init(void);\nstruct shmid_ds *shm_get_new_seg(void);\nvoid shm_release_seg(struct shmid_ds *);\nvoid free_seg(int);\nstruct vma *shm_get_new_attach(struct shmid_ds *);\nvoid shm_release_attach(struct vma *);\nint shm_map_page(struct vma *, unsigned int);\nint sys_shmat(int, char *, int, unsigned int *);\nint sys_shmdt(char *);\nint sys_shmget(key_t, __size_t, int);\nint sys_shmctl(int, int, struct shmid_ds *);\n\n#endif /* _FIWIX_SHM_H */\n\n#endif /* CONFIG_SYSVIPC */\n"
  },
  {
    "path": "include/fiwix/sigcontext.h",
    "content": "/*\n * fiwix/include/fiwix/sigcontext.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_SIGCONTEXT_H\n#define _FIWIX_SIGCONTEXT_H\n\nstruct sigcontext {\n\tunsigned int gs;\n\tunsigned int fs;\n\tunsigned int es;\n\tunsigned int ds;\n\tunsigned int edi;\n\tunsigned int esi;\n\tunsigned int ebp;\n\tunsigned int esp;\n\tint ebx;\n\tint edx;\n\tint ecx;\n\tint eax;\n\tint err;\n\tunsigned int eip;\n\tunsigned int cs;\n\tunsigned int eflags;\n\tunsigned int oldesp;\n\tunsigned int oldss;\n};\n\n#endif /* _FIWIX_SIGCONTEXT_H */\n"
  },
  {
    "path": "include/fiwix/signal.h",
    "content": "/*\n * fiwix/include/fiwix/signal.h\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_SIGNAL_H\n#define _FIWIX_SIGNAL_H\n\n#define NSIG\t\t32\n\n#define SIGHUP\t\t1\t/* Hangup or Reset */\n#define SIGINT\t\t2\t/* Interrupt */\n#define SIGQUIT\t\t3\t/* Quit */\n#define SIGILL\t\t4\t/* Illegal Instruction */\n#define SIGTRAP\t\t5\t/* Trace Trap */\n#define SIGABRT\t\t6\t/* Abort Instruction */\n#define SIGIOT\t\tSIGABRT\t/* I/O Trap Instruction */\n#define SIGBUS\t\t7\t/* Bus Error */\n#define SIGFPE\t\t8\t/* Floating Point Exception */\n#define SIGKILL\t\t9\t/* Kill */\n#define SIGUSR1\t\t10\t/* User Defined #1 */\n#define SIGSEGV\t\t11\t/* Segmentation Violation */\n#define SIGUSR2\t\t12\t/* User Defined #2 */\n#define SIGPIPE\t\t13\t/* Broken Pipe */\n#define SIGALRM\t\t14\t/* Alarm Clock */\n#define SIGTERM\t\t15\t/* Software Termination */\n#define SIGSTKFLT\t16\t/* Stack Fault */\n#define SIGCHLD\t\t17\t/* Child Termination */\n#define SIGCONT\t\t18\t/* Continue */\n#define SIGSTOP\t\t19\t/* Stop */\n#define SIGTSTP\t\t20\t/* Terminal Stop */\n#define SIGTTIN\t\t21\t/* Background Read */\n#define SIGTTOU\t\t22\t/* Background Write */\n#define SIGURG\t\t23\t/* Urgent Data */\n#define SIGXCPU\t\t24\t/* CPU eXceeded */\n#define SIGXFSZ\t\t25\t/* File Size eXceeded */\n#define SIGVTALRM\t26\t/* Virtual Time Alarm */\n#define SIGPROF\t\t27\t/* Profile Alarm */\n#define SIGWINCH\t28\t/* Window Change */\n#define SIGIO\t\t29\t/* I/O Asyncronous */\n#define SIGPOLL\t\tSIGIO\n#define SIGPWR\t\t30\t/* Power Fault */\n#define SIGUNUSED\t31\n\ntypedef unsigned int __sigset_t;\ntypedef void (*__sighandler_t)(int);\n\nstruct sigaction {\n\t__sighandler_t sa_handler;\n\t__sigset_t sa_mask;\n\tint sa_flags;\n\tvoid (*sa_restorer)(void);\n};\n\n#define SIG_DFL\t\t((__sighandler_t)  0)\n#define SIG_IGN\t\t((__sighandler_t)  1)\n#define SIG_ERR\t\t((__sighandler_t) -1)\n\n/* bits in sa_flags */\n#define SA_NOCLDSTOP\t0x00000001\t/* don't send SIGCHLD when children stop */\n#define SA_NOCLDWAIT\t0x00000002\t/* don't create zombie on child death */\n#define SA_ONSTACK\t0x08000000\t/* invoke handler on alternate stack */\n#define SA_RESTART\t0x10000000\t/* automatically restart system call */\n#define SA_INTERRUPT\t0x20000000\t/* unused */\n\n/* don't automatically block signal when the handler is executing */\n#define SA_NODEFER\t0x40000000\n#define SA_NOMASK\tSA_NODEFER\n\n/* reset signal disposition to SIG_DFL before invoking handler */\n#define SA_RESETHAND\t0x80000000\n#define SA_ONESHOT\tSA_RESETHAND\n\n/* bits in the third argument to 'waitpid/wait4' */\n#define WNOHANG\t\t1\t/* don't block waiting */\n#define WUNTRACED\t2\t/* report status of stopped children */\n\n#define SIG_BLOCK\t0\t/* for blocking signals */\n#define SIG_UNBLOCK\t1\t/* for unblocking signals */\n#define SIG_SETMASK\t2\t/* for setting the signal mask */\n\n/* SIGKILL and SIGSTOP can't ever be set as blockable signals */\n#define SIG_BLOCKABLE\t(~(1 << (SIGKILL - 1)) | (1 << (SIGSTOP - 1)))\n\n#define SIG_MASK(sig)\t(~(1 << ((sig) - 1)))\n\n#define\tKERNEL\t\t1\t/* kernel is who has sent the signal */\n#define\tUSER\t\t2\t/* user is who has sent the signal */\n\nint issig(void);\nvoid psig(unsigned int);\nint kill_pid(__pid_t, __sigset_t, int);\nint kill_pgrp(__pid_t, __sigset_t, int);\n\n#endif /* _FIWIX_SIGNAL_H */\n"
  },
  {
    "path": "include/fiwix/sleep.h",
    "content": "/*\n * fiwix/include/fiwix/sleep.h\n *\n * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_SLEEP_H\n#define _FIWIX_SLEEP_H\n\n#include <fiwix/process.h>\n\n#define AREA_BH\t\t\t0x00000001\n#define AREA_CALLOUT\t\t0x00000002\n#define AREA_TTY_READ\t\t0x00000004\n#define AREA_SERIAL_READ\t0x00000008\n\nextern struct proc *proc_run_head;\n\nstruct resource {\n\tchar locked;\n\tchar wanted;\n};\n\nvoid runnable(struct proc *);\nvoid not_runnable(struct proc *, int);\nint sleep(void *, int);\nvoid wakeup(void *);\nvoid wakeup_proc(struct proc *);\n\nvoid lock_resource(struct resource *);\nvoid unlock_resource(struct resource *);\nint can_lock_area(unsigned int);\nint unlock_area(unsigned int);\n\nvoid sleep_init(void);\n\n#endif /* _FIWIX_SLEEP_H */\n"
  },
  {
    "path": "include/fiwix/socket.h",
    "content": "/*\n * fiwix/include/fiwix/socket.h\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifdef CONFIG_NET\n\n#ifndef _FIWIX_SOCKET_H\n#define _FIWIX_SOCKET_H\n\n#include <fiwix/types.h>\n\n/* supported address families (domains) */\n#define AF_UNIX\t\t1\t\t/* UNIX domain socket */\n#define AF_LOCAL\tAF_UNIX\t\t/* POSIX name for AF_UNIX */\n#define AF_INET\t\t2\t\t/* IPv4 Internet domain socket */\n\n/* protocol families */\n#define PF_UNIX\t\tAF_UNIX\n#define PF_LOCAL\tAF_LOCAL\n#define PF_INET\t\tAF_INET\n\n/* types */\n#define SOCK_STREAM\t1\n#define SOCK_DGRAM\t2\n\n/* maximum queue length specifiable by listen() */\n#define SOMAXCONN\t128\n\n/* states */\n#define SS_UNCONNECTED\t\t1\n#define SS_CONNECTING\t\t2\n#define SS_CONNECTED\t\t3\n#define SS_DISCONNECTING\t4\n\n/* flags */\n#define SO_ACCEPTCONN\t\t0x10000\n\n/* flags for send() and recv() */\n#define MSG_PEEK\t\t0x02\n#define MSG_DONTWAIT\t\t0x40\n\ntypedef unsigned short int sa_family_t;\n\n\n/* generic socket address structure */\nstruct sockaddr {\n\tsa_family_t sa_family;\t\t/* address family: AF_xxx */\n\tchar sa_data[14];\t\t/* protocol specific address */\n};\n\n/* UNIX domain socket address structure */\nstruct sockaddr_un {\n        sa_family_t sun_family;\t\t/* AF_UNIX */\n        char sun_path[108];\t\t/* socket filename */\n};\n\n#endif /* _FIWIX_SOCKET_H */\n\n#endif /* CONFIG_NET */\n"
  },
  {
    "path": "include/fiwix/stat.h",
    "content": "#ifndef _FIWIX_STAT_H\n#define _FIWIX_STAT_H\n\n#include <fiwix/statbuf.h>\n\n/* Encoding of the file mode.  These are the standard Unix values,\n   but POSIX.1 does not specify what values should be used.  */\n\n#define S_IFMT\t\t0170000\t\t/* Type of file mask */\n\n/* File types.  */\n#define S_IFIFO\t\t0010000\t\t/* Named pipe (fifo) */\n#define S_IFCHR\t\t0020000\t\t/* Character special */\n#define S_IFDIR\t\t0040000\t\t/* Directory */\n#define S_IFBLK\t\t0060000\t\t/* Block special */\n#define S_IFREG\t\t0100000\t\t/* Regular */\n#define S_IFLNK\t\t0120000\t\t/* Symbolic link */\n#define S_IFSOCK \t0140000\t\t/* Socket */\n\n/* Protection bits.  */\n#define S_IXUSR\t\t00100\t\t/* USER   --x------ */\n#define S_IWUSR\t\t00200\t\t/* USER   -w------- */\n#define S_IRUSR\t\t00400\t\t/* USER   r-------- */\n#define S_IRWXU\t\t00700\t\t/* USER   rwx------ */\n\n#define S_IXGRP\t\t00010\t\t/* GROUP  -----x--- */\n#define S_IWGRP\t\t00020\t\t/* GROUP  ----w---- */\n#define S_IRGRP\t\t00040\t\t/* GROUP  ---r----- */\n#define S_IRWXG\t\t00070\t\t/* GROUP  ---rwx--- */\n\n#define S_IXOTH\t\t00001\t\t/* OTHERS --------x */\n#define S_IWOTH\t\t00002\t\t/* OTHERS -------w- */\n#define S_IROTH\t\t00004\t\t/* OTHERS ------r-- */\n#define S_IRWXO\t\t00007\t\t/* OTHERS ------rwx */\n\n#define S_ISUID\t\t0004000\t\t/* set user id on execution */\n#define S_ISGID\t\t0002000\t\t/* set group id on execution */\n#define S_ISVTX\t\t0001000\t\t/* sticky bit */\n\n#define S_IREAD\t\tS_IRUSR\t\t/* Read by owner.  */\n#define S_IWRITE\tS_IWUSR\t\t/* Write by owner.  */\n#define S_IEXEC\t\tS_IXUSR\t\t/* Execute by owner.  */\n\n#define S_ISFIFO(m)\t(((m) & S_IFMT) == S_IFIFO)\n#define S_ISCHR(m)\t(((m) & S_IFMT) == S_IFCHR)\n#define S_ISDIR(m)\t(((m) & S_IFMT) == S_IFDIR)\n#define S_ISBLK(m)\t(((m) & S_IFMT) == S_IFBLK)\n#define S_ISREG(m)\t(((m) & S_IFMT) == S_IFREG)\n#define S_ISLNK(m)\t(((m) & S_IFMT) == S_IFLNK)\n#define S_ISSOCK(m) \t(((m) & S_IFMT) == S_IFSOCK)\n\n#define TO_READ\t\t4\t/* test for read permission */\n#define TO_WRITE\t2\t/* test for write permission */\n#define TO_EXEC\t\t1\t/* test for execute permission */\n\n#endif /* _FIWIX_STAT_H */\n"
  },
  {
    "path": "include/fiwix/statbuf.h",
    "content": "/*\n * fiwix/include/fiwix/statbuf.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_STATBUF_H\n#define _FIWIX_STATBUF_H\n\nstruct old_stat {\n\t__dev_t st_dev;\n\tunsigned short int st_ino;\n\t__mode_t st_mode;\n\t__nlink_t st_nlink;\n\t__uid_t st_uid;\n\t__gid_t st_gid;\n\t__dev_t st_rdev;\n\tunsigned int st_size;\n\t__time_t st_atime;\n\t__time_t st_mtime;\n\t__time_t st_ctime;\n};\n\nstruct new_stat {\n\t__dev_t st_dev;\n\tunsigned short int __pad1;\n\t__ino_t st_ino;\n\t__mode_t st_mode;\n\t__nlink_t st_nlink;\n\t__uid_t st_uid;\n\t__gid_t st_gid;\n\t__dev_t st_rdev;\n\tunsigned short int __pad2;\n\t__off_t st_size;\n\t__blk_t st_blksize;\n\t__blk_t st_blocks;\n\t__time_t st_atime;\n\tunsigned int __unused1;\n\t__time_t st_mtime;\n\tunsigned int __unused2;\n\t__time_t st_ctime;\n\tunsigned int __unused3;\n\tunsigned int __unused4;\n\tunsigned int __unused5;\n};\n\nstruct stat64 {\n\tunsigned long long int st_dev;\n\tint __st_dev_padding;\n\tint __st_ino_truncated;\n\tunsigned int st_mode;\n\tunsigned int st_nlink;\n\tunsigned int st_uid;\n\tunsigned int st_gid;\n\tunsigned long long int st_rdev;\n\tint __st_rdev_padding;\n\tlong long int st_size;\n\tint st_blksize;\n\tlong long int st_blocks;\n\tint st_atime;\n\tint st_atime_nsec;\n\tint st_mtime;\n\tint st_mtime_nsec;\n\tint st_ctime;\n\tint st_ctime_nsec;\n\tunsigned long long int st_ino;\n};\n\n#endif /* _FIWIX_STATBUF_H */\n"
  },
  {
    "path": "include/fiwix/statfs.h",
    "content": "/*\n * fiwix/include/fiwix/statfs.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_STATFS_H\n#define _FIWIX_STATFS_H\n\ntypedef struct {\n\tint val[2];\n} fsid_t;\n\nstruct statfs {\n\tint f_type;\n\tint f_bsize;\n\tint f_blocks;\n\tint f_bfree;\n\tint f_bavail;\n\tint f_files;\n\tint f_ffree;\n\tfsid_t f_fsid;\n\tint f_namelen;\n\tint f_spare[6];\n};\n\n#endif /* _FIWIX_STATFS_H */\n"
  },
  {
    "path": "include/fiwix/stdarg.h",
    "content": "/* \nCopyright (C) 1988 Free Software Foundation\n\nThis file is part of GNU CC.\n\nGNU CC is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY.  No author or distributor\naccepts responsibility to anyone for the consequences of using it\nor for whether it serves any particular purpose or works at all,\nunless he says so in writing.  Refer to the GNU CC General Public\nLicense for full details.\n\nEveryone is granted permission to copy, modify and redistribute\nGNU CC, but only under the conditions described in the\nGNU CC General Public License.   A copy of this license is\nsupposed to have been given to you along with GNU CC so you\ncan know your rights and responsibilities.  It should be in a\nfile named COPYING.  Among other things, the copyright notice\nand this notice must be preserved on all copies.  \n*/\n\n#ifndef __stdarg_h\n#define __stdarg_h\n\ntypedef char *va_list;\n\n/* Amount of space required in an argument list for an arg of type TYPE.\n   TYPE may alternatively be an expression whose type is used.  */\n\n#define __va_rounded_size(TYPE)  \\\n  (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))\n\n#define va_start(AP, LASTARG) \\\n (AP = ((char *) &(LASTARG) + __va_rounded_size(LASTARG)))\n\nextern void va_end (va_list);\n#define va_end(AP) /* Nothing */\n\n#define va_arg(AP, TYPE) (AP += __va_rounded_size (TYPE), \\\n  *((TYPE *) (AP - __va_rounded_size (TYPE))))\n\n#endif /* __stdarg_h */\n"
  },
  {
    "path": "include/fiwix/stddef.h",
    "content": "/*\n * fiwix/include/fiwix/stddef.h\n *\n * Copyright 2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _INCLUDE_STDDEF_H\n#define _INCLUDE_STDDEF_H\n\n#define offsetof(st, m)\t((__size_t)&(((st *)0)->m))\n\n#endif /* _INCLUDE_STDDEF_H */\n"
  },
  {
    "path": "include/fiwix/stdio.h",
    "content": "/*\n * fiwix/include/fiwix/stdio.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _INCLUDE_STDIO_H\n#define _INCLUDE_STDIO_H\n\n#include <fiwix/tty.h>\n\nvoid flush_log_buf(struct tty *);\nvoid printk(const char *, ...);\nint sprintk(char *, const char *, ...);\nint snprintk(char *, unsigned int, const char *, ...);\n\n#endif /* _INCLUDE_STDIO_H */\n"
  },
  {
    "path": "include/fiwix/string.h",
    "content": "/*\n * fiwix/include/fiwix/string.h\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _INCLUDE_STRING_H\n#define _INCLUDE_STRING_H\n\n#include <fiwix/types.h>\n\n#ifndef NULL\n#define NULL\t((void *)0)\n#endif\n\n#define MIN(a,b)\t((a) < (b) ? (a) : (b))\n#define MAX(a,b)\t((a) > (b) ? (a) : (b))\n\nvoid swap_asc_word(char *, int);\nint strcmp(const char *, const char *);\nint strncmp(const char *, const char *, __ssize_t);\nchar *strcpy(char *, const char *);\nvoid strncpy(char *, const char *, int);\nchar *strcat(char *, const char *);\nchar *strncat(char *, const char *, __ssize_t);\nint strlen(const char *);\nchar *strchr(const char *, int);\nchar *strrchr(const char *, int);\nint strtol(const char *, char **, int);\nchar *get_basename(const char *);\nchar *remove_trailing_slash(char *);\nint is_dir(const char *);\nint atoi(const char *);\nvoid memcpy_b(void *, const void *, unsigned int);\nvoid memcpy_w(void *, const void *, unsigned int);\nvoid memcpy_l(void *, const void *, unsigned int);\nvoid memset_b(void *, unsigned char, unsigned int);\nvoid memset_w(void *, unsigned short int, unsigned int);\nvoid memset_l(void *, unsigned int, unsigned int);\nint memcmp(const void *, const void *, unsigned int);\nvoid *memmove(void *, void const *, int);\n\n#endif /* _INCLUDE_STRING_H */\n"
  },
  {
    "path": "include/fiwix/syscalls.h",
    "content": "/*\n * fiwix/include/fiwix/syscalls.h\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_SYSCALLS_H\n#define _FIWIX_SYSCALLS_H\n\n#include <fiwix/types.h>\n#include <fiwix/system.h>\n#include <fiwix/time.h>\n#include <fiwix/times.h>\n#include <fiwix/timeb.h>\n#include <fiwix/utime.h>\n#include <fiwix/statbuf.h>\n#include <fiwix/ustat.h>\n#include <fiwix/signal.h>\n#include <fiwix/utsname.h>\n#include <fiwix/resource.h>\n#include <fiwix/dirent.h>\n#include <fiwix/statfs.h>\n#include <fiwix/sigcontext.h>\n#include <fiwix/mman.h>\n#include <fiwix/ipc.h>\n\n#define NR_SYSCALLS\t(sizeof(syscall_table) / sizeof(unsigned int))\n\n#ifdef CONFIG_SYSCALL_6TH_ARG\nint do_syscall(unsigned int, int, int, int, int, int, int, struct sigcontext);\n#else\nint do_syscall(unsigned int, int, int, int, int, int, struct sigcontext);\n#endif /* CONFIG_SYSCALL_6TH_ARG */\n\nint sys_exit(int);\nvoid do_exit(int);\n#ifdef CONFIG_SYSCALL_6TH_ARG\nint sys_fork(int, int, int, int, int, int, struct sigcontext *);\n#else\nint sys_fork(int, int, int, int, int, struct sigcontext *);\n#endif /* CONFIG_SYSCALL_6TH_ARG */\nint sys_read(unsigned int, char *, int);\nint sys_write(unsigned int, const char *, int);\nint sys_open(const char *, int, __mode_t);\nint sys_close(unsigned int);\nint sys_waitpid(__pid_t, int *, int);\nint sys_creat(const char *, __mode_t);\nint sys_link(const char *, const char *);\nint sys_unlink(const char *);\n#ifdef CONFIG_SYSCALL_6TH_ARG\nint sys_execve(const char *, char **, char **, int, int, int, struct sigcontext *);\n#else\nint sys_execve(const char *, char **, char **, int, int, struct sigcontext *);\n#endif /* CONFIG_SYSCALL_6TH_ARG */\nint sys_chdir(const char *);\nint sys_time(__time_t *);\nint sys_mknod(const char *, __mode_t, __dev_t);\nint sys_chmod(const char *, __mode_t);\nint sys_lchown(const char *, __uid_t, __gid_t);\nint sys_stat(const char *, struct old_stat *);\nint sys_lseek(unsigned int, __off_t, unsigned int);\nint sys_getpid(void);\nint sys_mount(const char *, const char *, const char *, unsigned int, const void *);\nint sys_umount(const char *);\nint sys_setuid(__uid_t);\nint sys_getuid(void);\nint sys_stime(__time_t *);\nint sys_alarm(unsigned int);\nint sys_fstat(unsigned int, struct old_stat *);\nint sys_pause(void);\nint sys_utime(const char *, struct utimbuf *);\nint sys_access(const char *, __mode_t);\nint sys_ftime(struct timeb *);\nvoid sys_sync(void);\nint sys_kill(__pid_t, __sigset_t);\nint sys_rename(const char *, const char *);\nint sys_mkdir(const char *, __mode_t);\nint sys_rmdir(const char *);\nint sys_dup(unsigned int);\nint sys_pipe(int *);\nint sys_times(struct tms *);\nint sys_brk(unsigned int);\nint sys_setgid(__gid_t);\nint sys_getgid(void);\nunsigned int sys_signal(__sigset_t, void(*sighandler)(int));\nint sys_geteuid(void);\nint sys_getegid(void);\nint sys_umount2(const char *, int);\nint sys_ioctl(unsigned int, int, unsigned int);\nint sys_fcntl(unsigned int, int, unsigned int);\nint sys_setpgid(__pid_t, __pid_t);\nint sys_olduname(struct oldold_utsname *);\nint sys_umask(__mode_t);\nint sys_chroot(const char *);\nint sys_ustat(__dev_t, struct ustat *);\nint sys_dup2(unsigned int, unsigned int);\nint sys_getppid(void);\nint sys_getpgrp(void);\nint sys_setsid(void);\nint sys_sigaction(__sigset_t, const struct sigaction *, struct sigaction *);\nint sys_sgetmask(void);\nint sys_ssetmask(int);\nint sys_setreuid(__uid_t, __uid_t);\nint sys_setregid(__gid_t, __gid_t);\nint sys_sigsuspend(__sigset_t *);\nint sys_sigpending(__sigset_t *);\nint sys_sethostname(const char *, int);\nint sys_setrlimit(int, const struct rlimit *);\nint sys_getrlimit(int, struct rlimit *);\nint sys_getrusage(int, struct rusage *);\nint sys_gettimeofday(struct timeval *, struct timezone *);\nint sys_settimeofday(const struct timeval *, const struct timezone *);\nint sys_getgroups(__ssize_t, __gid_t *);\nint sys_setgroups(__ssize_t, const __gid_t *);\nint old_select(unsigned int *);\nint sys_symlink(const char *, const char *);\nint sys_lstat(const char *, struct old_stat *);\nint sys_readlink(const char *, char *, __size_t);\nint sys_reboot(int, int, int);\nint old_mmap(struct mmap *);\nint sys_munmap(unsigned int, __size_t);\nint sys_truncate(const char *, __off_t);\nint sys_ftruncate(unsigned int, __off_t);\nint sys_fchmod(unsigned int, __mode_t);\nint sys_fchown(unsigned int, __uid_t, __gid_t);\nint sys_statfs(const char *, struct statfs *);\nint sys_fstatfs(unsigned int, struct statfs *);\nint sys_ioperm(unsigned int, unsigned int, int);\nint sys_socketcall(int, unsigned int *);\nint sys_syslog(int, char *, int);\nint sys_setitimer(int, const struct itimerval *, struct itimerval *);\nint sys_getitimer(int, struct itimerval *);\nint sys_newstat(const char *, struct new_stat *);\nint sys_newlstat(const char *, struct new_stat *);\nint sys_newfstat(unsigned int, struct new_stat *);\nint sys_uname(struct old_utsname *);\n#ifdef CONFIG_SYSCALL_6TH_ARG\nint sys_iopl(int, int, int, int, int, int, struct sigcontext *);\n#else\nint sys_iopl(int, int, int, int, int, struct sigcontext *);\n#endif /* CONFIG_SYSCALL_6TH_ARG */\nint sys_wait4(__pid_t, int *, int, struct rusage *);\nint sys_sysinfo(struct sysinfo *);\n#ifdef CONFIG_SYSVIPC\nint sys_ipc(unsigned int, struct sysvipc_args *);\n#endif /* CONFIG_SYSVIPC */\nint sys_fsync(unsigned int);\n#ifdef CONFIG_SYSCALL_6TH_ARG\nint sys_sigreturn(unsigned int, int, int, int, int, int, struct sigcontext *);\n#else\nint sys_sigreturn(unsigned int, int, int, int, int, struct sigcontext *);\n#endif /* CONFIG_SYSCALL_6TH_ARG */\nint sys_setdomainname(const char *, int);\nint sys_newuname(struct new_utsname *);\nint sys_mprotect(unsigned int, __size_t, int);\nint sys_sigprocmask(int, const __sigset_t *, __sigset_t *);\nint sys_getpgid(__pid_t);\nint sys_fchdir(unsigned int);\nint sys_personality(unsigned int);\nint sys_setfsuid(__uid_t);\nint sys_setfsgid(__gid_t);\nint sys_llseek(unsigned int, unsigned int, unsigned int, __loff_t *, unsigned int);\nint sys_getdents(unsigned int, struct dirent *, unsigned int);\nint sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);\nint sys_flock(unsigned int, int);\nint sys_readv(int, struct iovec *, int);\nint sys_writev(int, struct iovec *, int);\nint sys_getsid(__pid_t);\nint sys_fdatasync(int);\nint sys_nanosleep(const struct timespec *, struct timespec *);\nint sys_chown(const char *, __uid_t, __gid_t);\nint sys_getcwd(char *, __size_t);\n#ifdef CONFIG_MMAP2\nint sys_mmap2(unsigned int, unsigned int, unsigned int, unsigned int, int, unsigned int);\n#endif /* CONFIG_MMAP2 */\nint sys_truncate64(const char *, __loff_t);\nint sys_ftruncate64(unsigned int, __loff_t);\nint sys_stat64(const char *, struct stat64 *);\nint sys_lstat64(const char *, struct stat64 *);\nint sys_fstat64(unsigned int, struct stat64 *);\nint sys_chown32(const char *, unsigned int, unsigned int);\nint sys_getdents64(unsigned int, struct dirent64 *, unsigned int);\nint sys_fcntl64(unsigned int, int, unsigned int);\nint sys_utimes(const char *, struct timeval times[2]);\n\n#endif /* _FIWIX_SYSCALLS_H */\n"
  },
  {
    "path": "include/fiwix/sysconsole.h",
    "content": "/*\n * fiwix/include/fiwix/sysconsole.h\n *\n * Copyright 2024, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_SYSCONSOLE_H\n#define _FIWIX_SYSCONSOLE_H\n\n#include <fiwix/config.h>\n#include <fiwix/types.h>\n#include <fiwix/tty.h>\n\nstruct sysconsole {\n\t__dev_t dev;\n\tstruct tty *tty;\n};\n\nextern struct sysconsole sysconsole_table[NR_SYSCONSOLES];\n\nint add_sysconsoledev(__dev_t);\nvoid register_console(struct tty *);\nvoid sysconsole_init(void);\n\n#endif /* _FIWIX_SYSCONSOLE_H */\n"
  },
  {
    "path": "include/fiwix/syslog.h",
    "content": "/*\n * fiwix/include/fiwix/syslog.h\n *\n * Copyright 2025, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_SYSLOG_H\n#define _FIWIX_SYSLOG_H\n\n#define SYSLOG_CLOSE\t\t0\t/* close the log */\n#define SYSLOG_OPEN\t\t1\t/* open the log */\n#define SYSLOG_READ\t\t2\t/* read the log */\n#define SYSLOG_READ_ALL\t\t3\t/* read all messages */\n#define SYSLOG_READ_CLEAR\t4\t/* read and clear all messages */\n#define SYSLOG_CLEAR\t\t5\t/* clear the buffer */\n#define SYSLOG_CONSOLE_OFF\t6\t/* disable printk to console */\n#define SYSLOG_CONSOLE_ON\t7\t/* enable printk to console */\n#define SYSLOG_CONSOLE_LEVEL\t8\t/* set printk level to console */\n#define SYSLOG_SIZE_UNREAD\t9\t/* get the number of unread chars */\n#define SYSLOG_SIZE_BUFFER\t10\t/* get the size of the buffer */\n\n#define DEFAULT_MESSAGE_LOGLEVEL 6\t/* KERN_INFO */\n#define DEFAULT_CONSOLE_LOGLEVEL 7 \t/* KERN_DEBUG */\n\n#define LOG_BUF_LEN\t4096\n\nextern char log_buf[LOG_BUF_LEN];\t/* circular buffer */\nextern unsigned int log_read, log_write, log_size, log_new_chars;\nextern int console_loglevel;\n\n#endif /* _FIWIX_SYSLOG_H */\n"
  },
  {
    "path": "include/fiwix/sysrq.h",
    "content": "/*\n * fiwix/include/fiwix/sysrq.h\n *\n * Copyright 2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_SYSRQ_H\n#define _FIWIX_SYSRQ_H\n\n/* the key combination consists of Alt+SysRq and another key, defined below */\n#define SYSRQ_STACK\t0x00000001\t/* 'l' -> stack backtrace */\n#define SYSRQ_MEMORY\t0x00000002\t/* 'm' -> memory information */\n#define SYSRQ_TASKS\t0x00000004\t/* 't' -> task list */\n#define SYSRQ_UNDEF\t0x80000000\t/* Undefined operation */\n\nvoid sysrq(int);\n\n#endif /* _FIWIX_SYSRQ_H */\n"
  },
  {
    "path": "include/fiwix/system.h",
    "content": "/*\n * fiwix/include/fiwix/system.h\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_SYSTEM_H\n#define _FIWIX_SYSTEM_H\n\n#define UTS_SYSNAME\t\"Fiwix\"\n#define UTS_NODENAME\t\"(none)\"\n#define UTS_RELEASE\t\"1.7.0\"\n#define UTS_DOMAINNAME\t\"(none)\"\n\nstruct sysinfo {\n\tint uptime;\t\t\t/* seconds since boot */\n\tunsigned int loads[3];\t\t/* load average (1, 5 and 15 minutes) */\n\tunsigned int totalram;\t\t/* total usable main memory size */\n\tunsigned int freeram;\t\t/* available memory size */\n\tunsigned int sharedram;\t\t/* amount of shared memory */\n\tunsigned int bufferram;\t\t/* amount of memory used by buffers */\n\tunsigned int totalswap;\t\t/* total swap space size */\n\tunsigned int freeswap;\t\t/* available swap space */\n\tunsigned short int procs;\t/* number of current processes */\n\tchar _f[22];\t\t\t/* pads structure to 64 bytes */\n};\n\n\n#ifdef CUSTOM_SYSTEM_H\n#include <fiwix/custom_system.h>\n#endif\n\n#endif /* _FIWIX_SYSTEM_H */\n"
  },
  {
    "path": "include/fiwix/termbits.h",
    "content": "/*\n * fiwix/include/fiwix/termbits.h\n *\n */\n\n#ifndef _FIWIX_TERMBITS_H\n#define _FIWIX_TERMBITS_H\n\n/* These definitions match those used by the 4.4 BSD kernel.\n   If the operating system has termios system calls or ioctls that\n   correctly implement the POSIX.1 behavior, there should be a\n   system-dependent version of this file that defines `struct termios',\n   `tcflag_t', `cc_t', `speed_t' and the `TC*' constants appropriately.  */\n\n/* Type of terminal control flag masks.  */\ntypedef unsigned int tcflag_t;\n\n/* Type of control characters.  */\ntypedef unsigned char cc_t;\n\n/* Type of baud rate specifiers.  */\ntypedef int speed_t;\n\n/* c_iflag bits */\n#define IGNBRK\t0000001\t\t/* Ignore break condition */\n#define BRKINT\t0000002\t\t/* Signal interrupt on break */\n#define IGNPAR\t0000004\t\t/* Ignore characters with parity errors */\n#define PARMRK\t0000010\t\t/* Mark parity and framing errors */\n#define INPCK\t0000020\t\t/* Enable input parity check */\n#define ISTRIP\t0000040\t\t/* Strip 8th bit off characters */\n#define INLCR\t0000100\t\t/* Map NL to CR on input */\n#define IGNCR\t0000200\t\t/* Ignore CR */\n#define ICRNL\t0000400\t\t/* Map CR to NL on input */\n#define IUCLC\t0001000\t\t/* Convert to lowercase */\n#define IXON\t0002000\t\t/* Enable start/stop output control */\n#define IXANY\t0004000\t\t/* Any character will restart after stop */\n#define IXOFF\t0010000\t\t/* Enable start/stop input control */\n#define IMAXBEL\t0020000\t\t/* Ring bell when input queue is full */\n\n/* c_oflag bits */\n#define OPOST\t0000001\t\t/* Perform output processing */\n#define OLCUC\t0000002\n#define ONLCR\t0000004\t\t/* Map NL to CR-NL on output */\n#define OCRNL\t0000010\n#define ONOCR\t0000020\n#define ONLRET\t0000040\n#define OFILL\t0000100\n#define OFDEL\t0000200\n#define NLDLY\t0000400\n#define   NL0\t0000000\n#define   NL1\t0000400\n#define CRDLY\t0003000\n#define   CR0\t0000000\n#define   CR1\t0001000\n#define   CR2\t0002000\n#define   CR3\t0003000\n#define TABDLY\t0014000\n#define   TAB0\t0000000\n#define   TAB1\t0004000\n#define   TAB2\t0010000\n#define   TAB3\t0014000\n#define   XTABS\t0014000\n#define BSDLY\t0020000\n#define   BS0\t0000000\n#define   BS1\t0020000\n#define VTDLY\t0040000\n#define   VT0\t0000000\n#define   VT1\t0040000\n#define FFDLY\t0100000\n#define   FF0\t0000000\n#define   FF1\t0100000\n\n/* c_cflag bit meaning */\n#define CBAUD\t0010017\n#define  B0\t0000000\t\t/* hang up */\n#define  B50\t0000001\t\t/* 50 baud */\n#define  B75\t0000002\t\t/* 75 baud */\n#define  B110\t0000003\t\t/* 110 baud */\n#define  B134\t0000004\t\t/* 134 baud */\n#define  B150\t0000005\t\t/* 150 baud */\n#define  B200\t0000006\t\t/* 200 baud */\n#define  B300\t0000007\t\t/* 300 baud */\n#define  B600\t0000010\t\t/* 600 baud */\n#define  B1200\t0000011\t\t/* 1200 baud */\n#define  B1800\t0000012\t\t/* 1800 baud */\n#define  B2400\t0000013\t\t/* 2400 baud */\n#define  B4800\t0000014\t\t/* 4800 baud */\n#define  B9600\t0000015\t\t/* 9600 baud */\n#define  B19200\t0000016\t\t/* 19200 baud */\n#define  B38400\t0000017\t\t/* 38400 baud */\n#define EXTA B19200\n#define EXTB B38400\n#define CSIZE\t0000060\t\t/* Number of bits per byte (mask) */\n#define   CS5\t0000000\t\t/* 5 bits per byte */\n#define   CS6\t0000020\t\t/* 6 bits per byte */\n#define   CS7\t0000040\t\t/* 7 bits per byte */\n#define   CS8\t0000060\t\t/* 8 bits per byte */\n#define CSTOPB\t0000100\t\t/* Two stop bits instead of one */\n#define CREAD\t0000200\t\t/* Enable receiver */\n#define PARENB\t0000400\t\t/* Parity enable */\n#define PARODD\t0001000\t\t/* Odd parity instead of even */\n#define HUPCL\t0002000\t\t/* Hang up on last close */\n#define CLOCAL\t0004000\t\t/* Ignore modem status lines */\n#define CBAUDEX 0010000\n#define    B57600 0010001\n#define   B115200 0010002\n#define   B230400 0010003\n#define   B460800 0010004\n#define   B500000 0010005\n#define   B576000 0010006\n#define   B921600 0010007\n#define  B1000000 0010010\n#define  B1152000 0010011\n#define  B1500000 0010012\n#define  B2000000 0010013\n#define  B2500000 0010014\n#define  B3000000 0010015\n#define  B3500000 0010016\n#define  B4000000 0010017\n#define CIBAUD\t  002003600000\t/* input baud rate (not used) */\n#define CMSPAR\t  010000000000\t\t/* mark or space (stick) parity */\n#define CRTSCTS\t  020000000000\t\t/* flow control */\n\n/* c_lflag bits */\n#define ISIG\t0000001\t\t/* Enable signals */\n#define ICANON\t0000002\t\t/* Do erase and kill processing */\n#define XCASE\t0000004\n#define ECHO\t0000010\t\t/* Enable echo */\n#define ECHOE\t0000020\t\t/* Visual erase for ERASE */\n#define ECHOK\t0000040\t\t/* Echo NL after KILL */\n#define ECHONL\t0000100\t\t/* Echo NL even if echo is OFF */\n#define NOFLSH\t0000200\t\t/* Disable flush after interrupt */\n#define TOSTOP\t0000400\t\t/* Send SIGTTOU for background output */\n#define ECHOCTL\t0001000\t\t/* Echo control characters as ^X */\n#define ECHOPRT\t0002000\t\t/* Hardcopy visual erase */\n#define ECHOKE\t0004000\t\t/* Visual erase for KILL */\n#define FLUSHO\t0010000\t\t/* Output being flushed (state) */\n#define PENDIN\t0040000\t\t/* Retype pending input (state) */\n#define IEXTEN\t0100000\t\t/* Enable DISCARD and LNEXT */\n\n/* c_cc characters */\n#define VINTR 0\t\t\t/* Interrupt character [ISIG] */\n#define VQUIT 1\t\t\t/* Quit character [ISIG] */\n#define VERASE 2\t\t/* Erase character [ICANON] */\n#define VKILL 3\t\t\t/* Kill-line character [ICANON] */\n#define VEOF 4\t\t\t/* End-of-file character [ICANON] */\n#define VTIME 5\t\t\t/* Time-out value (1/10 secs) [!ICANON] */\n#define VMIN 6\t\t\t/* Minimum # of bytes read at once [!ICANON] */\n#define VSWTC 7\n#define VSTART 8\t\t/* Start (X-ON) character [IXON, IXOFF] */\n#define VSTOP 9\t\t\t/* Stop (X-OFF) character [IXON, IXOFF] */\n#define VSUSP 10\t\t/* Suspend character [ISIG] */\n#define VEOL 11\t\t\t/* End-of-line character [ICANON] */\n#define VREPRINT 12\t\t/* Reprint-line character [ICANON] */\n#define VDISCARD 13\t\t/* Discard character [IEXTEN] */\n#define VWERASE 14\t\t/* Word-erase character [ICANON] */\n#define VLNEXT 15\t\t/* Literal-next character [IEXTEN] */\n#define VEOL2 16\t\t/* Second EOL character [ICANON] */\n\n/* Values for the ACTION argument to `tcflow'.  */\n#define TCOOFF\t\t0\t/* Suspend output */\n#define TCOON\t\t1\t/* Restart suspended output */\n#define TCIOFF\t\t2\t/* Send a STOP character */\n#define TCION\t\t3\t/* Send a START character */\n\n/* Values for the QUEUE_SELECTOR argument to `tcflush'.  */\n#define TCIFLUSH\t0\t/* Discard data received but not yet read */\n#define TCOFLUSH\t1\t/* Discard data written but not yet sent */\n#define TCIOFLUSH\t2\t/* Discard all pending data */\n\n/* Values for the OPTIONAL_ACTIONS argument to `tcsetattr'.  */\n#define TCSANOW\t\t0\t/* Change immediately */\n#define TCSADRAIN\t1\t/* Change when pending output is written */\n#define TCSAFLUSH\t2\t/* Flush pending input before changing */\n\n#endif /* _FIWIX_TERMBITS_H */\n"
  },
  {
    "path": "include/fiwix/termios.h",
    "content": "/*\n * fiwix/include/fiwix/termios.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_TERMIOS_H\n#define _FIWIX_TERMIOS_H\n\n#include <fiwix/termbits.h>\n\nstruct winsize {\n\tunsigned short int ws_row;\n\tunsigned short int ws_col;\n\tunsigned short int ws_xpixel;\n\tunsigned short int ws_ypixel;\n};\n\n\n#define NCC\t8\n\n/* old terminal control structure */\nstruct termio {\n\tunsigned short int c_iflag;\t/* input mode flags */\n\tunsigned short int c_oflag; \t/* output mode flags */\n\tunsigned short int c_cflag;\t/* control mode flags */\n\tunsigned short int c_lflag;\t/* local mode flags */\n\tunsigned char c_line;\t\t/* line discipline */\n\tunsigned char c_cc[NCC];\t/* control characters */\n};\n\n\n#define NCCS 19\n\n/* new terminal control structure */\nstruct termios {\n\ttcflag_t c_iflag;\t/* input mode flags */\n\ttcflag_t c_oflag;\t/* output mode flags */\n\ttcflag_t c_cflag;\t/* control mode flags */\n\ttcflag_t c_lflag;\t/* local mode flags */\n\tcc_t c_line;\t\t/* line discipline */\n\tcc_t c_cc[NCCS];\t/* control characters */\n};\n\n#endif /* _FIWIX_TERMIOS_H */\n"
  },
  {
    "path": "include/fiwix/time.h",
    "content": "/*\n * fiwix/include/fiwix/time.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_TIME_H\n#define _FIWIX_TIME_H\n\n#define ITIMER_REAL\t0\n#define ITIMER_VIRTUAL\t1\n#define ITIMER_PROF\t2\n\nstruct timespec {\n\tint tv_sec;\t\t/* seconds since 00:00:00, 1 Jan 1970 UTC */\n\tint tv_nsec;\t\t/* nanoseconds (1000000000ns = 1sec) */\n};\n\nstruct timeval {\n\tint tv_sec;\t\t/* seconds since 00:00:00, 1 Jan 1970 UTC */\n\tint tv_usec;\t\t/* microseconds\t(1000000us = 1sec) */\n};\n\nstruct timezone {\n\tint tz_minuteswest;\t/* minutes west of GMT */\n\tint tz_dsttime;\t\t/* type of DST correction */\n};\n\nstruct itimerval {\n\tstruct timeval it_interval;\n\tstruct timeval it_value;\n};\n\nstruct tm {\n\tint tm_sec;\t/* seconds */\n\tint tm_min;\t/* minutes */\n\tint tm_hour;\t/* hour */\n\tint tm_mday;\t/* day of the month */\n\tint tm_month;\t/* month */\n\tint tm_year;\t/* year */\n\tint tm_wday;\t/* day of the week */\n\tint tm_yday;\t/* day of the year */\n\tint tm_isdst;\t/* daylight savings flag */\n};\n\nunsigned int tv2ticks(const struct timeval *);\nvoid ticks2tv(int, struct timeval *);\nint setitimer(int, const struct itimerval *, struct itimerval *);\nunsigned int mktime(struct tm *);\n\n#endif /* _FIWIX_TIME_H */\n"
  },
  {
    "path": "include/fiwix/timeb.h",
    "content": "/*\n * fiwix/include/fiwix/timeb.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_TIMEB_H\n#define _FIWIX_TIMEB_H\n\nstruct timeb {\n\tunsigned int time;\t\t/* in seconds since Epoch */\n\tunsigned short int millitm;\t/* additional milliseconds */\n\tshort int timezone;\t\t/* minutes west of GMT */\n\tshort int dstflag;\t\t/* nonzero if DST is used */\n};\n\n#endif /* _FIWIX_TIMEB_H */\n"
  },
  {
    "path": "include/fiwix/timer.h",
    "content": "/*\n * fiwix/include/fiwix/timer.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_TIMER_H\n#define _FIWIX_TIMER_H\n\n#include <fiwix/types.h>\n#include <fiwix/sigcontext.h>\n\n#define TIMER_IRQ\t0\n#define HZ\t\t100\t/* kernel's Hertz rate (100 = 10ms) */\n#define TICK\t\t(1000000 / HZ)\n\n#define UNIX_EPOCH\t1970\n\n#define LEAP_YEAR(y)\t((y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0))\n#define DAYS_PER_YEAR(y)\t((LEAP_YEAR(y)) ? 366 : 365)\n\n#define SECS_PER_MIN\t60\n#define SECS_PER_HOUR\t(SECS_PER_MIN * 60)\n#define SECS_PER_DAY\t(SECS_PER_HOUR * 24)\n\n#define INFINITE_WAIT\t0xFFFFFFFF\n\nstruct callout {\n\tint expires;\n\tvoid (*fn)(unsigned int);\n\tunsigned int arg;\n\tstruct callout *next;\n};\n\nstruct callout_req {\n\tvoid (*fn)(unsigned int);\n\tunsigned int arg;\n};\n\nvoid add_callout(struct callout_req *, unsigned int);\nvoid del_callout(struct callout_req *);\nvoid irq_timer(int, struct sigcontext *);\nvoid irq_timer_bh(struct sigcontext *);\nvoid do_callouts_bh(struct sigcontext *);\nvoid get_system_time(void);\nvoid set_system_time(__time_t);\nint gettimeoffset(void);\nvoid timer_init(void);\n\n#endif /* _FIWIX_TIMER_H */\n"
  },
  {
    "path": "include/fiwix/times.h",
    "content": "/*\n * fiwix/include/fiwix/times.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_TIMES_H\n#define _FIWIX_TIMES_H\n\nstruct tms {\n\t__clock_t tms_utime;\t/* CPU time spent in user-mode */\n\t__clock_t tms_stime;\t/* CPU time spent in kernel-mode */\n\t__clock_t tms_cutime;\t/* (tms_utime + tms_cutime) of children */\n\t__clock_t tms_cstime;\t/* (tms_stime + tms_cstime) of children */\n};\n\n#endif /* _FIWIX_TIMES_H */\n"
  },
  {
    "path": "include/fiwix/traps.h",
    "content": "/*\n * fiwix/include/fiwix/traps.h\n *\n * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_TRAPS_H\n#define _FIWIX_TRAPS_H\n\n#include <fiwix/sigcontext.h>\n\n#define NR_EXCEPTIONS\t32\n\nstruct traps {\n\tchar *name;\n\tvoid (*handler)(unsigned int, struct sigcontext *);\n\tchar errcode;\n};\n\nvoid do_divide_error(unsigned int, struct sigcontext *);\nvoid do_debug(unsigned int, struct sigcontext *);\nvoid do_nmi_interrupt(unsigned int, struct sigcontext *);\nvoid do_breakpoint(unsigned int, struct sigcontext *);\nvoid do_overflow(unsigned int, struct sigcontext *);\nvoid do_bound(unsigned int, struct sigcontext *);\nvoid do_invalid_opcode(unsigned int, struct sigcontext *);\nvoid do_no_math_coprocessor(unsigned int, struct sigcontext *);\nvoid do_double_fault(unsigned int, struct sigcontext *);\nvoid do_coprocessor_segment_overrun(unsigned int, struct sigcontext *);\nvoid do_invalid_tss(unsigned int, struct sigcontext *);\nvoid do_segment_not_present(unsigned int, struct sigcontext *);\nvoid do_stack_segment_fault(unsigned int, struct sigcontext *);\nvoid do_general_protection(unsigned int, struct sigcontext *);\nvoid do_page_fault(unsigned int, struct sigcontext *);\nvoid do_reserved(unsigned int, struct sigcontext *);\nvoid do_floating_point_error(unsigned int, struct sigcontext *);\nvoid do_alignment_check(unsigned int, struct sigcontext *);\nvoid do_machine_check(unsigned int, struct sigcontext *);\nvoid do_simd_fault(unsigned int, struct sigcontext *);\n\nvoid trap_handler(unsigned int, struct sigcontext);\n\nconst char * elf_lookup_symbol(unsigned int addr);\nvoid stack_backtrace(void);\nint dump_registers(unsigned int, struct sigcontext *);\n\n#endif /* _FIWIX_TRAPS_H */\n"
  },
  {
    "path": "include/fiwix/tty.h",
    "content": "/*\n * fiwix/include/fiwix/tty.h\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_TTY_H\n#define _FIWIX_TTY_H\n\n#include <fiwix/termios.h>\n#include <fiwix/fs.h>\n#include <fiwix/fd.h>\n#include <fiwix/charq.h>\n#include <fiwix/console.h>\n#include <fiwix/serial.h>\n\n#define TAB_SIZE\t8\n#define MAX_TAB_COLS\t132\t/* maximum number of tab stops */\n\n/* tty flags */\n#define TTY_HAS_LNEXT\t\t0x01\n#define TTY_OTHER_CLOSED\t0x02\n#define TTY_PTY_LOCK\t\t0x04\n\nstruct kbd_state {\n\tchar mode;\n};\n\nstruct tty {\n\t__dev_t dev;\n\tstruct clist read_q;\n\tstruct clist cooked_q;\n\tstruct clist write_q;\n\tshort int count;\n\tstruct termios termios;\n\tstruct winsize winsize;\n\tstruct kbd_state kbd;\n\t__pid_t pid, pgid, sid;\n\tvoid *driver_data;\n\tint canon_data;\n\tchar tab_stop[132];\n\tint column;\n\tint flags;\n\tstruct tty *link;\n\tstruct tty *next;\n\n\t/* tty driver operations */\n\tvoid (*stop)(struct tty *);\n\tvoid (*start)(struct tty *);\n\tvoid (*deltab)(struct tty *);\n\tvoid (*reset)(struct tty *);\n\tvoid (*input)(struct tty *);\n\tvoid (*output)(struct tty *);\n\tint (*open)(struct tty *);\n\tint (*close)(struct tty *);\n\tint (*ioctl)(struct tty *, struct fd *, int cmd, unsigned int);\n\tvoid (*set_termios)(struct tty *);\n};\nextern struct tty *tty_table;\n\nvoid tty_reset(struct tty *);\nstruct tty *register_tty(__dev_t);\nvoid unregister_tty(struct tty *);\nstruct tty *get_tty(__dev_t);\nvoid disassociate_ctty(struct tty *);\nvoid termios_reset(struct tty *);\nvoid tty_deltab(struct tty *);\nvoid do_cook(struct tty *);\nint tty_open(struct inode *, struct fd *);\nint tty_close(struct inode *, struct fd *);\nint tty_read(struct inode *, struct fd *, char *, __size_t);\nint tty_write(struct inode *, struct fd *, const char *, __size_t);\nint tty_ioctl(struct inode *, struct fd *, int cmd, unsigned int);\n__loff_t tty_llseek(struct inode *, __loff_t);\nint tty_select(struct inode *, struct fd *, int);\nvoid tty_init(void);\n\nint vt_ioctl(struct tty *, int, unsigned int);\n\n#endif /* _FIWIX_TTY_H */\n"
  },
  {
    "path": "include/fiwix/types.h",
    "content": "/*\n * fiwix/include/fiwix/types.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_TYPES_H\n#define _FIWIX_TYPES_H\n\ntypedef __signed__ char __s8;\ntypedef unsigned char __u8;\ntypedef __signed__ short int __s16;\ntypedef unsigned short int __u16;\ntypedef __signed__ int __s32;\ntypedef unsigned int __u32;\ntypedef __signed__ long long int __s64;\ntypedef unsigned long long int __u64;\n\ntypedef __u16 __uid_t;\ntypedef __u16 __gid_t;\ntypedef __u32 __ino_t;\ntypedef __u64 __ino64_t;\ntypedef __u16 __mode_t;\ntypedef __u16 __nlink_t;\ntypedef __u32 __off_t;\ntypedef __s32 __pid_t;\ntypedef __s32 __ssize_t;\ntypedef __u32 __size_t;\ntypedef __u32 __clock_t;\ntypedef __u32 __time_t;\ntypedef __u16 __dev_t;\ntypedef __u16 __key_t;\ntypedef __s32 __blk_t;\t\t/* must be signed in order to return error */\ntypedef __s32 __daddr_t;\ntypedef __s64 __loff_t;\t\t/* must be signed in order to return error */\n\n/* number of descriptors that can fit in an 'fd_set' */\n/* WARNING: this value must be the same as in the C Library */\n#define __FD_SETSIZE\t64\n\n#define __NFDBITS\t(sizeof(unsigned int) * 8)\n#define __FDELT(d)\t((d) / __NFDBITS)\n#define __FDMASK(d)\t(1 << ((d) % __NFDBITS))\n\n/* define the fd_set structure for select() */\ntypedef struct {\n\tunsigned int fds_bits[__FD_SETSIZE / __NFDBITS];\n} fd_set;\n\n/* define the iovec structure for readv/writev */\nstruct iovec {\n\tvoid  *iov_base;\n\t__size_t iov_len;\n};\n\n#define __FD_ZERO(set)\t\t(memset_b((void *) (set), 0, sizeof(fd_set)))\n#define __FD_SET(d, set)\t((set)->fds_bits[__FDELT(d)] |= __FDMASK(d))\n#define __FD_CLR(d, set)\t((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))\n#define __FD_ISSET(d, set)\t((set)->fds_bits[__FDELT(d)] & __FDMASK(d))\n\n#define __bswap32(x) \\\n\t((unsigned int)(\t\t\t\\\n\t\t((x & 0xFF) << 24) |\t\t\\\n\t\t(((x >> 8) & 0xFF) << 16) |\t\\\n\t\t(((x >> 16) & 0xFF) << 8) |\t\\\n\t\t((x >> 24) & 0xFF)\t\t\\\n\t))\n\n#endif /* _FIWIX_TYPES_H */\n"
  },
  {
    "path": "include/fiwix/unistd.h",
    "content": "/*\n * fiwix/include/fiwix/unistd.h\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_UNISTD_H\n#define _FIWIX_UNISTD_H\n\n/*\n * This is intended to be pure Linux 2.0 i386 ABI, plus some system calls from\n * Linux 2.2 and Linux 2.4.\n */\n\n/* #define SYS_setup */\n#define SYS_exit\t\t1\n#define SYS_fork\t\t2\n#define SYS_read\t\t3\n#define SYS_write\t\t4\n#define SYS_open\t\t5\n#define SYS_close\t\t6\n#define SYS_waitpid\t\t7\n#define SYS_creat\t\t8\n#define SYS_link\t\t9\n#define SYS_unlink\t\t10\n#define SYS_execve\t\t11\n#define SYS_chdir\t\t12\n#define SYS_time\t\t13\n#define SYS_mknod\t\t14\n#define SYS_chmod\t\t15\n#define SYS_lchown\t\t16\n#define SYS_break\t\t17\t\t/* -ENOSYS */\n#define SYS_oldstat\t\t18\n#define SYS_lseek\t\t19\n#define SYS_getpid\t\t20\n#define SYS_mount\t\t21\n#define SYS_umount\t\t22\n#define SYS_setuid\t\t23\n#define SYS_getuid\t\t24\n#define SYS_stime\t\t25\n/* #define SYS_ptrace */\n#define SYS_alarm\t\t27\n#define SYS_oldfstat\t\t28\n#define SYS_pause\t\t29\n#define SYS_utime\t\t30\n#define SYS_stty\t\t31\t\t/* -ENOSYS */\n#define SYS_gtty\t\t32\t\t/* -ENOSYS */\n#define SYS_access\t\t33\n/* #define SYS_nice */\n#define SYS_ftime\t\t35\n#define SYS_sync\t\t36\n#define SYS_kill\t\t37\n#define SYS_rename\t\t38\n#define SYS_mkdir\t\t39\n#define SYS_rmdir\t\t40\n#define SYS_dup\t\t\t41\n#define SYS_pipe\t\t42\n#define SYS_times\t\t43\n#define SYS_prof\t\t44\t\t/* -ENOSYS */\n#define SYS_brk\t\t\t45\n#define SYS_setgid\t\t46\n#define SYS_getgid\t\t47\n#define SYS_signal\t\t48\n#define SYS_geteuid\t\t49\n#define SYS_getegid\t\t50\n/* #define SYS_acct */\n#define SYS_umount2\t\t52\t/* (from Linux 2.2) it was sys_phys() */\n#define SYS_lock\t\t53\t\t/* -ENOSYS */\n#define SYS_ioctl\t\t54\n#define SYS_fcntl\t\t55\n#define SYS_mpx\t\t\t56\t\t/* -ENOSYS */\n#define SYS_setpgid\t\t57\n#define SYS_ulimit\t\t58\t\t/* -ENOSYS */\n#define SYS_olduname\t\t59\n#define SYS_umask\t\t60\n#define SYS_chroot\t\t61\n#define SYS_ustat\t\t62\n#define SYS_dup2\t\t63\n#define SYS_getppid\t\t64\n#define SYS_getpgrp\t\t65\n#define SYS_setsid\t\t66\n#define SYS_sigaction\t\t67\n#define SYS_sgetmask\t\t68\n#define SYS_ssetmask\t\t69\n#define SYS_setreuid\t\t70\n#define SYS_setregid\t\t71\n#define SYS_sigsuspend\t\t72\n#define SYS_sigpending\t\t73\n#define SYS_sethostname\t\t74\n#define SYS_setrlimit\t\t75\n#define SYS_getrlimit\t\t76\n#define SYS_getrusage\t\t77\n#define SYS_gettimeofday\t78\n#define SYS_settimeofday\t79\n#define SYS_getgroups\t\t80\n#define SYS_setgroups\t\t81\n#define SYS_oldselect\t\t82\n#define SYS_symlink\t\t83\n#define SYS_oldlstat\t\t84\n#define SYS_readlink\t\t85\n/* #define SYS_uselib */\n/* #define SYS_swapon */\n#define SYS_reboot\t\t88\n/* #define SYS_oldreaddir */\n#define SYS_old_mmap\t\t90\n#define SYS_munmap\t\t91\n#define SYS_truncate\t\t92\n#define SYS_ftruncate\t\t93\n#define SYS_fchmod\t\t94\n#define SYS_fchown\t\t95\n/* #define SYS_getpriority */\n/* #define SYS_setpriority */\n/* #define SYS_profil */\n#define SYS_statfs\t\t99\n#define SYS_fstatfs\t\t100\n#define SYS_ioperm\t\t101\n#define SYS_socketcall \t\t102\n#define SYS_syslog\t\t103\n#define SYS_setitimer\t\t104\n#define SYS_getitimer\t\t105\n#define SYS_newstat\t\t106\n#define SYS_newlstat\t\t107\n#define SYS_newfstat\t\t108\n#define SYS_uname\t\t109\n#define SYS_iopl\t\t110\n/* #define SYS_vhangup */\n/* #define SYS_idle\t\t112\t\t -ENOSYS */\n/* #define SYS_vm86old */\n#define SYS_wait4\t\t114\n/* #define SYS_swapoff */\n#define SYS_sysinfo\t\t116\n#define SYS_ipc\t\t\t117\n#define SYS_fsync\t\t118\n#define SYS_sigreturn\t\t119\n/* #define SYS_clone */\n#define SYS_setdomainname\t121\n#define SYS_newuname\t\t122\n/* #define SYS_modify_ldt */\n/* #define SYS_adjtimex */\n#define SYS_mprotect \t\t125\n#define SYS_sigprocmask\t\t126\n/* #define SYS_create_module */\n/* #define SYS_init_module */\n/* #define SYS_delete_module */\n/* #define SYS_get_kernel_syms */\n/* #define SYS_quotactl */\n#define SYS_getpgid \t\t132\n#define SYS_fchdir\t\t133\n/* #define SYS_bdflush */\n/* #define SYS_sysfs */\n#define SYS_personality\t\t136\n/* #define afs_syscall */\n#define SYS_setfsuid\t\t138\n#define SYS_setfsgid\t\t139\n#define SYS_llseek\t\t140\n#define SYS_getdents\t\t141\n#define SYS_select\t\t142\n#define SYS_flock\t\t143\n/* #define SYS_msync */\n#define SYS_readv\t\t145\n#define SYS_writev\t\t146\n#define SYS_getsid\t\t147\n#define SYS_fdatasync\t\t148\n/* #define SYS_sysctl */\n/* #define SYS_mlock */\n/* #define SYS_munlock */\n/* #define SYS_mlockall */\n/* #define SYS_munlockall */\n/* #define SYS_sched_setparam */\n/* #define SYS_sched_getparam */\n/* #define SYS_sched_setscheduler */\n/* #define SYS_sched_getscheduler */\n/* #define SYS_sched_yield */\n/* #define SYS_sched_get_priority_max */\n/* #define SYS_sched_get_priority_min */\n/* #define SYS_sched_rr_get_interval */\n#define SYS_nanosleep\t\t162\n/* #define SYS_mremap */\n\n/* extra system calls from Linux 2.2 */\n/* #define SYS_setresuid */\n/* #define SYS_getresuid */\n/* #define SYS_ni_syscall */\n/* #define SYS_query_module */\n/* #define SYS_poll */\n/* #define SYS_nfsservctl */\n/* #define SYS_setresgid */\n/* #define SYS_getresgid */\n/* #define SYS_prctl */\n/* #define SYS_rt_sigreturn_wrapper */\n/* #define SYS_rt_sigaction */\n/* #define SYS_rt_sigprocmask */\n/* #define SYS_rt_sigpending */\n/* #define SYS_rt_sigtimedwait */\n/* #define SYS_rt_sigqueueinfo */\n/* #define SYS_rt_sigsuspend_wrapper */\n/* #define SYS_pread */\n/* #define SYS_pwrite */\n#define SYS_chown\t\t182\n#define SYS_getcwd\t\t183\n/* #define SYS_capget */\n/* #define SYS_capset */\n/* #define SYS_sigaltstack_wrapper */\n/* #define SYS_sendfile */\n/* #define SYS_ni_syscall */\n/* #define SYS_ni_syscall */\n#define SYS_vfork\t\t190\n\n/* extra system calls from Linux 2.4 */\n/* #define SYS_ugetrlimit */\n#define SYS_mmap2\t\t192\n#define SYS_truncate64\t\t193\n#define SYS_ftruncate64\t\t194\n#define SYS_stat64\t\t195\n#define SYS_lstat64\t\t196\n#define SYS_fstat64\t\t197\n\n#define SYS_chown32\t\t212\n\n#define SYS_getdents64\t\t220\n#define SYS_fcntl64\t\t221\n\n#define SYS_utimes\t\t271\n\n#endif /* _FIWIX_UNISTD_H */\n"
  },
  {
    "path": "include/fiwix/ustat.h",
    "content": "/*\n * fiwix/include/fiwix/ustat.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_USTAT_H\n#define _FIWIX_USTAT_H\n\n#include <fiwix/types.h>\n\nstruct ustat {\n\t__daddr_t f_tfree;\t/* total free blocks */\n\t__ino_t f_tinode;\t/* number of free inodes */\n\tchar f_fname;\t\t/* filesystem name */\n\tchar f_fpack;\t\t/* filesystem pack name */\n};\n\n#endif /* _FIWIX_USTAT_H */\n"
  },
  {
    "path": "include/fiwix/utime.h",
    "content": "/*\n * fiwix/include/fiwix/utime.h\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_UTIME_H\n#define _FIWIX_UTIME_H\n\n#include <fiwix/types.h>\n\nstruct utimbuf {\n\t__time_t actime;\t/* access time */\n\t__time_t modtime;\t/* modification time */\n};\n\n#endif /* _FIWIX_UTIME_H */\n"
  },
  {
    "path": "include/fiwix/utsname.h",
    "content": "/* Copyright (C) 1991, 1992, 1994, 1996 Free Software Foundation, Inc.\n   This file is part of the GNU C Library.\n\n   The GNU C Library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public License as\n   published by the Free Software Foundation; either version 2 of the\n   License, or (at your option) any later version.\n\n   The GNU C Library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with the GNU C Library; see the file COPYING.LIB.  If not,\n   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,\n   Boston, MA 02111-1307, USA.  */\n\n/*\n * fiwix/include/fiwix/utsname.h\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_UTSNAME_H\n#define _FIWIX_UTSNAME_H\n\n#define _OLD_UTSNAME_LENGTH\t8\n#define _UTSNAME_LENGTH\t\t64\n\n#ifndef _UTSNAME_NODENAME_LENGTH\n#define _UTSNAME_NODENAME_LENGTH _UTSNAME_LENGTH\n#endif\n\n/* very old structure describing the system and machine */\nstruct oldold_utsname\n{\n    char sysname[_OLD_UTSNAME_LENGTH + 1];\n    char nodename[_OLD_UTSNAME_LENGTH + 1];\n    char release[_OLD_UTSNAME_LENGTH + 1];\n    char version[_OLD_UTSNAME_LENGTH + 1];\n    char machine[_OLD_UTSNAME_LENGTH + 1];\n};\n\n/* old structure describing the system and machine */\nstruct old_utsname\n{\n    char sysname[_UTSNAME_LENGTH + 1];\n    char nodename[_UTSNAME_NODENAME_LENGTH + 1];\n    char release[_UTSNAME_LENGTH + 1];\n    char version[_UTSNAME_LENGTH + 1];\n    char machine[_UTSNAME_LENGTH + 1];\n};\n\n/* new structure describing the system and machine */\nstruct new_utsname\n{\n    /* name of this implementation of the operating system */\n    char sysname[_UTSNAME_LENGTH + 1];\n\n    /* name of this node on the network */\n    char nodename[_UTSNAME_NODENAME_LENGTH + 1];\n\n    /* current release level of this implementation */\n    char release[_UTSNAME_LENGTH + 1];\n    /* current version level of this release */\n    char version[_UTSNAME_LENGTH + 1];\n\n    /* name of the hardware type on which the system is running */\n    char machine[_UTSNAME_LENGTH + 1];\n    char domainname[_UTSNAME_LENGTH + 1];\n};\n\nextern struct new_utsname sys_utsname;\nextern char UTS_MACHINE[_UTSNAME_LENGTH + 1];\n\n#endif /* _FIWIX_UTSNAME_H */\n"
  },
  {
    "path": "include/fiwix/version.h",
    "content": "#define UTS_VERSION \"Sat Nov 15 08:10:29 UTC 2025\"\n"
  },
  {
    "path": "include/fiwix/vgacon.h",
    "content": "/*\n * fiwix/include/fiwix/vgacon.h\n *\n * Copyright 2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_VGACON_H\n#define _FIWIX_VGACON_H\n\n#include <fiwix/console.h>\n\n#define MONO_ADDR\t\t0xB0000L\n#define COLOR_ADDR\t\t0xB8000L\n\n#define MONO_6845_ADDR\t\t0x3B4\t/* i/o address (+1 for data register) */\n#define COLOR_6845_ADDR\t\t0x3D4\t/* i/o address (+1 for data register) */\n\n#define ATTR_CONTROLLER\t\t0x3C0\t/* attribute controller registrer */\n#define ATTR_CONTROLLER_PAS\t0x20\t/* palette address source */\n#define INPUT_STAT1\t\t0x3DA\t/* input status #1 register */\n\n#define CRT_INDEX\t\t0\n#define CRT_DATA\t\t1\n#define CRT_CURSOR_STR\t\t0xA\n#define CRT_CURSOR_END\t\t0xB\n#define CRT_START_ADDR_HI\t0xC\n#define CRT_START_ADDR_LO\t0xD\n#define CRT_CURSOR_POS_HI\t0xE\n#define CRT_CURSOR_POS_LO\t0xF\n\n#define CURSOR_MASK\t\t0x1F\n#define CURSOR_DISABLE\t\t0x20\n\nvoid vgacon_put_char(struct vconsole *, unsigned char);\nvoid vgacon_insert_char(struct vconsole *);\nvoid vgacon_delete_char(struct vconsole *);\nvoid vgacon_update_curpos(struct vconsole *);\nvoid vgacon_show_cursor(struct vconsole *, int);\nvoid vgacon_get_curpos(struct vconsole *);\nvoid vgacon_write_screen(struct vconsole *, int, int, short int);\nvoid vgacon_blank_screen(struct vconsole *);\nvoid vgacon_scroll_screen(struct vconsole *, int, int);\nvoid vgacon_restore_screen(struct vconsole *);\nvoid vgacon_screen_on(struct vconsole *);\nvoid vgacon_screen_off(unsigned int);\nvoid vgacon_buf_scroll(struct vconsole *, int);\nvoid vgacon_cursor_blink(unsigned int);\nvoid vgacon_init(void);\n\n#endif /* _FIWIX_VGACON_H */\n"
  },
  {
    "path": "include/fiwix/video.h",
    "content": "/*\n * fiwix/include/fiwix/video.h\n *\n * Copyright 2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifndef _FIWIX_VIDEO_H\n#define _FIWIX_VIDEO_H\n\nvoid video_init(void);\n\n#endif /* _FIWIX_VIDEO_H */\n"
  },
  {
    "path": "include/fiwix/vt.h",
    "content": "#ifndef VT_H\n#define VT_H\n\n/* prefix 0x56 is 'V', to avoid collision with termios and kd */\n\n#define VT_OPENQRY\t0x5600\t/* find available vt */\n\nstruct vt_mode {\n\tchar mode;\t\t/* vt mode */\n\tchar waitv;\t\t/* if set, hang on writes if not active */\n\tshort int relsig;\t/* signal to raise on release req */\n\tshort int acqsig;\t/* signal to raise on acquisition */\n\tshort int frsig;\t/* unused (set to 0) */\n};\n#define VT_GETMODE\t0x5601\t/* get mode of active vt */\n#define VT_SETMODE\t0x5602\t/* set mode of active vt */\n#define VT_AUTO\t\t0x00\t/* auto vt switching */\n#define VT_PROCESS\t0x01\t/* process controls switching */\n#define VT_ACKACQ\t0x02\t/* acknowledge switch */\n\nstruct vt_stat {\n\tunsigned short int v_active;\t/* active vt */\n\tunsigned short int v_signal;\t/* signal to send */\n\tunsigned short int v_state;\t/* vt bitmask */\n};\n#define VT_GETSTATE\t0x5603\t/* get global vt state info */\n#define VT_SENDSIG\t0x5604\t/* signal to send to bitmask of vts */\n\n#define VT_RELDISP\t0x5605\t/* release display */\n\n#define VT_ACTIVATE\t0x5606\t/* make vt active */\n#define VT_WAITACTIVE\t0x5607\t/* wait for vt active */\n#define VT_DISALLOCATE\t0x5608  /* free memory associated to vt */\n\nstruct vt_sizes {\n\tunsigned short int v_rows;\t/* number of rows */\n\tunsigned short int v_cols;\t/* number of columns */\n\tunsigned short int v_scrollsize;/* number of lines of scrollback */\n};\n#define VT_RESIZE\t0x5609\t\t/* set kernel's idea of screensize */\n\nstruct vt_consize {\n\tunsigned short int v_rows;\t/* number of rows */\n\tunsigned short int v_cols;\t/* number of columns */\n\tunsigned short int v_vlin;\t/* number of pixel rows on screen */\n\tunsigned short int v_clin;\t/* number of pixel rows per character */\n\tunsigned short int v_vcol;\t/* number of pixel columns on screen */\n\tunsigned short int v_ccol;\t/* number of pixel columns per character */\n};\n#define VT_RESIZEX      0x560A  /* set kernel's idea of screensize + more */\n#define VT_LOCKSWITCH   0x560B  /* disallow vt switching */\n#define VT_UNLOCKSWITCH 0x560C  /* allow vt switching */\n\n#endif /* VT_H */\n"
  },
  {
    "path": "kernel/Makefile",
    "content": "# fiwix/kernel/Makefile\n#\n# Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n# Distributed under the terms of the Fiwix License.\n#\n\n.S.o:\n\t$(CC) $(CONFFLAGS) -traditional -I$(INCLUDE) -c -o $@ $<\n.c.o:\n\t$(CC) $(CFLAGS) -c -o $@ $<\n\nOBJS = boot.o core386.o main.o init.o gdt.o idt.o kexec.o syscalls.o pic.o \\\n       pit.o irq.o traps.o cpu.o cmos.o timer.o sched.o sleep.o signal.o \\\n       process.o multiboot.o\n\nall:\t$(OBJS)\n\nclean:\n\trm -f *.o\n\n"
  },
  {
    "path": "kernel/boot.S",
    "content": "/*\n * fiwix/kernel/boot.S\n *\n * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#define ASM_FILE\t1\n\n#include <fiwix/segments.h>\n#include <fiwix/multiboot1.h>\n\n#define MULTIBOOT_HEADER_FLAGS\tMULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO\n\n/* flags for CR0 (control register) */\n#define CR0_MP\t0x00000002\t/* bit 01 -> enable monitor coprocessor */\n#define CR0_NE\t0x00000020\t/* bit 05 -> enable native x87 FPU mode */\n#define CR0_WP\t0x00010000\t/* bit 16 -> enable write protect (for CoW) */\n#define CR0_AM\t0x00040000\t/* bit 18 -> enable alignment checking */\n#define CR0_PG\t0x80000000\t/* bit 31 -> enable paging */\n\n#ifdef __TINYC__\n.data\n#else\n.section .setup, \"a\"\t\t/* \"a\" attribute means Allocatable section */\n#endif\n\n.align 4\ntmp_gdtr:\n\t.word ((3 * 8) - 1)\ntmp_gdta:\n\t.long tmp_gdt\n\n.align 4\ntmp_gdt:\n\t/* NULL DESCRIPTOR */\n\t.word\t0x0000\n\t.word\t0x0000\n\t.word\t0x0000\n\t.word\t0x0000\n\n\t/* KERNEL CODE */\n\t.word\t0xFFFF\t\t/* segment limit 15-00 */\n\t.word\t0x0000\t\t/* base address 15-00 */\n\t.byte\t0x00\t\t/* base address 23-16 */\n\t.byte\t0x9A\t\t/* P=1 DPL=00 S=1 TYPE=1010 (exec/read) */\n\t.byte\t0xCF\t\t/* G=1 DB=1 0=0 AVL=0 SEGLIM=1111 */\n\t.byte\tGDT_BASE >> 24\t/* base address 31-24 */\n\n\t/* KERNEL DATA */\n\t.word\t0xFFFF\t\t/* segment limit 15-00 */\n\t.word\t0x0000\t\t/* base address 15-00 */\n\t.byte\t0x00\t\t/* base address 23-16 */\n\t.byte\t0x92\t\t/* P=1 DPL=00 S=1 TYPE=0010 (read/write) */\n\t.byte\t0xCF\t\t/* G=1 DB=1 0=0 AVL=0 SEGLIM=1111 */\n\t.byte\tGDT_BASE >> 24\t/* base address 31-24 */\n\n\n#ifdef __TINYC__\n.text\n#endif\n\n.align 4\nmultiboot_header:\t\t\t/* multiboot header */\n\t.long\tMULTIBOOT_HEADER_MAGIC\t/* magic */\n\t.long\tMULTIBOOT_HEADER_FLAGS\t/* flags */\n\t/* checksum */\n\t.long\t-(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)\n\n\t/* not used */\n\t.long\t0\t\t\t/* header_addr */\n\t.long\t0\t\t\t/* load_addr */\n\t.long\t0\t\t\t/* load_end_addr */\n\t.long\t0\t\t\t/* bss_end_addr */\n\t.long\t0\t\t\t/* entry_addr */\n\n\t/* valid only with GRUB2 */\n\t.long\t0\t\t\t/* mode_type */\n\t.long\t0\t\t\t/* width */\n\t.long\t0\t\t\t/* height */\n\t.long\t0\t\t\t/* depth */\n\n/*\n * We use the CX register in order to keep intact the values in AX and BX\n * registers, since they are holding the Multiboot values 'magic' and 'info'\n * respectively.\n */\n.align 4\n.globl _start; _start:\n\tcli\n#ifdef __TINYC__\n\tmovl\t$tmp_gdt, %esi\n\tsubl\t$PAGE_OFFSET, %esi\n\tmovl\t$tmp_gdta, %edi\n\tsubl\t$PAGE_OFFSET, %edi\n\tmovl\t%esi, (%edi)\n\tmovl\t$tmp_gdtr, %esi\n\tsubl\t$PAGE_OFFSET, %esi\n\tlgdt\t(%esi)\t\t\t/* load GDTR with the temporary GDT */\n#else\n\tlgdt\ttmp_gdtr\t\t/* load GDTR with the temporary GDT */\n#endif\n\tmovw\t$KERNEL_DS, %cx\n\tmovw\t%cx, %ds\n\tmovw\t%cx, %es\n\tmovw\t%cx, %fs\n\tmovw\t%cx, %gs\n\tmovw\t%cx, %ss\n\tljmp\t$KERNEL_CS, $setup_kernel\n\n.text\n\n.align 4\n.globl setup_kernel; setup_kernel:\n\tmovl\t$PAGE_OFFSET + 0x10000, %esp\t/* default stack address */\n\tpushl\t$0\t\t\t/* reset EFLAGS */\n\tpopf\n\n\tpushl\t%ebx\t\t\t/* save Multiboot info structure */\n\tpushl\t%eax\t\t\t/* save Multiboot magic value */\n\tcall\tsetup_tmp_pgdir\t\t/* setup a temporary page directory */\n\tmovl\t%eax, %cr3\n\n\tmovl\t%cr0, %eax\n\tandl\t$0x00000011, %eax\t/* disable all, preserve ET & PE (GRUB) */\n\torl\t$CR0_PG, %eax\t\t/* enable PG */\n\torl\t$CR0_AM, %eax\t\t/* enable AM */\n\torl\t$CR0_WP, %eax\t\t/* enable WP */\n\torl\t$CR0_NE, %eax\t\t/* enable NE */\n\torl\t$CR0_MP, %eax\t\t/* enable MP */\n\tmovl\t%eax, %cr0\n\n\tcall\tbss_init\t\t/* initialize BSS segment */\n\tcall\tgdt_init\t\t/* setup and load the definitive GDT */\n\tcall\tget_last_boot_addr\n\tpopl\t%ecx\t\t\t/* restore Multiboot magic value */\n\tpopl\t%ebx\t\t\t/* restore Multiboot info structure */\n\n\tpushl\t%eax\t\t\t/* save the last boot address */\n\tpushl\t%ebx\t\t\t/* save Multiboot info structure */\n\tpushl\t%ecx\t\t\t/* save Multiboot magic value */\n\tcall\tstart_kernel\n\n\t/* not reached */\n\tjmp\tcpu_idle\n\n"
  },
  {
    "path": "kernel/cmos.c",
    "content": "/*\n * fiwix/kernel/cmos.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/cmos.h>\n\nint cmos_update_in_progress(void)\n{\n\treturn(cmos_read(CMOS_STATA) & CMOS_STATA_UIP);\n}\n\nunsigned char cmos_read_date(unsigned char addr)\n{\n\t/* make sure an update isn't in progress */\n\twhile(cmos_update_in_progress());\n\n\tif(!(cmos_read(CMOS_STATB) & CMOS_STATB_DM)) {\n\t\treturn BCD2BIN(cmos_read(addr));\n\t}\n\treturn cmos_read(addr);\n}\n\nvoid cmos_write_date(unsigned char addr, unsigned char value)\n{\n\t/* make sure an update isn't in progress */\n\twhile(cmos_update_in_progress());\n\n\tif(!(cmos_read(CMOS_STATB) & CMOS_STATB_DM)) {\n\t\tcmos_write(addr, BIN2BCD(value));\n\t}\n\tcmos_write(addr, value);\n}\n\nunsigned char cmos_read(unsigned char addr)\n{\n\tunsigned int flags;\n\n\tSAVE_FLAGS(flags); CLI();\n\toutport_b(CMOS_INDEX, addr);\n\tRESTORE_FLAGS(flags);\n\n\treturn inport_b(CMOS_DATA);\n}\n\nvoid cmos_write(unsigned char addr, unsigned char value)\n{\n\tunsigned int flags;\n\n\tSAVE_FLAGS(flags); CLI();\n\toutport_b(CMOS_INDEX, addr);\n\toutport_b(CMOS_DATA, value);\n\tRESTORE_FLAGS(flags);\n}\n"
  },
  {
    "path": "kernel/core386.S",
    "content": "/*\n * fiwix/kernel/core386.S\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#define ASM_FILE\t1\n\n#include <fiwix/config.h>\n#include <fiwix/segments.h>\n#include <fiwix/unistd.h>\n\n#define CR0_MP\t~(0x00000002)\t/* CR0 bit-01 MP (Monitor Coprocessor) */\n#define CR0_EM\t0x00000004\t/* CR0 bit-02 EM (Emulation) */\n\n#define GS\t\t0x00\n#define FS\t\t0x04\n#define ES\t\t0x08\n#define DS\t\t0x0C\n#define EDI\t\t0x10\t/* \\\t\t\t\t*/\n#define ESI\t\t0x14\t/* |\t\t\t\t*/\n#define EBP\t\t0x18\t/* |\t\t\t\t*/\n#define ESP\t\t0x1C\t/* | saved by\t\t\t*/\n#define EBX\t\t0x20\t/* | 'pusha'\t\t\t*/\n#define EDX\t\t0x24\t/* |\t\t\t\t*/\n#define ECX\t\t0x28\t/* |\t\t\t\t*/\n#define EAX\t\t0x2C\t/* /\t\t\t\t*/\n#define ERR\t\t0x30\t/*   error code (or padding)\t*/\n#define EIP\t\t0x34\t/* \\\t\t\t\t*/\n#define CS\t\t0x38\t/* | saved by processor\t\t*/\n#define FLAGS\t\t0x3C\t/* /\t\t\t\t*/\n#define OLDESP\t\t0x40\t/* \\ saved by processor on\t*/\n#define OLDSS\t\t0x44\t/* / privilege level change\t*/\n\n#define SAVE_ALL\t\t\t\t\t\t\t\\\n\tpusha\t\t\t\t\t\t\t\t;\\\n\tpushl\t%ds\t\t\t\t\t\t\t;\\\n\tpushl\t%es\t\t\t\t\t\t\t;\\\n\tpushl\t%fs\t\t\t\t\t\t\t;\\\n\tpushl\t%gs\n\n#define EXCEPTION(exception)\t\t\t\t\t\t\\\n\tpushl\t$exception\t\t\t\t\t\t;\\\n\tcall\ttrap_handler\t\t\t\t\t\t;\\\n\taddl\t$4, %esp\n\n#define IRQ(irq)\t\t\t\t\t\t\t\\\n\tpushl\t$irq\t\t\t\t\t\t\t;\\\n\tcall\tirq_handler\t\t\t\t\t\t;\\\n\taddl\t$4, %esp\n\n#define BOTTOM_HALVES\t\t\t\t\t\t\t\\\n\tsti\t\t\t\t\t\t\t\t;\\\n\tcall\tdo_bh\n\n#define CHECK_IF_NESTED_INTERRUPT\t\t\t\t\t\\\n\tcmpw\t$(KERNEL_CS), CS(%esp)\t\t\t\t\t;\\\n\tje\t2f\n\n#define CHECK_IF_SIGNALS\t\t\t\t\t\t\\\n\tcall\tissig\t\t\t\t\t\t\t;\\\n\ttestl\t$0xFFFFFFFF, %eax\t\t\t\t\t;\\\n\tjz\t1f\t\t\t\t\t\t\t;\\\n\tmovl\t%esp, %eax\t\t\t\t\t\t;\\\n\tpushl\t%eax\t\t\t\t\t\t\t;\\\n\tcall\tpsig\t\t\t\t\t\t\t;\\\n\taddl\t$4, %esp\t\t\t\t\t\t;\\\n1:\n\n#define CHECK_IF_NEED_SCHEDULE\t\t\t\t\t\t\\\n\tmovl\tneed_resched, %eax\t\t\t\t\t;\\\n\ttestl\t$0xFFFFFFFF, %eax\t\t\t\t\t;\\\n\tjz\t2f\t\t\t\t\t\t\t;\\\n\tcall\tdo_sched\t\t\t\t\t\t;\\\n2:\n\n#define RESTORE_ALL\t\t\t\t\t\t\t\\\n\tpopl\t%gs\t\t\t\t\t\t\t;\\\n\tpopl\t%fs\t\t\t\t\t\t\t;\\\n\tpopl\t%es\t\t\t\t\t\t\t;\\\n\tpopl\t%ds\t\t\t\t\t\t\t;\\\n\tpopa\t\t\t\t\t\t\t\t;\\\n\taddl\t$4, %esp\t/* suppress error code from stack */\n\n\n.text\n\n#define BUILD_EXCEPTION_SIMUL_ERR(num, name)\t\t\t\t\\\n.align 4\t\t\t\t\t\t\t\t;\\\n.globl name; name:\t\t\t\t\t\t\t;\\\n\tpushl\t$0\t\t/* save simulated error code to stack */;\\\n\tSAVE_ALL\t\t\t\t\t\t\t;\\\n\tEXCEPTION(num)\t\t\t\t\t\t\t;\\\n\tBOTTOM_HALVES\t\t\t\t\t\t\t;\\\n\tCHECK_IF_NESTED_INTERRUPT\t\t\t\t\t;\\\n\tCHECK_IF_SIGNALS\t\t\t\t\t\t;\\\n\tCHECK_IF_NEED_SCHEDULE\t\t\t\t\t\t;\\\n\tRESTORE_ALL\t\t\t\t\t\t\t;\\\n\tiret\n\n#define BUILD_EXCEPTION(num, name)\t\t\t\t\t\\\n.align 4\t\t\t\t\t\t\t\t;\\\n.globl name; name:\t\t\t\t\t\t\t;\\\n\tSAVE_ALL\t\t\t\t\t\t\t;\\\n\tEXCEPTION(num)\t\t\t\t\t\t\t;\\\n\tBOTTOM_HALVES\t\t\t\t\t\t\t;\\\n\tCHECK_IF_NESTED_INTERRUPT\t\t\t\t\t;\\\n\tCHECK_IF_SIGNALS\t\t\t\t\t\t;\\\n\tCHECK_IF_NEED_SCHEDULE\t\t\t\t\t\t;\\\n\tRESTORE_ALL\t\t\t\t\t\t\t;\\\n\tiret\n\nBUILD_EXCEPTION_SIMUL_ERR(0, except0)\t/* DIVIDE ERROR */\nBUILD_EXCEPTION_SIMUL_ERR(1, except1)\t/* DEBUG */\nBUILD_EXCEPTION_SIMUL_ERR(2, except2)\t/* NMI INTERRUPT */\nBUILD_EXCEPTION_SIMUL_ERR(3, except3)\t/* BREAKPOINT INT3 */\nBUILD_EXCEPTION_SIMUL_ERR(4, except4)\t/* OVERFLOW */\nBUILD_EXCEPTION_SIMUL_ERR(5, except5)\t/* BOUND */\nBUILD_EXCEPTION_SIMUL_ERR(6, except6)\t/* INVALID OPCODE */\n\n.align 4\n.globl except7; except7:\t# NO MATH COPROCESSOR\n\tpushl\t$0\t\t# save simulated error code to stack\n\tSAVE_ALL\n\tEXCEPTION(0x7)\n\tclts\t\t\t# floating-opcode cached!\n\tBOTTOM_HALVES\n\tCHECK_IF_NESTED_INTERRUPT\n\tCHECK_IF_SIGNALS\n\tCHECK_IF_NEED_SCHEDULE\n\tRESTORE_ALL\n\tiret\n\nBUILD_EXCEPTION(8, except8)\t\t/* DOUBLE FAULT */\nBUILD_EXCEPTION_SIMUL_ERR(9, except9)\t/* COPROCESSOR SEGMENT OVERRUN */\nBUILD_EXCEPTION(10, except10)\t\t/* INVALID TSS */\nBUILD_EXCEPTION(11, except11)\t\t/* SEGMENT NOT PRESENT */\nBUILD_EXCEPTION(12, except12)\t\t/* STACK SEGMENT FAULT */\nBUILD_EXCEPTION(13, except13)\t\t/* GENERAL PROTECTION FAULT */\nBUILD_EXCEPTION(14, except14)\t\t/* PAGE FAULT */\nBUILD_EXCEPTION_SIMUL_ERR(15, except15)\t/* INTEL RESERVED */\nBUILD_EXCEPTION_SIMUL_ERR(16, except16)\t/* FLOATING POINT ERROR */\nBUILD_EXCEPTION(17, except17)\t\t/* ALIGNMENT CHECK */\nBUILD_EXCEPTION_SIMUL_ERR(18, except18)\t/* MACHINE CHECK */\nBUILD_EXCEPTION_SIMUL_ERR(19, except19)\t/* SIMD FLOATING POINT */\nBUILD_EXCEPTION_SIMUL_ERR(20, except20)\t/* INTEL RESERVED */\nBUILD_EXCEPTION_SIMUL_ERR(21, except21)\t/* INTEL RESERVED */\nBUILD_EXCEPTION_SIMUL_ERR(22, except22)\t/* INTEL RESERVED */\nBUILD_EXCEPTION_SIMUL_ERR(23, except23)\t/* INTEL RESERVED */\nBUILD_EXCEPTION_SIMUL_ERR(24, except24)\t/* INTEL RESERVED */\nBUILD_EXCEPTION_SIMUL_ERR(25, except25)\t/* INTEL RESERVED */\nBUILD_EXCEPTION_SIMUL_ERR(26, except26)\t/* INTEL RESERVED */\nBUILD_EXCEPTION_SIMUL_ERR(27, except27)\t/* INTEL RESERVED */\nBUILD_EXCEPTION_SIMUL_ERR(28, except28)\t/* INTEL RESERVED */\nBUILD_EXCEPTION_SIMUL_ERR(29, except29)\t/* INTEL RESERVED */\nBUILD_EXCEPTION_SIMUL_ERR(30, except30)\t/* INTEL RESERVED */\nBUILD_EXCEPTION_SIMUL_ERR(31, except31)\t/* INTEL RESERVED */\n\n\n#define BUILD_IRQ(num, name)\t\t\t\t\t\t\\\n.align 4\t\t\t\t\t\t\t\t;\\\n.globl name; name:\t\t\t\t\t\t\t;\\\n\tpushl\t$0\t\t/* save simulated error code to stack */;\\\n\tSAVE_ALL\t\t\t\t\t\t\t;\\\n\tIRQ(num)\t\t\t\t\t\t\t;\\\n\tBOTTOM_HALVES\t\t\t\t\t\t\t;\\\n\tCHECK_IF_NESTED_INTERRUPT\t\t\t\t\t;\\\n\tCHECK_IF_SIGNALS\t\t\t\t\t\t;\\\n\tCHECK_IF_NEED_SCHEDULE\t\t\t\t\t\t;\\\n\tRESTORE_ALL\t\t\t\t\t\t\t;\\\n\tiret\n\nBUILD_IRQ(0, irq0)\nBUILD_IRQ(1, irq1)\nBUILD_IRQ(2, irq2)\nBUILD_IRQ(3, irq3)\nBUILD_IRQ(4, irq4)\nBUILD_IRQ(5, irq5)\nBUILD_IRQ(6, irq6)\nBUILD_IRQ(7, irq7)\nBUILD_IRQ(8, irq8)\nBUILD_IRQ(9, irq9)\nBUILD_IRQ(10, irq10)\nBUILD_IRQ(11, irq11)\nBUILD_IRQ(12, irq12)\nBUILD_IRQ(13, irq13)\nBUILD_IRQ(14, irq14)\nBUILD_IRQ(15, irq15)\n\n.align 4\n.globl unknown_irq; unknown_irq:\n\tpushl\t$0\t\t# save simulated error code to stack\n\tSAVE_ALL\n\tcall\tunknown_irq_handler\n\tRESTORE_ALL\n\tiret\n\n.align 4\n.globl switch_to_user_mode; switch_to_user_mode:\n\tcli\n\txorl\t%eax, %eax\t\t# initialize %eax\n\tmovl\t%eax, %ebx\t\t# initialize %ebx\n\tmovl\t%eax, %ecx\t\t# initialize %ecx\n\tmovl\t%eax, %edx\t\t# initialize %edx\n\tmovl\t%eax, %esi\t\t# initialize %esi\n\tmovl\t%eax, %edi\t\t# initialize %edi\n\tmovl\t%eax, %ebp\t\t# initialize %ebp\n\tmovl\t$(USER_DS | USER_PL), %eax\n\tmovw\t%ax, %ds\n\tmovw\t%ax, %es\n\tmovw\t%ax, %fs\n\tmovw\t%ax, %gs\n\tpushl\t%eax\n\tpushl\t$PAGE_OFFSET - 4\t# user stack address\n\tpushl\t$0x202\t\t\t# initialize eflags (Linux 2.2 = 0x292)\n\tpopfl\n\tpushfl\n\tmovl\t$(USER_CS | USER_PL), %eax\n\tpushl\t%eax\n\tpushl\t$PAGE_OFFSET - 0x1000\t# go to init_trampoline() in user mode\n\tiret\n\n.align 4\n.globl sighandler_trampoline; sighandler_trampoline:\n\t/*\n\t * This pushes twice the %eax register in order to save the 'signum'\n\t * value from being clobbered by functions like printf(), during the\n\t * signal handler calling.\n\t * FIXME: is this a bug in Newlib or in my side?\n\t */\n\tpushl\t%eax\t\t\t# save 'signum'\n\tpushl\t%eax\t\t\t# 'signum' is the argument of the handler\n\tcall\t*%ecx\n\taddl\t$4, %esp\t\t# discard the first push\n\tpopl\t%ebx\t\t\t# restore 'signum'\n\n\tmovl\t$SYS_sigreturn, %eax\n\tint\t$0x80\n\n\t# never reached, otherwise call sys_exit()\n\tmovl\t$SYS_exit, %eax\n\tint\t$0x80\n\tret\n.align 4\n.globl end_sighandler_trampoline; end_sighandler_trampoline:\n\tnop\n\n.align 4\n.globl syscall; syscall:\t\t# SYSTEM CALL ENTRY\n\tpushl\t%eax\t\t\t# save the system call number\n\tSAVE_ALL\n\n#ifdef CONFIG_SYSCALL_6TH_ARG\n\tpushl\t%ebp\t\t\t# + 6th argument\n#endif /* CONFIG_SYSCALL_6TH_ARG */\n\tpushl\t%edi\t\t\t# \\ 5th argument\n\tpushl\t%esi\t\t\t# | 4th argument\n\tpushl\t%edx\t\t\t# | 3rd argument\n\tpushl\t%ecx\t\t\t# | 2nd argument\n\tpushl\t%ebx\t\t\t# / 1st argument\n\tpushl\t%eax\t\t\t# system call number\n\tcall\tdo_syscall\n#ifdef CONFIG_SYSCALL_6TH_ARG\n\taddl\t$28, %esp\t\t# suppress all 7 pushl from the stack\n#else\n\taddl\t$24, %esp\t\t# suppress all 6 pushl from the stack\n#endif /* CONFIG_SYSCALL_6TH_ARG */\n\tmovl\t%eax, EAX(%esp)\t\t# save the return value\n\n\tBOTTOM_HALVES\n\tCHECK_IF_SIGNALS\n\tCHECK_IF_NEED_SCHEDULE\n.globl return_from_syscall; return_from_syscall:\n\tRESTORE_ALL\n\tiret\n\n.align 4\n.globl do_switch; do_switch:\n\tpusha\n\tpushfl\n\tmovl\t%esp, %ebx\n\taddl\t$0x24, %ebx\n\tmovl\t0x4(%ebx), %eax\t\t# save ESP to 'prev->tss.esp'\n\tmovl\t%esp, (%eax)\n\tmovl\t0x8(%ebx), %eax\t\t# save EIP to 'prev->tss.eip'\n\tmovl\t$1f, (%eax)\n\tmovl\t0xC(%ebx), %esp\t\t# load 'next->tss.esp' into ESP\n\tpushl\t0x10(%ebx)\t\t# push 'next->tss.eip' into ESP\n\tmovl\t0x14(%ebx), %eax\t# load 'next->tss.cr3' into CR3\n\tltr\t0x18(%ebx)\t\t# load TSS\n\tmovl\t%eax, %cr3\n\tret\n1:\n\tpopfl\n\tpopa\n\tret\n\n.align 4\n.globl cpuid; cpuid:\n\tpushl\t%ebp\n\tmovl\t%esp, %ebp\n\tpushl\t%edi\n\tpushl\t%esi\n\tpushl\t%ebx\n\n\tpushf\n\tpop\t%eax\t\t\t# put original EFLAGS in EAX\n\tmov\t%eax, %ecx\t\t# save original EFLAGS in ECX\n\txor\t$0x200000, %eax\t\t# change bit 21 (ID) in EFLAGS\n\tpush\t%eax\t\t\t# save new EFLAGS on stack\n\tpopf\t\t\t\t# replace current EFLAGS\n\tpushf\n\tpop\t%eax\t\t\t# put EFLAGS in EAX\n\tcmp\t%ecx, %eax\t\t# compare if both EFLAGS are equal\n\n\tje\ttest386\t\t\t# can't toggle ID bit, no CPUID\n\txor\t%ebx, %ebx\t\t# CPUID available, will return 0\n\tjmp\tend_cpuid \n\ntest386:\n\tmov\t%ecx, %eax\t\t# get original EFLAGS\n\txor\t$0x40000, %eax\t\t# change bit 18 (AC) in EFLAGS\n\tpush\t%eax\t\t\t# save new EFLAGS on stack\n\tpopf\t\t\t\t# replace current EFLAGS\n\tpushf\n\tpop\t%eax\n\tcmp\t%ecx, %eax\t\t# compare if both EFLAGS are equal\n\tmovb\t$3, %bl\t\t\t# looks like an i386, return 3\n\tje\tend_cpuid\n\tmovb\t$4, %bl\t\t\t# otherwise is an old i486, return 4\n\nend_cpuid:\n\tpush\t%ecx\t\t\t# push original EFLAGS\n\tpopf\t\t\t\t# restore original EFLAGS\n\txor\t%eax, %eax\n\tmovb\t%bl, %al\t\t# put return value to AL\n\n\tpopl\t%ebx\n\tpopl\t%esi\n\tpopl\t%edi\n\tpopl\t%ebp\n\tret\n\n.align 4\n.globl getfpu; getfpu:\n\tpushl\t%ebp\n\tmovl\t%esp, %ebp\n\tpushl\t%edi\n\tpushl\t%esi\n\tpushl\t%ebx\n\n\tfninit\n\tmovl\t$0x5a5a, _fpstatus\n\tfnstsw\t_fpstatus\n\tmovl\t_fpstatus, %eax\n\tcmp\t$0, %al\n\tmovl\t$0, _fpstatus\n\tjne\tend_getfpu\n\ncheck_control_word:\n\tfnstcw\t_fpstatus\n\tmovl\t_fpstatus, %eax\n\tandl\t$0x103f, %eax\n\tcmp\t$0x3f, %ax\n\tmovl\t$0, _fpstatus\n\tjne\tend_getfpu\n\tmovl\t$1, _fpstatus\n\nend_getfpu:\n\tmovl\t_fpstatus, %eax\n\tcmp\t$0, %al\n\tjne\t1f\t\t\t# return if there is a coprocessor\n\tmovl\t%cr0, %eax\t\t# otherwise (no math processor):\n\torl\t$CR0_EM, %eax\t\t# - set   EM (Emulation)\n\tandl\t$CR0_MP, %eax\t\t# - clear MP (Monitor Coprocessor)\n\tmovl\t%eax, %cr0\n\tmovl\t$0, %eax\n1:\n\tpopl\t%ebx\n\tpopl\t%esi\n\tpopl\t%edi\n\tpopl\t%ebp\n\tret\n\n.align 4\n.globl get_cpu_vendor_id; get_cpu_vendor_id:\n\tpushl\t%ebp\n\tmovl\t%esp, %ebp\n\tpushl\t%ebx\n\tpushl\t%edx\n\tpushl\t%ecx\n\n\tmov\t$0, %eax\n\tcpuid\n\tmovl\t%ebx, _vendorid\t\t# save the 12 bytes of vendor ID string\n\tmovl\t%edx, _vendorid+4\n\tmovl\t%ecx, _vendorid+8\n\n\tpopl\t%ecx\n\tpopl\t%edx\n\tpopl\t%ebx\n\tpopl\t%ebp\n\tret\t\t\t\t# EAX returns the highest CPUID value\n\n.align 4\n.globl signature_flags; signature_flags:\n\tpushl\t%ebp\n\tmovl\t%esp, %ebp\n\tpushl\t%edi\n\tpushl\t%esi\n\tpushl\t%ebx\n\tpushl\t%edx\n\n\tmov\t$1, %eax\n\tcpuid\n\tmovl\t%eax, _cpusignature\t# signature (model and stepping)\n\tmovl\t%ebx, _brandid\t\t# misc. information\n\tmovl\t%edx, _cpuflags\t\t# feature flags\n\tshrl\t$8, %eax\n\tandl\t$0xF, %eax\n\tmovl\t%eax, _cputype\t\t# family\n\n\tpopl\t%edx\n\tpopl\t%ebx\n\tpopl\t%esi\n\tpopl\t%edi\n\tpopl\t%ebp\n\tret\n\n.align 4\n.globl brand_str; brand_str:\n\tpushl\t%ebp\n\tmovl\t%esp, %ebp\n\tpushl\t%edi\n\tpushl\t%esi\n\tpushl\t%ebx\n\n\tmovl\t$0x80000000, %eax\n\tcpuid\n\tcmp\t$0x80000000, %eax\t# check if brand string is supported\n\tjbe\tno_brand_str\n\tmovl\t$0x80000002, %eax\t# get first 16 bytes of brand string\n\tcpuid\n\tmovl\t%eax, _brandstr\n\tmovl\t%ebx, _brandstr+4\n\tmovl\t%ecx, _brandstr+8\n\tmovl\t%edx, _brandstr+12\n\tmovl\t$0x80000003, %eax\t# get more 16 bytes of brand string\n\tcpuid\n\tmovl\t%eax, _brandstr+16\n\tmovl\t%ebx, _brandstr+20\n\tmovl\t%ecx, _brandstr+24\n\tmovl\t%edx, _brandstr+28\n\tmovl\t$0x80000004, %eax\t# get last 16 bytes of brand string\n\tcpuid\n\tmovl\t%eax, _brandstr+32\n\tmovl\t%ebx, _brandstr+36\n\tmovl\t%ecx, _brandstr+40\n\tmovl\t%edx, _brandstr+44\n\tjmp\tend_brand_str\n\nno_brand_str:\n\tmovl\t$1, %eax\n\nend_brand_str:\n\tmovl\t$0, %eax\n\tpopl\t%ebx\n\tpopl\t%esi\n\tpopl\t%edi\n\tpopl\t%ebp\n\tret\n\n.align 4\n.globl tlbinfo; tlbinfo:\n\tpushl\t%edx\n\tpushl\t%ecx\n\tpushl\t%ebx\n\tmov\t$2, %eax\n\tcpuid\n\tmovl\t%eax, _tlbinfo_eax\t# store cache information\n\tmovl\t%ebx, _tlbinfo_ebx\n\tmovl\t%edx, _tlbinfo_ecx\n\tmovl\t%ecx, _tlbinfo_edx\n\tpopl\t%ebx\n\tpopl\t%ecx\n\tpopl\t%edx\n\tret\n\n.align 4\n.globl inport_b; inport_b:\n\tpushl\t%ebp\n\tmovl\t%esp, %ebp\n\n\tmovw\t0x08(%ebp), %dx\t\t# port addr\n\txorl\t%eax, %eax\t\t# initialize %eax\n\tinb\t%dx, %al\n\n\tjmp\t1f\t\t\t# recovery time\n1:\tjmp\t1f\t\t\t# recovery time\n1:\tpopl\t%ebp\n\tret\n\n.align 4\n.globl inport_w; inport_w:\n\tpushl\t%ebp\n\tmovl\t%esp, %ebp\n\n\tmovw\t0x08(%ebp), %dx\t\t# port addr\n\tinw\t%dx, %ax\n\n\tjmp\t1f\t\t\t# recovery time\n1:\tjmp\t1f\t\t\t# recovery time\n1:\tpopl\t%ebp\n\tret\n\n.align 4\n.globl inport_l; inport_l:\n\tpushl\t%ebp\n\tmovl\t%esp, %ebp\n\n\tmovl\t0x08(%ebp), %edx\t# port addr\n\tinl\t%dx, %eax\n\n\tjmp\t1f\t\t\t# recovery time\n1:\tjmp\t1f\t\t\t# recovery time\n1:\tpopl\t%ebp\n\tret\n\n.align 4\n.globl inport_sw; inport_sw:\n\tpushl\t%ebp\n\tmovl\t%esp, %ebp\n\tpushl\t%edx\n\tpushl\t%edi\n\tpushl\t%ecx\n\n\tcld\n\tmov\t0x8(%ebp), %edx\t\t# port addr\n\tmov\t0xC(%ebp), %edi\t\t# dest\n\tmov\t0x10(%ebp), %ecx\t# count\n\trep\tinsw\n\n\tpopl\t%ecx\n\tpopl\t%edi\n\tpopl\t%edx\n\tpopl\t%ebp\n\tret\n\n.align 4\n.globl inport_sl; inport_sl:\n\tpushl\t%ebp\n\tmovl\t%esp, %ebp\n\tpushl\t%edx\n\tpushl\t%edi\n\tpushl\t%ecx\n\n\tcld\n\tmovl\t0x8(%ebp), %edx\t\t# port addr\n\tmovl\t0xC(%ebp), %edi\t\t# dest\n\tmovl\t0x10(%ebp), %ecx\t# count\n\trep\tinsl\n\n\tpopl\t%ecx\n\tpopl\t%edi\n\tpopl\t%edx\n\tpopl\t%ebp\n\tret\n\n.align 4\n.globl outport_b; outport_b:\n\tpushl\t%ebp\n\tmovl\t%esp, %ebp\n\n\tmovw\t0x8(%ebp), %dx\t\t# port addr\n\tmovb\t0xC(%ebp), %al\t\t# data\n\toutb\t%al, %dx\n\n\tjmp\t1f\t\t\t# recovery time\n1:\tjmp\t1f\t\t\t# recovery time\n1:\tpopl\t%ebp\n\tret\n\n.align 4\n.globl outport_w; outport_w:\n\tpushl\t%ebp\n\tmovl\t%esp, %ebp\n\n\tmovw\t0x8(%ebp), %dx\t\t# port addr\n\tmovw\t0xC(%ebp), %ax\t\t# data\n\toutw\t%ax, %dx\n\n\tjmp\t1f\t\t\t# recovery time\n1:\tjmp\t1f\t\t\t# recovery time\n1:\tpopl\t%ebp\n\tret\n\n.align 4\n.globl outport_l; outport_l:\n\tpushl\t%ebp\n\tmovl\t%esp, %ebp\n\n\tmovl\t0x8(%ebp), %edx\t\t# port addr\n\tmovl\t0xC(%ebp), %eax\t\t# data\n\toutl\t%eax, %dx\n\n\tjmp\t1f\t\t\t# recovery time\n1:\tjmp\t1f\t\t\t# recovery time\n1:\tpopl\t%ebp\n\tret\n\n.align 4\n.globl outport_sw; outport_sw:\n\tpushl\t%ebp\n\tmovl\t%esp, %ebp\n\tpushl\t%edx\n\tpushl\t%esi\n\tpushl\t%ecx\n\n\tcld\n\tmov\t0x8(%ebp), %edx\t\t# port addr\n\tmov\t0xC(%ebp), %esi\t\t# src\n\tmov\t0x10(%ebp), %ecx\t# count\n\trep\toutsw\n\n\tpopl\t%ecx\n\tpopl\t%esi\n\tpopl\t%edx\n\tpopl\t%ebp\n\tret\n\n.align 4\n.globl outport_sl; outport_sl:\n\tpushl\t%ebp\n\tmovl\t%esp, %ebp\n\tpushl\t%edx\n\tpushl\t%esi\n\tpushl\t%ecx\n\n\tcld\n\tmovl\t0x8(%ebp), %edx\t\t# port addr\n\tmovl\t0xC(%ebp), %esi\t\t# src\n\tmovl\t0x10(%ebp), %ecx\t# count\n\trep\toutsl\n\n\tpopl\t%ecx\n\tpopl\t%esi\n\tpopl\t%edx\n\tpopl\t%ebp\n\tret\n\n.align 4\n.globl load_gdt; load_gdt:\n\tmovl\t0x4(%esp), %eax\n\tlgdt\t(%eax)\n\tmovw\t$KERNEL_DS, %ax\n\tmovw\t%ax, %ds\n\tmovw\t%ax, %es\n\tmovw\t%ax, %fs\n\tmovw\t%ax, %gs\n\tmovw\t%ax, %ss\n\tljmp\t$KERNEL_CS, $1f\n1:\n\tret\n\n.align 4\n.globl load_idt; load_idt:\n\tmovl\t0x4(%esp), %eax\n\tlidt\t(%eax)\n\tret\n\n.align 4\n.globl activate_kpage_dir; activate_kpage_dir:\n\tmovl\tkpage_dir, %eax\n\tmovl\t%eax, %cr3\n\tret\n\n.align 4\n.globl load_tr; load_tr:\n\tmov\t0x4(%esp), %ax\n\tltr\t%ax\n\tret\n\n.align 4\n.globl get_rdtsc; get_rdtsc:\n\tcpuid\n\trdtsc\n\tret\n\n.align 4\n.globl invalidate_tlb; invalidate_tlb:\n\tmovl\t%cr3, %eax\n\tmovl\t%eax, %cr3\n\tret\n\n\n.data\n\n.globl\t_cputype\n.globl\t_cpusignature\n.globl\t_cpuflags\n.globl\t_fpstatus\n.globl\t_brandid\n.globl\t_vendorid\n.globl\t_brandstr\n.globl\t_tlbinfo_eax\n.globl\t_tlbinfo_ebx\n.globl\t_tlbinfo_ecx\n.globl\t_tlbinfo_edx\n\n_cputype:\t.int\t0\n_cpusignature:\t.int\t0\n_cpuflags:\t.int\t0\n_fpstatus:\t.int\t0\n_brandid:\t.int\t0\n_vendorid:\t.fill\t13,1,0\n_brandstr:\t.fill\t49,1,0\n_tlbinfo_eax:\t.int\t0\n_tlbinfo_ebx:\t.int\t0\n_tlbinfo_ecx:\t.int\t0\n_tlbinfo_edx:\t.int\t0\n"
  },
  {
    "path": "kernel/cpu.c",
    "content": "/*\n * fiwix/kernel/cpu.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/utsname.h>\n#include <fiwix/pic.h>\n#include <fiwix/pit.h>\n#include <fiwix/cpu.h>\n#include <fiwix/timer.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nchar UTS_MACHINE[_UTSNAME_LENGTH + 1];\nstruct cpu cpu_table;\n\nstatic struct cpu_type intel[] = {\n\t{ 4,\n\t   { \"i486 DX\", \"i486 DX\", \"i486 SX\", \"i486 DX/2\",\n\t     \"i486 SL\", \"i486 SX/2\", NULL, \"i486 DX/2 WBE\",\n\t     \"i486 DX/4\", NULL, NULL, NULL, NULL, NULL, NULL, NULL }\n\t},\n\t{ 5,\n\t   { NULL, \"Pentium 60/66\", \"Pentium 75-200\", \"Pentium ODfor486\",\n\t     \"PentiumMMX\", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,\n\t     NULL, NULL, NULL }\n\t},\n\t{ 6,\n\t   { NULL, \"Pentium Pro\", NULL, \"Pentium II\", NULL, \"Pentium II\",\n\t     \"Intel Celeron\", \"Pentium III\", \"Pentium III\", NULL,\n\t     \"Pentium III Xeon\", \"Pentium III\", NULL, NULL, NULL, NULL }\n\t}\n};\n\nstatic const char *cpu_flags[] = {\n\t\"FPU\", \"VME\", \"DE\", \"PSE\", \"TSC\", \"MSR\", \"PAE\", \"MCE\", \"CX8\", \"APIC\",\n\t\"10\", \"SEP\", \"MTRR\", \"PGE\", \"MCA\", \"CMOV\", \"PAT\", \"PSE-36\", \"PSN\",\n\t\"CLFSH\", \"20\", \"DS\", \"ACPI\", \"MMX\", \"FXSR\", \"SSE\", \"SSE2\", \"SS\",\n\t\"HTT\", \"TM\", \"30\", \"PBE\"\n};\n\nstatic unsigned int detect_cpuspeed(void)\n{\n\tunsigned long long int tsc1, tsc2;\n\n\toutport_b(MODEREG, SEL_CHAN2 | LSB_MSB | TERM_COUNT | BINARY_CTR);\n\toutport_b(CHANNEL2, (OSCIL / HZ) & 0xFF);\n\toutport_b(CHANNEL2, (OSCIL / HZ) >> 8);\n\toutport_b(PS2_SYSCTRL_B, inport_b(PS2_SYSCTRL_B) | ENABLE_SDATA | ENABLE_TMR2G);\n\n\ttsc1 = 0;\n\ttsc1 = get_rdtsc();\n\n\twhile(!(inport_b(PS2_SYSCTRL_B) & 0x20));\n\n\ttsc2 = 0;\n\ttsc2 = get_rdtsc();\n\n\toutport_b(PS2_SYSCTRL_B, inport_b(PS2_SYSCTRL_B) & ~(ENABLE_SDATA | ENABLE_TMR2G));\n\n\treturn (tsc2 - tsc1) * HZ;\n}\n\n/*\n * These are the 2nd and 3rd level cache values according to Intel Processor\n * Identification and the CPUID Instruction.\n * Application Note 485. Document Number: 241618-031. September 2006.\n */\nstatic void show_cache(int value)\n{\n\tswitch(value) {\n\t\t/* 2nd level cache */\n\t\tcase 0x39:\n\t\tcase 0x3B:\n\t\tcase 0x41:\n\t\tcase 0x79:\n\t\t\tcpu_table.cache = \"128KB L2\";\n\t\t\tbreak;\n\t\tcase 0x3A:\n\t\t\tcpu_table.cache = \"192KB L2\";\n\t\t\tbreak;\n\t\tcase 0x3C:\n\t\tcase 0x42:\n\t\tcase 0x7A:\n\t\tcase 0x82:\n\t\t\tcpu_table.cache = \"256KB L2\";\n\t\t\tbreak;\n\t\tcase 0x3D:\n\t\t\tcpu_table.cache = \"384KB L2\";\n\t\t\tbreak;\n\t\tcase 0x3E:\n\t\tcase 0x43:\n\t\tcase 0x7B:\n\t\tcase 0x7F:\n\t\tcase 0x83:\n\t\tcase 0x86:\n\t\t\tcpu_table.cache = \"512KB L2\";\n\t\t\tbreak;\n\t\tcase 0x44:\n\t\tcase 0x78:\n\t\tcase 0x7C:\n\t\tcase 0x84:\n\t\tcase 0x87:\n\t\t\tcpu_table.cache = \"1MB L2\";\n\t\t\tbreak;\n\t\tcase 0x45:\n\t\tcase 0x7D:\n\t\tcase 0x85:\n\t\t\tcpu_table.cache = \"2MB L2\";\n\t\t\tbreak;\n\n\t\t/* 3rd level cache */\n\t\tcase 0x22:\n\t\t\tcpu_table.cache = \"512KB L3\";\n\t\t\tbreak;\n\t\tcase 0x23:\n\t\t\tcpu_table.cache = \"1MB L3\";\n\t\t\tbreak;\n\t\tcase 0x25:\n\t\t\tcpu_table.cache = \"2MB L3\";\n\t\t\tbreak;\n\t\tcase 0x29:\n\t\tcase 0x46:\n\t\t\tcpu_table.cache = \"4MB L3\";\n\t\t\tbreak;\n\t\tcase 0x49:\n\t\t\tcpu_table.cache = \"4MB L3 & L2\";\n\t\t\tbreak;\n\t\tcase 0x4A:\n\t\t\tcpu_table.cache = \"6MB L3\";\n\t\t\tbreak;\n\t\tcase 0x47:\n\t\tcase 0x4B:\n\t\t\tcpu_table.cache = \"8MB L3\";\n\t\t\tbreak;\n\t\tcase 0x4C:\n\t\t\tcpu_table.cache = \"12MB L3\";\n\t\t\tbreak;\n\t\tcase 0x4D:\n\t\t\tcpu_table.cache = \"16MB L3\";\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t}\n}\n\nstatic void check_cache(int maxcpuid)\n{\n\tint n, maxcpuids;\n\n\tmaxcpuids = 1;\n\tif(maxcpuid >= 2) {\n\t\tfor(n = 0; n < maxcpuids; n++) {\n\t\t\ttlbinfo();\n\t\t\tmaxcpuids = _tlbinfo_eax & 0xFF;\n\t\t\tshow_cache((_tlbinfo_eax >> 8) & 0xFF);\n\t\t\tshow_cache((_tlbinfo_eax >> 16) & 0xFF);\n\t\t\tshow_cache((_tlbinfo_eax >> 24) & 0xFF);\n\t\t\tif(!(_tlbinfo_ebx & RESERVED_DESC)) {\n\t\t\t\tshow_cache(_tlbinfo_ebx & 0xFF);\n\t\t\t\tshow_cache((_tlbinfo_ebx >> 8) & 0xFF);\n\t\t\t\tshow_cache((_tlbinfo_ebx >> 16) & 0xFF);\n\t\t\t\tshow_cache((_tlbinfo_ebx >> 24) & 0xFF);\n\t\t\t}\n\t\t\tif(!(_tlbinfo_ecx & RESERVED_DESC)) {\n\t\t\t\tshow_cache(_tlbinfo_ecx & 0xFF);\n\t\t\t\tshow_cache((_tlbinfo_ecx >> 8) & 0xFF);\n\t\t\t\tshow_cache((_tlbinfo_ecx >> 16) & 0xFF);\n\t\t\t\tshow_cache((_tlbinfo_ecx >> 24) & 0xFF);\n\t\t\t}\n\t\t\tif(!(_tlbinfo_edx & RESERVED_DESC)) {\n\t\t\t\tshow_cache(_tlbinfo_edx & 0xFF);\n\t\t\t\tshow_cache((_tlbinfo_edx >> 8) & 0xFF);\n\t\t\t\tshow_cache((_tlbinfo_edx >> 16) & 0xFF);\n\t\t\t\tshow_cache((_tlbinfo_edx >> 24) & 0xFF);\n\t\t\t}\n\t\t}\n\t}\n}\n\nint get_cpu_flags(char *buffer)\n{\n\tint n, size;\n\tunsigned int mask;\n\n\tsize = sprintk(buffer, \"flags           :\");\n\tfor(n = 0, mask = 1; n < 32; n++, mask <<= 1) {\n\t\tif(_cpuflags & mask) {\n\t\t\tsize += sprintk(buffer + size, \" %s\", cpu_flags[n]);\n\t\t}\n\t}\n\tsize += sprintk(buffer + size, \"\\n\");\n\treturn size;\n}\n\nvoid cpu_init(void)\n{\n\tunsigned int n;\n\tint maxcpuid;\n\n\tmemset_b(&cpu_table, 0, sizeof(cpu_table));\n\tcpu_table.model = -1;\n\tcpu_table.stepping = -1;\n\n\tprintk(\"cpu       -                 -\\t\");\n\tcpu_table.family = cpuid();\n\tif(!cpu_table.family) {\n\t\tcpu_table.has_cpuid = 1;\n\t\tmaxcpuid = get_cpu_vendor_id();\n\t\tcpu_table.vendor_id = _vendorid;\n\t\tif(maxcpuid >= 1) {\n\t\t\tsignature_flags();\n\t\t\tcpu_table.family = _cputype;\n\t\t\tcpu_table.flags = _cpuflags;\n\t\t\tif(!strcmp((char *)_vendorid, \"GenuineIntel\")) {\n\t\t\t\tprintk(\"Intel \");\n\t\t\t\tfor(n = 0; n < sizeof(intel) / sizeof(struct cpu_type); n++) {\n\t\t\t\t\tif(intel[n].cpu == _cputype) {\n\t\t\t\t\t\tcpu_table.model_name = !intel[n].name[(((int)_cpusignature >> 4) & 0xF)] ? NULL : intel[n].name[(((int)_cpusignature >> 4) & 0xF)];\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(cpu_table.model_name) {\n\t\t\t\t\tprintk(\"%s\", cpu_table.model_name);\n\t\t\t\t} else {\n\t\t\t\t\tprintk(\"processor\");\n\t\t\t\t}\n\t\t\t} else if(!strcmp((char *)_vendorid, \"AuthenticAMD\")) {\n\t\t\t\t\tprintk(\"AMD processor\");\n\t\t\t} else {\n\t\t\t\tprintk(\"x86\");\n\t\t\t}\n\t\t\tif(_cpuflags & CPU_TSC) {\n\t\t\t\tcpu_table.hz = detect_cpuspeed();\n\t\t\t\tprintk(\" at %d.%d Mhz\", (cpu_table.hz / 1000000), ((cpu_table.hz % 1000000) / 100000));\n\t\t\t\tcheck_cache(maxcpuid);\n\t\t\t\tif(cpu_table.cache) {\n\t\t\t\t\tprintk(\" (%s)\", cpu_table.cache);\n\t\t\t\t}\n\t\t\t}\n\t\t\tprintk(\"\\n\");\n\t\t\tprintk(\"\\t\\t\\t\\tvendorid=%s \", _vendorid);\n\t\t\tcpu_table.model = (_cpusignature >> 4) & 0xF;\n\t\t\tcpu_table.stepping = _cpusignature & 0xF;\n\t\t\tprintk(\"model=%d stepping=%d\\n\", cpu_table.model, cpu_table.stepping);\n\t\t}\n\t\tif(!brand_str()) {\n\t\t\tcpu_table.model_name = _brandstr;\n\t\t\tif(cpu_table.model_name[0]) {\n\t\t\t\tprintk(\"\\t\\t\\t\\t%s\\n\", cpu_table.model_name);\n\t\t\t}\n\t\t}\n\t} else {\n\t\tprintk(\"80%d86\\n\", cpu_table.family);\n\t\tcpu_table.has_cpuid = 0;\n\t}\n\tstrcpy(UTS_MACHINE, \"i386\");\n\tstrncpy(sys_utsname.machine, UTS_MACHINE, _UTSNAME_LENGTH);\n\tcpu_table.has_fpu = getfpu();\n}\n"
  },
  {
    "path": "kernel/gdt.c",
    "content": "/*\n * fiwix/kernel/gdt.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/types.h>\n#include <fiwix/segments.h>\n#include <fiwix/process.h>\n#include <fiwix/limits.h>\n#include <fiwix/string.h>\n\nstruct seg_desc gdt[NR_GDT_ENTRIES];\n\nstruct desc_r gdtr = {\n\tsizeof(gdt) - 1,\n\t(unsigned int)&gdt\n};\n\nstatic void gdt_set_entry(int num, unsigned int base_addr, unsigned int limit, char loflags, char hiflags)\n{\n\tnum /= sizeof(struct seg_desc);\n\tgdt[num].sd_lolimit = limit & 0xFFFF;\n\tgdt[num].sd_lobase = base_addr & 0xFFFFFF;\n\tgdt[num].sd_loflags = loflags;\n\tgdt[num].sd_hilimit = (limit >> 16) & 0x0F;\n\tgdt[num].sd_hiflags = hiflags;\n\tgdt[num].sd_hibase = (base_addr >> 24) & 0xFF;\n}\n\nvoid gdt_init(void)\n{\n\tunsigned char loflags;\n\n\tgdt_set_entry(0, 0, 0, 0, 0);\t/* null descriptor */\n\n\tloflags = SD_CODE | SD_CD | SD_DPL0 | SD_PRESENT;\n\tgdt_set_entry(KERNEL_CS, 0, 0xFFFFFFFF, loflags, SD_OPSIZE32 | SD_PAGE4KB);\n\tloflags = SD_DATA | SD_CD | SD_DPL0 | SD_PRESENT;\n\tgdt_set_entry(KERNEL_DS, 0, 0xFFFFFFFF, loflags, SD_OPSIZE32 | SD_PAGE4KB);\n\n\tloflags = SD_CODE | SD_CD | SD_DPL3 | SD_PRESENT;\n\tgdt_set_entry(USER_CS, 0, 0xFFFFFFFF, loflags, SD_OPSIZE32 | SD_PAGE4KB);\n\tloflags = SD_DATA | SD_CD | SD_DPL3 | SD_PRESENT;\n\tgdt_set_entry(USER_DS, 0, 0xFFFFFFFF, loflags, SD_OPSIZE32 | SD_PAGE4KB);\n\n\tloflags = SD_TSSPRESENT;\n\tgdt_set_entry(TSS, 0, sizeof(struct i386tss), loflags, SD_OPSIZE32);\n\n\tload_gdt((unsigned int)&gdtr);\n}\n"
  },
  {
    "path": "kernel/idt.c",
    "content": "/*\n * fiwix/kernel/idt.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/types.h>\n#include <fiwix/segments.h>\n#include <fiwix/string.h>\n\nstruct gate_desc idt[NR_IDT_ENTRIES];\n\nstruct desc_r idtr = {\n\tsizeof(idt) - 1,\n\t(unsigned int)idt\n};\n\nstatic void *except_handlers[] = {\n\t&except0, &except1, &except2, &except3, &except4, &except5, &except6, &except7,\n\t&except8, &except9, &except10, &except11, &except12, &except13, &except14, &except15,\n\t&except16, &except17, &except18, &except19, &except20, &except21, &except22, &except23,\n\t&except24, &except25, &except26, &except27, &except28, &except29, &except30, &except31\n};\n\nstatic void *irq_handlers[] = {\n\t&irq0, &irq1, &irq2, &irq3, &irq4, &irq5, &irq6, &irq7,\n\t&irq8, &irq9, &irq10, &irq11, &irq12, &irq13, &irq14, &irq15\n};\n\nstatic void set_idt_entry(int num, __off_t handler, unsigned int flags)\n{\n\tidt[num].gd_looffset = handler & 0x0000FFFF;\n\tidt[num].gd_selector = KERNEL_CS;\n\tidt[num].gd_flags = flags << 8;\n\tidt[num].gd_hioffset = handler >> 16;\n}\n\nvoid idt_init(void)\n{\n\tint n;\n\n\tmemset_b(idt, 0, sizeof(idt));\n\tfor(n = 0; n < NR_IDT_ENTRIES; n++) {\n\t\tif(n < 0x20) {\n\t\t\tset_idt_entry(n, (__off_t)except_handlers[n], SD_32TRAPGATE | SD_PRESENT);\n\t\t\tcontinue;\n\t\t}\n\t\tif(n < 0x30) {\n\t\t\tset_idt_entry(n, (__off_t)irq_handlers[n - 0x20], SD_32INTRGATE | SD_PRESENT);\n\t\t\tcontinue;\n\t\t}\n\t\tset_idt_entry(n, (__off_t)&unknown_irq, SD_32INTRGATE | SD_PRESENT);\n\t}\n\n\tset_idt_entry(0x80, (__off_t)&syscall, SD_32TRAPGATE | SD_DPL3 | SD_PRESENT);\n\n\tload_idt((unsigned int)&idtr);\n}\n"
  },
  {
    "path": "kernel/init.c",
    "content": "/*\n * fiwix/kernel/init.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/system.h>\n#include <fiwix/mm.h>\n#include <fiwix/timer.h>\n#include <fiwix/sched.h>\n#include <fiwix/sleep.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/stat.h>\n#include <fiwix/process.h>\n#include <fiwix/syscalls.h>\n#include <fiwix/unistd.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#define INIT_TRAMPOLINE_SIZE\t256\t/* max. size of init_trampoline() */\n\nchar *init_args;\nchar *init_argv[] = { INIT_PROGRAM, NULL, NULL };\nchar *init_envp[] = { \"HOME=/\", \"TERM=linux\", NULL };\n\nstatic void init_trampoline(void)\n{\n\tUSER_SYSCALL(SYS_open, \"/dev/console\", O_RDWR, 0);\t/* stdin */\n\tUSER_SYSCALL(SYS_dup, 0, NULL, NULL);\t\t\t/* stdout */\n\tUSER_SYSCALL(SYS_dup, 0, NULL, NULL);\t\t\t/* stderr */\n\tUSER_SYSCALL(SYS_execve, INIT_PROGRAM, init_argv, init_envp);\n\n\t/* only reached in case of error in sys_execve() */\n\tUSER_SYSCALL(SYS_exit, NULL, NULL, NULL);\n}\n\nvoid init_init(void)\n{\n\tint n;\n\tunsigned int page;\n\tstruct inode *i;\n\tunsigned int *pgdir;\n\tstruct proc *init;\n\n\tif(namei(INIT_PROGRAM, &i, NULL, FOLLOW_LINKS)) {\n\t\tPANIC(\"can't find %s.\\n\", INIT_PROGRAM);\n\t}\n\tif(!S_ISREG(i->i_mode)) {\n\t\tPANIC(\"%s is not a regular file.\\n\", INIT_PROGRAM);\n\t}\n\tiput(i);\n\n\t/* INIT slot was already created in main.c */\n\tinit = &proc_table[INIT];\n\n\t/* INIT process starts with the current (kernel) Page Directory */\n\tif(!(pgdir = (void *)kmalloc(PAGE_SIZE))) {\n\t\tgoto init_init__die;\n\t}\n\tinit->rss++;\n\tmemcpy_b(pgdir, kpage_dir, PAGE_SIZE);\n\tinit->tss.cr3 = V2P((unsigned int)pgdir);\n\n\tinit->ppid = &proc_table[IDLE];\n\tinit->pgid = 0;\n\tinit->sid = 0;\n\tinit->flags = 0;\n\tinit->children = 0;\n\tinit->priority = DEF_PRIORITY;\n\tinit->start_time = CURRENT_TICKS;\n\tinit->sleep_address = NULL;\n\tinit->uid = init->gid = 0;\n\tinit->euid = init->egid = 0;\n\tinit->suid = init->sgid = 0;\n\tmemset_b(init->fd, 0, sizeof(init->fd));\n\tmemset_b(init->fd_flags, 0, sizeof(init->fd_flags));\n\tinit->root = current->root;\n\tinit->pwd = current->pwd;\n\tstrcpy(init->argv0, init_argv[0]);\n\tinit_argv[1] = init_args;\n\tsprintk(init->pidstr, \"%d\", init->pid);\n\tinit->sigpending = 0;\n\tinit->sigblocked = 0;\n\tinit->sigexecuting = 0;\n\tmemset_b(init->sigaction, 0, sizeof(init->sigaction));\n\tmemset_b(&init->usage, 0, sizeof(struct rusage));\n\tmemset_b(&init->cusage, 0, sizeof(struct rusage));\n\tinit->timeout = 0;\n\tfor(n = 0; n < RLIM_NLIMITS; n++) {\n\t\tinit->rlim[n].rlim_cur = init->rlim[n].rlim_max = RLIM_INFINITY;\n\t}\n\tinit->rlim[RLIMIT_NOFILE].rlim_cur = OPEN_MAX;\n\tinit->rlim[RLIMIT_NOFILE].rlim_max = NR_OPENS;\n\tinit->rlim[RLIMIT_NPROC].rlim_cur = CHILD_MAX;\n\tinit->rlim[RLIMIT_NPROC].rlim_max = NR_PROCS;\n\tinit->umask = 0022;\n\n\t/* setup the stack */\n\tif(!(init->tss.esp0 = kmalloc(PAGE_SIZE))) {\n\t\tgoto init_init__die;\n\t}\n\tinit->tss.esp0 += PAGE_SIZE - 4;\n\tinit->rss++;\n\tinit->tss.ss0 = KERNEL_DS;\n\n\t/* setup the init_trampoline */\n\tpage = map_page(init, PAGE_OFFSET - PAGE_SIZE, 0, PROT_READ | PROT_WRITE);\n\tmemcpy_b((void *)page, init_trampoline, INIT_TRAMPOLINE_SIZE);\n\n\tinit->tss.eip = (unsigned int)switch_to_user_mode;\n\tinit->tss.esp = page + PAGE_SIZE - 4;\n\n\trunnable(init);\n\tnr_processes++;\n\treturn;\n\ninit_init__die:\n\tPANIC(\"unable to run init process.\\n\");\n}\n"
  },
  {
    "path": "kernel/irq.c",
    "content": "/*\n * fiwix/kernel/irq.c\n *\n * Copyright 2021-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/errno.h>\n#include <fiwix/irq.h>\n#include <fiwix/pic.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n#include <fiwix/sigcontext.h>\n#include <fiwix/sleep.h>\n\nstruct interrupt *irq_table[NR_IRQS];\nstatic struct bh *bh_table = NULL;\n\nint register_irq(int num, struct interrupt *new_irq)\n{\n\tstruct interrupt **irq;\n\n\tif(num < 0  || num >= NR_IRQS) {\n\t\tprintk(\"WARNING: %s(): interrupt %d is greater than NR_IRQS (%d)!\\n\", __FUNCTION__, num, NR_IRQS);\n\t\treturn -EINVAL;\n\t}\n\n\tirq = &irq_table[num];\n\n\twhile(*irq) {\n\t\tif(*irq == new_irq) {\n\t\t\tprintk(\"WARNING: %s(): interrupt %d already registered!\\n\", __FUNCTION__, num);\n\t\t\treturn -EINVAL;\n\t\t}\n\t\tirq = &(*irq)->next;\n\t}\n\t*irq = new_irq;\n\tnew_irq->ticks = 0;\n\treturn 0;\n}\n\nint unregister_irq(int num, const struct interrupt *old_irq)\n{\n\tstruct interrupt **irq, *prev_irq;\n\n\tif(num < 0  || num >= NR_IRQS) {\n\t\treturn -EINVAL;\n\t}\n\n\tirq = &irq_table[num];\n\tprev_irq = NULL;\n\n\twhile(*irq) {\n\t\tif(*irq == old_irq) {\n\t\t\tif((*irq)->next) {\n\t\t\t\tprintk(\"WARNING: %s(): cannot unregister interrupt %d.\\n\", __FUNCTION__, num);\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\t*irq = NULL;\n\t\t\tif(prev_irq) {\n\t\t\t\tprev_irq->next = NULL;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tprev_irq = *irq;\n\t\tirq = &(*irq)->next;\n\t}\n\treturn 0;\n}\n\nvoid add_bh(struct bh *new)\n{\n\tunsigned int flags;\n\tstruct bh **b;\n\n\tSAVE_FLAGS(flags); CLI();\n\n\tb = &bh_table;\n\twhile(*b) {\n\t\tb = &(*b)->next;\n\t}\n\t*b = new;\n\n\tRESTORE_FLAGS(flags);\n}\n\n/* each ISR points to this function (interrupts are disabled) */\nvoid irq_handler(int num, struct sigcontext sc)\n{\n\tstruct interrupt *irq;\n\n\tdisable_irq(num);\n\n\tirq = irq_table[num];\n\n\t/* spurious interrupt treatment */\n\tif(!irq) {\n\t\tspurious_interrupt(num);\n\t\tgoto end;\n\t}\n\n\tack_pic_irq(num);\n\n\tkstat.irqs++;\n\tirq->ticks++;\n\tdo {\n\t\tirq->handler(num, &sc);\n\t\tirq = irq->next;\n\t} while(irq);\n\nend:\n\tenable_irq(num);\n}\n\nvoid unknown_irq_handler(void)\n{\n\tprintk(\"Unknown IRQ received!\\n\");\n\treturn;\n}\n\n/* execute bottom halves (interrupts are enabled) */\nvoid do_bh(struct sigcontext sc)\n{\n\tstruct bh *b;\n\tvoid (*fn)(struct sigcontext *);\n\n\tb = bh_table;\n\twhile(b) {\n\t\tif(b->flags & BH_ACTIVE) {\n\t\t\tb->flags &= ~BH_ACTIVE;\n\t\t\tfn = b->fn;\n\t\t\t(*fn)(&sc);\n\t\t}\n\t\tb = b->next;\n\t}\n}\n\nvoid irq_init(void)\n{\n\tmemset_b(irq_table, 0, sizeof(irq_table));\n}\n"
  },
  {
    "path": "kernel/kexec.c",
    "content": "/*\n * fiwix/kernel/kexec.c\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Copyright (C) 2019-2024 mintsuki and contributors, Limine project.\n * Copyright 2023-2024, Richard R. Masters.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/system.h>\n#include <fiwix/config.h>\n#include <fiwix/kexec.h>\n#include <fiwix/segments.h>\n#include <fiwix/mm.h>\n#include <fiwix/sched.h>\n#include <fiwix/ramdisk.h>\n#include <fiwix/multiboot1.h>\n#include <fiwix/linuxboot.h>\n#include <fiwix/bios.h>\n#include <fiwix/i386elf.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#ifdef CONFIG_KEXEC\n\nint kexec_proto;\nint kexec_size;\nchar kexec_cmdline[NAME_MAX + 1];\n\nstatic void _memcpy_b(void *dest, const void *src, unsigned int count)\n{\n\tunsigned char *d, *s;\n\n\ts = (unsigned char *)src;\n\td = (unsigned char *)dest;\n\twhile(count--) {\n\t\t*d = *s;\n\t\td++;\n\t\ts++;\n\t}\n}\n\nstatic void _memset_b(void *dest, unsigned char value, unsigned int count)\n{\n\tunsigned char *d;\n\n\td = (unsigned char *)dest;\n\twhile(count--) {\n\t\t*d = 0;\n\t\td++;\n\t}\n}\n\nstatic void multiboot1_trampoline(unsigned int ramdisk_addr, unsigned int kernel_addr, int size, struct multiboot_info *info)\n{\n\tstruct elf32_phdr *elf32_ph;\n\tstruct elf32_hdr *elf32_h;\n\tunsigned int start, length, offset;\n\tunsigned int entry_addr;\n\n\tstruct gate_desc idt[64];\n\tstruct desc_r idtr = {\n\t\tsizeof(idt) - 1,\n\t\t(unsigned int)&idt\n\t};\n\n\tstruct seg_desc gdt[3];\n\tstruct desc_r gdtr = {\n\t\tsizeof(gdt) - 1,\n\t\t(unsigned int)&gdt\n\t};\n\n\tint n, cr0;\n\n\n\tCLI();\n\n\t/* invalidate IDT */\n\t_memset_b(&idt, 0, sizeof(idt));\n\t__asm__ __volatile__ (\n\t\t\"lidt %0\\n\\t\"\n\t\t: /* no output */\n\t\t: \"m\"(idtr)\n\t);\n\n\t/* configure a new flat GDT */\n\tgdt[0].sd_lolimit = 0;\n\tgdt[0].sd_lobase = 0;\n\tgdt[0].sd_loflags = 0;\n\tgdt[0].sd_hilimit = 0;\n\tgdt[0].sd_hiflags = 0;\n\tgdt[0].sd_hibase = 0;\n\n\tgdt[1].sd_lolimit = 0xFFFF;\n\tgdt[1].sd_lobase = 0x00000000 & 0xFFFFFF;\n\tgdt[1].sd_loflags = SD_CODE | SD_CD | SD_DPL0 | SD_PRESENT;\n\tgdt[1].sd_hilimit = (0xFFFFFFFF >> 16) & 0x0F;\n\tgdt[1].sd_hiflags = SD_OPSIZE32 | SD_PAGE4KB;\n\tgdt[1].sd_hibase = (0x00000000 >> 24) & 0xFF;\n\n\tgdt[2].sd_lolimit = 0xFFFF;\n\tgdt[2].sd_lobase = 0x00000000 & 0xFFFFFF;\n\tgdt[2].sd_loflags = SD_DATA | SD_CD | SD_DPL0 | SD_PRESENT;\n\tgdt[2].sd_hilimit = (0xFFFFFFFF >> 16) & 0x0F;\n\tgdt[2].sd_hiflags = SD_OPSIZE32 | SD_PAGE4KB;\n\tgdt[2].sd_hibase = (0x00000000 >> 24) & 0xFF;\n\t__asm__ __volatile__ (\n\t\t\"lgdt %0\\n\\t\"\n\t\t: /* no output */\n\t\t: \"m\"(gdtr)\n\t);\n\n\t/* disable paging and others */\n\tcr0 = 0x11;\t/* preserve ET & PE */\n\t__asm__ __volatile__(\n\t\t\"mov\t%0, %%cr0\"\n\t\t: /* no output */\n\t\t: \"r\"(cr0)\n\t);\n\n\t/* flush TLB (needed?) */\n\t__asm__ __volatile__(\n\t\t\"xorl\t%%eax, %%eax\\n\\t\"\n\t\t\"movl\t%%eax, %%cr3\\n\\t\"\n\t\t: /* no output */\n\t\t: /* no input */\n\t\t: \"eax\"\t/* clobbered registers */\n\t);\n\n\t/*\n\t * Clear memory. This is intended to avoid unexpected results if the\n\t * new kernel guesses its uninitialized variables are zeroed.\n\t */\n\t_memset_b(0x0, 0, KEXEC_BOOT_ADDR);\n\t_memset_b((void *)0x100000, 0, ramdisk_addr - 0x100000);\n\n\t/* install the kernel previously stored in RAMdisk by the user */\n\telf32_h = (struct elf32_hdr *)ramdisk_addr;\n\tentry_addr = elf32_h->e_entry;\n\n\tfor(n = 0; n < elf32_h->e_phnum; n++) {\n\t\telf32_ph = (struct elf32_phdr *)(ramdisk_addr + elf32_h->e_phoff + (sizeof(struct elf32_phdr) * n));\n\t\tif(elf32_ph->p_type == PT_LOAD) {\n\t\t\tstart = elf32_ph->p_paddr;\n\t\t\tlength = elf32_ph->p_filesz;\n\t\t\toffset = elf32_ph->p_offset;\n\t\t\t_memcpy_b((void *)start, (unsigned char *)(ramdisk_addr + offset), length);\n\t\t}\n\t}\n\n\t/* flush TLB (needed?) */\n\t__asm__ __volatile__(\n\t\t\"xorl\t%%eax, %%eax\\n\\t\"\n\t\t\"movl\t%%eax, %%cr3\\n\\t\"\n\t\t: /* no output */\n\t\t: /* no input */\n\t\t: \"eax\"\t/* clobbered registers */\n\t);\n\n\t/* load all the segment registers with the kernel data segment value */\n\t__asm__ __volatile__(\n\t\t\"movw\t$0x10, %%ax\\n\\t\"\n\t\t\"movw\t%%ax, %%ds\\n\\t\"\n\t\t\"movw\t%%ax, %%es\\n\\t\"\n\t\t\"movw\t%%ax, %%fs\\n\\t\"\n\t\t\"movw\t%%ax, %%gs\\n\\t\"\n\t\t\"movw\t%%ax, %%ss\\n\\t\"\n\t\t: /* no output */\n\t\t: /* no input */\n\t\t: \"eax\"\t/* clobbered registers */\n\t);\n\n\t/* Multiboot 1 */\n#ifdef __TINYC__\n\tunsigned int multiboot_magic = MULTIBOOT_BOOTLOADER_MAGIC;\n\t__asm__ __volatile__(\n\t\t\"movl\t%0, %%eax\\n\\t\"\n\t\t\"movl\t%1, %%ebx\\n\\t\"\n\t\t: /* no output */\n\t\t: \"r\"(multiboot_magic), \"r\"((unsigned int)info)\n\t);\n#else\n\t__asm__ __volatile__(\n\t\t\"movl\t%0, %%eax\\n\\t\"\n\t\t\"movl\t%1, %%ebx\\n\\t\"\n\t\t: /* no output */\n\t\t: \"eax\"(MULTIBOOT_BOOTLOADER_MAGIC), \"ebx\"((unsigned int)info)\n\t);\n#endif\n\n\t/*\n\t * This jumps to the kernel entry address.\n\t *\n\t * i.e.: ljmp $0x08, $entry_addr\n\t */\n\t__asm__ __volatile__(\n\t\t\"pushw\t$0x08\\n\\t\"\n\t\t\"pushl\t%0\\n\\t\"\n\t\t\"ljmp\t*(%%esp)\\n\\t\"\n\t\t: /* no output */\n\t\t: \"c\"(entry_addr)\n\t);\n\n\t/* not reached */\n}\n\nvoid kexec_multiboot1(void)\n{\n\tunsigned int *esp, ramdisk_addr;\n\tstruct proc *idle, *prev;\n\tstruct multiboot_info *info;\n\tstruct multiboot_mmap_entry *map, *map_orig;\n\tstruct elf32_hdr *elf32_h;\n\tchar *cmdline;\n\tchar *boot_loader_name;\n\tint n, nmaps;\n\n\tCLI();\n\n\tramdisk_addr = (unsigned int)ramdisk_table[ramdisk_minors - 1].addr;\n\telf32_h = (struct elf32_hdr *)ramdisk_addr;\n\tif(check_elf(elf32_h)) {\n\t\tprintk(\"WARNING: %s(): unrecognized i386 binary ELF.\\n\", __FUNCTION__);\n\t\treturn;\n\t}\n\n\t/* the IDLE process will do the job */\n\tidle = &proc_table[IDLE];\n\tidle->tss.eip = (unsigned int)KEXEC_BOOT_ADDR;\n\n\tmap_kaddr((unsigned int *)P2V(current->tss.cr3), KEXEC_BOOT_ADDR, KEXEC_BOOT_ADDR + PAGE_SIZE, 0, PAGE_PRESENT | PAGE_RW);\n\tmap_kaddr((unsigned int *)P2V(idle->tss.cr3), KEXEC_BOOT_ADDR, KEXEC_BOOT_ADDR + PAGE_SIZE, 0, PAGE_PRESENT | PAGE_RW);\n\tinvalidate_tlb();\n\n\tmemcpy_b((void *)KEXEC_BOOT_ADDR, multiboot1_trampoline, PAGE_SIZE);\n\n\t/* stack starts at the end of the page */\n\tesp = (unsigned int *)(KEXEC_BOOT_ADDR + PAGE_SIZE - 4);\n\n\t/* space reserved for the cmdline string (256 bytes) */\n\tesp -= 256 / sizeof(unsigned int);\n\tcmdline = (char *)esp;\n\tsprintk(cmdline, \"%s %s\", UTS_SYSNAME, kexec_cmdline);\n\n\t/* space reserved for the boot_loader_name string (16 bytes) */\n\tesp -= 16 / sizeof(unsigned int);\n\tboot_loader_name = (char *)esp;\n\tsprintk(boot_loader_name, \"Fiwix kexec\");\n\n\t/* space reserved for the memory map structure */\n\tnmaps = 0;\n\twhile(bios_mem_map[nmaps].type) {\n\t\tnmaps++;\n\t}\n\tesp -= sizeof(struct multiboot_mmap_entry) * nmaps;\n\tmap_orig = map = (struct multiboot_mmap_entry *)esp;\n\t/* setup the memory map */\n\tfor(n = 0; n < nmaps; n++) {\n\t\tmap->size = sizeof(struct multiboot_mmap_entry) - sizeof(map->size);\n\t\tmap->addr = bios_mem_map[n].from_hi;\n\t\tmap->addr = map->addr << 32 | bios_mem_map[n].from;\n\t\tmap->len = bios_mem_map[n].to_hi;\n\t\tmap->len = map->len << 32 | bios_mem_map[n].to;\n\t\tmap->len -= map->addr;\n\t\tmap->type = bios_mem_map[n].type;\n\t\tmap++;\n\t}\n\n\t/* space reserved for the multiboot_info structure */\n\tesp -= sizeof(struct multiboot_info) / sizeof(unsigned int);\n\tmemset_b(esp, 0, sizeof(struct multiboot_info));\n\tinfo = (struct multiboot_info *)esp;\n\n\t/* setup Multiboot structure */\n\tinfo->flags = MULTIBOOT_INFO_MEMORY;\n\tinfo->mem_lower = kparm_memsize;\n\tinfo->mem_upper = kparm_extmemsize;\n\tinfo->flags |= MULTIBOOT_INFO_CMDLINE;\n\tinfo->cmdline = (unsigned int)cmdline;\n\tinfo->flags |= MULTIBOOT_INFO_BOOT_LOADER_NAME;\n\tinfo->boot_loader_name = (unsigned int)boot_loader_name;\n\tinfo->flags |= MULTIBOOT_INFO_MEM_MAP;\n\tinfo->mmap_length = sizeof(struct multiboot_mmap_entry) * nmaps;\n\tinfo->mmap_addr = (unsigned int)map_orig;\n\tesp--;\n\n\t/* now put the four parameters into the stack */\n\t*esp = (unsigned int)info;\n\tesp--;\n\t*esp = kexec_size * 1024;\n\tesp--;\n\t*esp = KERNEL_ADDR;\n\tesp--;\n\t*esp = V2P(ramdisk_addr);\n\tesp--;\n\tidle->tss.esp = (unsigned int)esp;\n\n\tprintk(\"%s(): jumping to multiboot1_trampoline() ...\\n\", __FUNCTION__);\n\tprev = current;\n\tset_tss(idle);\n\tdo_switch(&prev->tss.esp, &prev->tss.eip, idle->tss.esp, idle->tss.eip, idle->tss.cr3, TSS);\n\t/* not reached */\n\treturn;\n}\n\nstatic void linux_trampoline(char *kernel_src_addr, unsigned int kernel_size,\n\t\tchar *initrd_src_addr, unsigned int initrd_size,\n\t\tchar *initrd_dst_addr,\n\t\tstruct boot_params *boot_params)\n{\n\tstruct gate_desc idt[64];\n\tstruct desc_r idtr = {\n\t\tsizeof(idt) - 1,\n\t\t(unsigned int)&idt\n\t};\n\n\tstruct seg_desc gdt[4];\n\tstruct desc_r gdtr = {\n\t\tsizeof(gdt) - 1,\n\t\t(unsigned int)&gdt\n\t};\n\n\tint cr0;\n\n\tCLI();\n\n\t/* invalidate IDT */\n\tchar *dst, *src;\n\tunsigned int len;\n\tfor (dst = (char *)&idt, len = sizeof(idt); len; len--) {\n\t\t*dst++ = 0;\n\t}\n\n\t__asm__ __volatile__ (\n\t\t\"lidt %0\\n\\t\"\n\t\t: /* no output */\n\t\t: \"m\"(idtr)\n\t);\n\n\t/* configure a new flat GDT */\n\tgdt[0].sd_lolimit = 0;\n\tgdt[0].sd_lobase = 0;\n\tgdt[0].sd_loflags = 0;\n\tgdt[0].sd_hilimit = 0;\n\tgdt[0].sd_hiflags = 0;\n\tgdt[0].sd_hibase = 0;\n\n\tgdt[1].sd_lolimit = 0;\n\tgdt[1].sd_lobase = 0;\n\tgdt[1].sd_loflags = 0;\n\tgdt[1].sd_hilimit = 0;\n\tgdt[1].sd_hiflags = 0;\n\tgdt[1].sd_hibase = 0;\n\n\tgdt[2].sd_lolimit = 0xFFFF;\n\tgdt[2].sd_lobase = 0x00000000 & 0xFFFFFF;\n\tgdt[2].sd_loflags = SD_CODE | SD_CD | SD_DPL0 | SD_PRESENT;\n\tgdt[2].sd_hilimit = (0xFFFFFFFF >> 16) & 0x0F;\n\tgdt[2].sd_hiflags = SD_OPSIZE32 | SD_PAGE4KB;\n\tgdt[2].sd_hibase = (0x00000000 >> 24) & 0xFF;\n\n\tgdt[3].sd_lolimit = 0xFFFF;\n\tgdt[3].sd_lobase = 0x00000000 & 0xFFFFFF;\n\tgdt[3].sd_loflags = SD_DATA | SD_CD | SD_DPL0 | SD_PRESENT;\n\tgdt[3].sd_hilimit = (0xFFFFFFFF >> 16) & 0x0F;\n\tgdt[3].sd_hiflags = SD_OPSIZE32 | SD_PAGE4KB;\n\tgdt[3].sd_hibase = (0x00000000 >> 24) & 0xFF;\n\t__asm__ __volatile__ (\n\t\t\"lgdt %0\\n\\t\"\n\t\t: /* no output */\n\t\t: \"m\"(gdtr)\n\t);\n\n\t/* disable paging and others */\n\tcr0 = 0x11;\t/* preserve ET & PE */\n\t__asm__ __volatile__(\n\t\t\"mov\t%0, %%cr0\"\n\t\t: /* no output */\n\t\t: \"r\"(cr0)\n\t);\n\n\t/* flush TLB (needed?) */\n\t__asm__ __volatile__(\n\t\t\"xorl\t%%eax, %%eax\\n\\t\"\n\t\t\"movl\t%%eax, %%cr3\\n\\t\"\n\t\t: /* no output */\n\t\t: /* no input */\n\t\t: \"eax\"\t/* clobbered registers */\n\t);\n\n\t/* Note that below we avoid using _memset_b and _memcpy_b because we cannot\n\t * make function calls because this trampoline has been relocated.\n\t */\n\n\t/*\n\t * Clear memory. This is intended to avoid unexpected results if the\n\t * new kernel guesses its uninitialized variables are zeroed.\n\t */\n\tfor (dst = (char *)0, len = KEXEC_BOOT_ADDR; len; len--) {\n\t\t*dst++ = 0;\n\t}\n\n\tfor (dst = (char *)0x100000, len = (unsigned int)kernel_src_addr - 0x100000; len; len--) {\n\t\t*dst++ = 0;\n\t}\n\n\t/* install the kernel previously stored in RAMdisk by the user */\n\tfor (dst = (char *)0x100000, src = kernel_src_addr, len = kernel_size; len; len--) {\n\t\t*dst++ = *src++;\n\t}\n\n\t/* install the ramdisk previously stored in RAMdisk by the user */\n\tfor (dst = (char *)initrd_dst_addr, src = initrd_src_addr, len = initrd_size; len; len--) {\n\t\t*dst++ = *src++;\n\t}\n\n\t/* flush TLB (needed?) */\n\t__asm__ __volatile__(\n\t\t\"xorl\t%%eax, %%eax\\n\\t\"\n\t\t\"movl\t%%eax, %%cr3\\n\\t\"\n\t\t: /* no output */\n\t\t: /* no input */\n\t\t: \"eax\"\t/* clobbered registers */\n\t);\n\n\t/* load all the segment registers with the kernel data segment value */\n\t__asm__ __volatile__(\n\t\t\"movw\t$0x18, %%ax\\n\\t\"\n\t\t\"movw\t%%ax, %%ds\\n\\t\"\n\t\t\"movw\t%%ax, %%es\\n\\t\"\n\t\t\"movw\t%%ax, %%fs\\n\\t\"\n\t\t\"movw\t%%ax, %%gs\\n\\t\"\n\t\t\"movw\t%%ax, %%ss\\n\\t\"\n\t\t: /* no output */\n\t\t: /* no input */\n\t\t: \"eax\"\t/* clobbered registers */\n\t);\n\n\t/* Linux boot */\n#ifdef __TINYC__\n\t__asm__ __volatile__(\n\t\t\"movl\t%0, %%eax\\n\\t\"\n\t\t\"movl\t%%eax, %%esi\\n\\t\"\n\t\t: /* no output */\n\t\t: \"r\"((unsigned int)boot_params)\n\t);\n#else\n\t__asm__ __volatile__(\n\t\t\"movl\t%0, %%eax\\n\\t\"\n\t\t\"movl\t%%eax, %%esi\\n\\t\"\n\t\t: /* no output */\n\t\t: \"eax\"((unsigned int)boot_params)\n\t);\n#endif\n\n\t/*\n\t * This jumps to the kernel entry address.\n\t *\n\t */\n\t__asm__ __volatile__(\n\t\t\"pushw\t$0x10\\n\\t\"\n\t\t\"pushl\t%0\\n\\t\"\n\t\t\"ljmp\t*(%%esp)\\n\\t\"\n\t\t: /* no output */\n\t\t: \"c\"(KERNEL_ADDR)\n\t);\n\n\t/* not reached */\n}\n\n\nvoid kexec_linux(void)\n{\n\tstruct proc *idle, *prev;\n\tunsigned int *esp;\n\tchar *kernel_src_addr, *initrd_src_addr;\n\t__u32 kernel_size, initrd_size;\n\tstruct boot_params *boot_params;\n\tchar *cmdline;\n\n\tkernel_size = *((__u32 *)ramdisk_table[ramdisk_minors - 1].addr);\n\tprintk(\"kexec_linux: kernel file size: %u\\n\", kernel_size);\n\tinitrd_size = *((__u32 *) (ramdisk_table[ramdisk_minors - 1].addr + sizeof(__u32)));\n\n\t/* space reserved for the memory map structure */\n\tkernel_src_addr = ramdisk_table[ramdisk_minors - 1].addr + (sizeof(__u32) * 2);\n\n\t__u32 signature;\n\tmemcpy_b(&signature, kernel_src_addr + 0x202, sizeof(__u32));\n\n\t/* validate signature */\n\tif (signature != 0x53726448) {\n\t\tprintk(\"kexec_linux: Invalid kernel signature\\n\");\n\t\treturn;\n\t} else {\n\t\tprintk(\"kexec_linux: Valid kernel signature\\n\");\n\t}\n\n\t__size_t setup_code_size = 0;\n\tmemcpy_b(&setup_code_size, kernel_src_addr + 0x1f1, 1);\n\tif (setup_code_size == 0) {\n\t\tsetup_code_size = 4;\n\t}\n\tsetup_code_size *= 512;\n\n\t__size_t real_mode_code_size = 512 + setup_code_size;\n\n\t/* the IDLE process will do the job */\n\tidle = &proc_table[IDLE];\n\tidle->tss.eip = (unsigned int)KEXEC_BOOT_ADDR;\n\n\tmap_kaddr((unsigned int *)P2V(current->tss.cr3), KEXEC_BOOT_ADDR, KEXEC_BOOT_ADDR + (PAGE_SIZE * 2), 0, PAGE_PRESENT | PAGE_RW);\n\tmap_kaddr((unsigned int *)P2V(idle->tss.cr3), KEXEC_BOOT_ADDR, KEXEC_BOOT_ADDR + (PAGE_SIZE * 2), 0, PAGE_PRESENT | PAGE_RW);\n\tinvalidate_tlb();\n\n\tmemcpy_b((void *)KEXEC_BOOT_ADDR, linux_trampoline, PAGE_SIZE);\n\n\t/* stack starts at the end of the page */\n\tesp = (unsigned int *)(KEXEC_BOOT_ADDR + (PAGE_SIZE * 2) - 4);\n\n\t/* space reserved for the cmdline string (256 bytes) */\n\tesp -= 256 / sizeof(unsigned int);\n\tcmdline = (char *)esp;\n\tstrcpy(cmdline, kexec_cmdline);\n\n\t/* space reserved for the boot_params structure */\n\tesp -= sizeof(struct boot_params) / sizeof(unsigned int);\n\tmemset_b(esp, 0, sizeof(struct boot_params));\n\tboot_params = (struct boot_params *)esp;\n\n\tstruct setup_header *setup_header = &boot_params->hdr;\n\n\t__size_t setup_header_end = ({\n\t\t__u8 x;\n\t\tmemcpy_b(&x, kernel_src_addr + 0x201, 1);\n\t\t0x202 + x;\n\t});\n\n\tmemcpy_b(setup_header, kernel_src_addr + 0x1f1, setup_header_end - 0x1f1);\n\n\tprintk(\"kexec_linux: Boot protocol: %u.%u\\n\",\n\t\tsetup_header->version >> 8, setup_header->version & 0xff);\n\n\tif (setup_header->version < 0x203) {\n\t\tprintk(\"kexec_linux: Protocols < 2.03 are not supported\");\n\t\treturn;\n\t}\n\n\tsetup_header->cmdline_addr = (__u32)(unsigned int *)cmdline;\n\n\t/* video_mode. 0xffff means \"normal\" */\n\tsetup_header->video_mode = 0xffff;\n\n\t/* 0xff means this loader does not have an assigned id */\n\tsetup_header->loader_type = 0xff;\n\n\tif (!(setup_header->load_flags & (1 << 0))) {\n\t\tprintk(\"kexec_linux: Kernels that load at 0x10000 are not supported\");\n\t\treturn;\n\t}\n\n\tsetup_header->load_flags &= ~(1 << 5);     /* print early messages */\n\n\t/* Modules */\n\n\t__u32 modules_mem_base = setup_header->initramfs_addr_max;\n\tif (modules_mem_base == 0) {\n\t\tmodules_mem_base = 0x38000000;\n\t}\n\n\tinitrd_src_addr = kernel_src_addr + kernel_size;\n\n\tmodules_mem_base -= initrd_size;\n\n\tif (initrd_size) {\n\t\tsetup_header->initramfs_addr = (__u32)modules_mem_base;\n\t} else {\n\t\tsetup_header->initramfs_addr = 0;\n\t}\n\tsetup_header->initramfs_size  = (__u32)initrd_size;\n\n\tstruct screen_info *screen_info = &boot_params->screen_info;\n\n\tscreen_info->mode = 3;\n\tscreen_info->ega_bx = 3;\n\tscreen_info->lines = 25;\n\tscreen_info->cols = 80;\n\tscreen_info->points = 16;\n\n\tscreen_info->is_vga = IS_VGA_VGA_COLOR;\n\n\t/* e820 bios memory entries */\n\n\tstruct bios_mem_entry *bios_mem_table = boot_params->bios_mem_table;\n\n\t__size_t i, j;\n\tfor (i = 0, j = 0; i < NR_BIOS_MM_ENT; i++) {\n                if(!bios_mem_map[i].type || bios_mem_map[i].type > 0x1000) {\n\t\t\tcontinue;\n\t\t}\n\t\tbios_mem_table[j].addr = bios_mem_map[i].from_hi;\n\t\tbios_mem_table[j].addr = (bios_mem_table[j].addr << 32) | bios_mem_map[i].from;\n\t\tbios_mem_table[j].size = bios_mem_map[i].to_hi;\n\t\tbios_mem_table[j].size = (bios_mem_table[j].size << 32) | bios_mem_map[i].to;\n\t\tbios_mem_table[j].size -= bios_mem_table[j].addr;\n\t\tbios_mem_table[j].type = bios_mem_map[i].type;\n\t\tj++;\n\t\tboot_params->num_bios_mem_entries = j;\n\t}\n\n\t/* now put the six parameters into the stack */\n\tesp--;\n\t*esp = (unsigned int)boot_params;\n\tesp--;\n\t*esp = modules_mem_base;\n\tesp--;\n\t*esp = initrd_size;\n\tesp--;\n\t*esp = (unsigned int)V2P(initrd_src_addr);\n\tesp--;\n\t*esp = (kernel_size - real_mode_code_size);\n\tesp--;\n\t*esp = (unsigned int)V2P(kernel_src_addr + real_mode_code_size);\n\tesp--;\n\tidle->tss.esp = (unsigned int)esp;\n\n\tprintk(\"kexec_linux: boot_params: %x\\n\", boot_params);\n\tprintk(\"kexec_linux: modules_mem_base: %x\\n\", modules_mem_base);\n\tprintk(\"kexec_linux: initrd_size: %u\\n\", initrd_size);\n\tprintk(\"kexec_linux: initrd_src_addr: %x\\n\", initrd_src_addr);\n\tprintk(\"kexec_linux: initrd_src_addr: %x\\n\", V2P(initrd_src_addr));\n\tprintk(\"kexec_linux: kernel_size: %u\\n\", kernel_size - real_mode_code_size);\n\tprintk(\"kexec_linux: kernel_src_addr: %x\\n\", kernel_src_addr + real_mode_code_size);\n\tprintk(\"kexec_linux: kernel_src_addr: %x\\n\", V2P(kernel_src_addr + real_mode_code_size));\n\n\tprintk(\"kexec_linux: jumping to linux_trampoline() ...\\n\");\n\tprev = current;\n\tset_tss(idle);\n\tdo_switch(&prev->tss.esp, &prev->tss.eip, idle->tss.esp, idle->tss.eip, idle->tss.cr3, TSS);\n\t/* not reached */\n\treturn;\n}\n\n#endif /* CONFIG_KEXEC */\n"
  },
  {
    "path": "kernel/main.c",
    "content": "/*\n * fiwix/kernel/main.c\n *\n * Copyright 2018-2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/limits.h>\n#include <fiwix/kparms.h>\n#include <fiwix/fs.h>\n#include <fiwix/system.h>\n#include <fiwix/version.h>\n#include <fiwix/utsname.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n#include <fiwix/video.h>\n#include <fiwix/console.h>\n#include <fiwix/pci.h>\n#include <fiwix/pic.h>\n#include <fiwix/irq.h>\n#include <fiwix/segments.h>\n#include <fiwix/devices.h>\n#include <fiwix/buffer.h>\n#include <fiwix/cpu.h>\n#include <fiwix/timer.h>\n#include <fiwix/sleep.h>\n#include <fiwix/locks.h>\n#include <fiwix/ps2.h>\n#include <fiwix/keyboard.h>\n#include <fiwix/sched.h>\n#include <fiwix/mm.h>\n#include <fiwix/kexec.h>\n#include <fiwix/sysconsole.h>\n\nstruct kernel_params kparms;\nstruct kernel_stat kstat;\nunsigned int _last_data_addr;\n\nstruct new_utsname sys_utsname = {\n\tUTS_SYSNAME,\n\tUTS_NODENAME,\n\tUTS_RELEASE,\n\tUTS_VERSION,\n\t\"\",\n\tUTS_DOMAINNAME,\n};\n\nstatic void set_default_values(void)\n{\n\t/* filesystem is ext2 */\n\tif(!kparms.rootfstype[0]) {\n\t\tstrcpy(kparms.rootfstype, \"ext2\");\n\t}\n\n\t/* console is /dev/tty0 */\n\tif(!kparms.syscondev) {\n\t\tkparms.syscondev = MKDEV(VCONSOLES_MAJOR, 0);\n\t\tadd_sysconsoledev(kparms.syscondev);\n\t}\n}\n\nvoid start_kernel(unsigned int magic, unsigned int info, unsigned int last_boot_addr)\n{\n\tstruct proc *init;\n\n\t_last_data_addr = last_boot_addr - PAGE_OFFSET;\n\tmemset_b(&kstat, 0, sizeof(kstat));\n\tsysconsole_init();\n\n#ifdef CONFIG_QEMU_DEBUGCON\n\tif(inport_b(QEMU_DEBUG_PORT) == QEMU_DEBUG_PORT) {\n\t\tkstat.flags |= KF_HAS_DEBUGCON;\n\t}\n#endif /* CONFIG_QEMU_DEBUGCON */\n\n\tprintk(\"                       Fiwix v%s for i386 architecture\\n\", UTS_RELEASE);\n\tprintk(\"                     Copyright (c) 2018-2025, Jordi Sanfeliu\\n\");\n\tprintk(\"\\n\");\n#ifdef __TINYC__\n\tprintk(\"             (built on %s with tcc)\\n\", UTS_VERSION);\n#else\n\tprintk(\"             (built on %s with GCC %s)\\n\", UTS_VERSION, __VERSION__);\n#endif\n\tprintk(\"\\n\");\n\tprintk(\"DEVICE    ADDRESS         IRQ   COMMENT\\n\");\n\tprintk(\"--------------------------------------------------------------------------------\\n\");\n\n\tcpu_init();\n\tmultiboot(magic, info);\n\tset_default_values();\n\tpic_init();\n\tirq_init();\n\tidt_init();\n\tdev_init();\n\ttty_init();\n\tmem_init();\n\n#ifdef CONFIG_PCI\n\tpci_init();\n#endif /* CONFIG_PCI */\n\n\tvideo_init();\n\tconsole_init();\n\ttimer_init();\n\tps2_init();\n\tproc_init();\n\tsleep_init();\n\tbuffer_init();\n\tsched_init();\n\tinode_init();\n\tfd_init();\n\n\t/*\n\t * IDLE is now the current process (created manually as PID 0),\n\t * it won't be placed in the running queue.\n\t */\n\tcurrent = get_proc_free();\n\tproc_slot_init(current);\n\tset_tss(current);\n\tload_tr(TSS);\n\tcurrent->tss.cr3 = V2P((unsigned int)kpage_dir);\n\tcurrent->flags |= PF_KPROC;\n\tsprintk(current->argv0, \"%s\", \"idle\");\n\n\t/* PID 1 is for the INIT process */\n\tinit = get_proc_free();\n\tproc_slot_init(init);\n\tinit->pid = get_unused_pid();\n\n\tkernel_process(\"kswapd\", kswapd);\t/* PID 2 */\n\tkernel_process(\"kbdflushd\", kbdflushd);\t/* PID 3 */\n\n\t/* kswapd will take over the rest of the kernel initialization */\n\tneed_resched = 1;\n\n\tSTI();\t\t/* let's rock! */\n\tcpu_idle();\n}\n\nvoid stop_kernel(void)\n{\n\tstruct proc *p, *next;\n\tint n;\n\n\t/* put all processes to sleep and reset all pending signals */\n\tFOR_EACH_PROCESS_RUNNING(p) {\n\t\tnext = p->next_run;\n\t\tnot_runnable(p, PROC_SLEEPING);\n\t\tp->sigpending = 0;\n\t\tp = next;\n\t}\n\n#ifdef CONFIG_KEXEC\n\tif(!(kstat.flags & KF_HAS_PANICKED)) {\n\t\tif(kexec_size > 0) {\n\t\t\tswitch(kexec_proto) {\n\t\t\t\tcase KEXEC_MULTIBOOT1:\n\t\t\t\t\tkexec_multiboot1();\n\t\t\t\t\tbreak;\n\t\t\t\tcase KEXEC_LINUX:\n\t\t\t\t\tkexec_linux();\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n#endif /* CONFIG_KEXEC */\n\n\tprintk(\"\\n\");\n\tprintk(\"**    Safe to Power Off    **\\n\");\n\tprintk(\"            -or-\\n\");\n\tprintk(\"** Press Any Key to Reboot **\\n\");\n\tany_key_to_reboot = 1;\n\n\t/* stop and disable all interrupts! */\n\tCLI();\n\tfor(n = 0; n < NR_IRQS; n++) {\n\t\tdisable_irq(n);\n\t}\n\n\t/* enable keyboard only */\n\tenable_irq(KEYBOARD_IRQ);\n\tSTI();\n\n\tcpu_idle();\n}\n\nvoid cpu_idle(void)\n{\n\tfor(;;) {\n\t\tif(need_resched) {\n\t\t\tdo_sched();\n\t\t}\n\t\tHLT();\n\t}\n}\n"
  },
  {
    "path": "kernel/multiboot.c",
    "content": "/*\n * fiwix/kernel/multiboot.c\n *\n * Copyright 2021-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/config.h>\n#include <fiwix/kernel.h>\n#include <fiwix/multiboot1.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n#include <fiwix/limits.h>\n#include <fiwix/kparms.h>\n#include <fiwix/i386elf.h>\n#include <fiwix/ramdisk.h>\n#include <fiwix/kexec.h>\n#include <fiwix/mm.h>\n#include <fiwix/bios.h>\n#include <fiwix/vgacon.h>\n#include <fiwix/fb.h>\n#include <fiwix/fbcon.h>\n#include <fiwix/sysconsole.h>\n\nchar bios_data[256];\n\nstatic struct kernel_params_value kparamval_table[] = {\n#ifdef CONFIG_BGA\n\t{ \"bga=\",\n\t   { \"640x480x32\", \"800x600x32\", \"1024x768x32\" },\n\t   { 0 }\n\t},\n#endif /* CONFIG_BGA */\n\t{ \"console=\",\n\t   { \"/dev/tty0\", \"/dev/tty1\", \"/dev/tty2\", \"/dev/tty3\", \"/dev/tty4\",\n\t     \"/dev/tty5\", \"/dev/tty6\", \"/dev/tty7\", \"/dev/tty8\", \"/dev/tty9\",\n\t     \"/dev/tty10\", \"/dev/tty11\", \"/dev/tty12\",\n\t     \"/dev/ttyS0\", \"/dev/ttyS1\", \"/dev/ttyS2\", \"/dev/ttyS3\"\n\t   },\n\t   { 0x400, 0x401, 0x402, 0x403, 0x404,\n\t     0x405, 0x406, 0x407, 0x408, 0x409,\n\t     0x40A, 0x40B, 0x40C,\n\t     0x440, 0x441, 0x442, 0x443\n\t   }\n\t},\n\t{ \"ide_nodma\",\n\t   { 0 },\n\t   { 0 }\n\t},\n\t{ \"initrd=\",\n\t   { 0 },\n\t   { 0 }\n\t},\n#ifdef CONFIG_KEXEC\n\t{ \"kexec_proto=\",\n\t   { \"multiboot1\", \"linux\" },\n\t   { 1, 2 }\n\t},\n\t{ \"kexec_size=\",\n\t   { 0 },\n\t   { 0 }\n\t},\n\t{ \"kexec_cmdline=\",\n\t   { 0 },\n\t   { 0 }\n\t},\n#endif /* CONFIG_KEXEC */\n\t{ \"ps2_noreset\",\n\t   { 0 },\n\t   { 0 }\n\t},\n\t{ \"ramdisksize=\",\n\t   { 0 },\n\t   { 0 }\n\t},\n\t{ \"ro\",\n\t   { 0 },\n\t   { 0 }\n\t},\n\t{ \"root=\",\n\t   { \"/dev/ram0\", \"/dev/fd0\", \"/dev/fd1\",\n\t     \"/dev/hda\", \"/dev/hda1\", \"/dev/hda2\", \"/dev/hda3\", \"/dev/hda4\",\n\t     \"/dev/hdb\", \"/dev/hdb1\", \"/dev/hdb2\", \"/dev/hdb3\", \"/dev/hdb4\",\n\t     \"/dev/hdc\", \"/dev/hdc1\", \"/dev/hdc2\", \"/dev/hdc3\", \"/dev/hdc4\",\n\t     \"/dev/hdd\", \"/dev/hdd1\", \"/dev/hdd2\", \"/dev/hdd3\", \"/dev/hdd4\",\n\t   },\n\t   { 0x100, 0x200, 0x201,\n\t     0x300, 0x301, 0x302, 0x303, 0x304,\n\t     0x340, 0x341, 0x342, 0x343, 0x344,\n\t     0x1600, 0x1601, 0x1602, 0x1603, 0x1604,\n\t     0x1640, 0x1641, 0x1642, 0x1643, 0x1644,\n\t   }\n\t},\n\t{ \"rootfstype=\",\n\t   { \"minix\", \"ext2\", \"iso9660\" },\n\t   { 0 }\n\t},\n\n\t{ NULL }\n};\n\nchar kernel_cmdline[NAME_MAX + 1];\nElf32_Shdr *symtab, *strtab;\n\n/* check the validity of a command line parameter */\nstatic int check_param(struct kernel_params_value *kpv, const char *value)\n{\n\tint n;\n\n#ifdef CONFIG_PCI\n#ifdef CONFIG_BGA\n\tif(!strcmp(kpv->name, \"bga=\")) {\n\t\tfor(n = 0; kpv->value[n]; n++) {\n\t\t\tif(!strcmp(kpv->value[n], value)) {\n\t\t\t\tstrncpy(kparms.bgaresolution, value, 14);\n\t\t\t\tkparms.bgaresolution[14] = '\\0';\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t\treturn 1;\n\t}\n#endif /* CONFIG_BGA */\n#endif /* CONFIG_PCI */\n\tif(!strcmp(kpv->name, \"console=\")) {\n\t\tfor(n = 0; kpv->value[n]; n++) {\n\t\t\tif(!strcmp(kpv->value[n], value)) {\n\t\t\t\tif(kpv->sysval[n]) {\n\t\t\t\t\tif(add_sysconsoledev(kpv->sysval[n])) {\n\t\t\t\t\t\tkparms.syscondev = kpv->sysval[n];\n\t\t\t\t\t} else {\n\t\t\t\t\t\tprintk(\"WARNING: console device '%s' exceeds NR_SYSCONSOLES.\\n\", value);\n\t\t\t\t\t}\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t\tprintk(\"WARNING: device name for '%s' is not defined!\\n\", kpv->name);\n\t\t\t}\n\t\t}\n\t\treturn 1;\n\t}\n\tif(!strcmp(kpv->name, \"ide_nodma\")) {\n\t\tkparms.flags |= KPARMS_IDE_NODMA;\n\t\treturn 0;\n\t}\n\tif(!strcmp(kpv->name, \"initrd=\")) {\n\t\tif(value[0]) {\n\t\t\tstrncpy(kparms.initrd, value, DEVNAME_MAX);\n\t\t\treturn 0;\n\t\t}\n\t}\n#ifdef CONFIG_KEXEC\n\tif(!strcmp(kpv->name, \"kexec_proto=\")) {\n\t\tfor(n = 0; kpv->value[n]; n++) {\n\t\t\tif(!strcmp(kpv->value[n], value)) {\n\t\t\t\tif(kpv->sysval[n]) {\n\t\t\t\t\tkexec_proto = kpv->sysval[n];\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t\tprintk(\"WARNING: kexec protocol '%s' is not defined!\\n\", kpv->name);\n\t\t\t}\n\t\t}\n\t\treturn 1;\n\t}\n\tif(!strcmp(kpv->name, \"kexec_size=\")) {\n\t\tif(value[0]) {\n\t\t\tkexec_size = atoi(value);\n\t\t\treturn 0;\n\t\t}\n\t\treturn 1;\n\t}\n\tif(!strcmp(kpv->name, \"kexec_cmdline=\")) {\n\t\tif(value[0]) {\n\t\t\t/* copy the provided cmdline and also remove quotes */\n\t\t\tstrncpy(kexec_cmdline, value + 1, MIN(strlen(value) - 2, NAME_MAX));\n\t\t\treturn 0;\n\t\t}\n\t\treturn 1;\n\t}\n#endif /* CONFIG_KEXEC */\n\tif(!strcmp(kpv->name, \"ps2_noreset\")) {\n\t\tkparms.flags |= KPARMS_PS2_NORESET;\n\t\treturn 0;\n\t}\n\tif(!strcmp(kpv->name, \"ramdisksize=\")) {\n\t\tkparms.ramdisksize = atoi(value);\n\t\tramdisk_minors = RAMDISK_DRIVES;\n\t\treturn 0;\n\t}\n\tif(!strcmp(kpv->name, \"ro\")) {\n\t\tkparms.ro = 1;\n\t\treturn 0;\n\t}\n\tif(!strcmp(kpv->name, \"root=\")) {\n\t\tfor(n = 0; kpv->value[n]; n++) {\n\t\t\tif(!strcmp(kpv->value[n], value)) {\n\t\t\t\tkparms.rootdev = kpv->sysval[n];\n\t\t\t\tstrncpy(kparms.rootdevname, value, DEVNAME_MAX);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t\treturn 1;\n\t}\n\tif(!strcmp(kpv->name, \"rootfstype=\")) {\n\t\tfor(n = 0; kpv->value[n]; n++) {\n\t\t\tif(!strcmp(kpv->value[n], value)) {\n\t\t\t\tstrncpy(kparms.rootfstype, value, sizeof(kparms.rootfstype));\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t\treturn 1;\n\t}\n\tprintk(\"WARNING: the parameter '%s' looks valid but it's not defined!\\n\", kpv->name);\n\treturn 0;\n}\n\nstatic int parse_arg(const char *arg)\n{\n\tint n;\n\tconst char *value;\n\n\t/* '--' marks the beginning of the init arguments */\n\tif(!strcmp(arg, \"--\")) {\n\t\treturn 1;\n\t}\n\n\t/* find out where the value starts (if it exists) */\n\tvalue = arg;\n\twhile(*value && *value != '=') {\n\t\tvalue++;\n\t}\n\tif(*value) {\n\t\tvalue++;\n\t}\n\n\tfor(n = 0; kparamval_table[n].name; n++) {\n\t\tif(!strncmp(arg, kparamval_table[n].name, value ? value - arg : strlen(arg))) {\n\t\t\tif(check_param(&kparamval_table[n], value)) {\n\t\t\t\tprintk(\"WARNING: invalid value '%s' in the '%s' parameter.\\n\", value, kparamval_table[n].name);\n\t\t\t}\n\t\t\treturn 0;\n\t\t}\n\t}\n\tprintk(\"WARNING: invalid cmdline parameter: '%s'.\\n\", arg);\n\treturn 0;\n}\n\nstatic char *parse_cmdline(const char *str)\n{\n\tchar *from, *to;\n\tchar arg[CMDL_ARG_LEN];\n\tchar c;\n\tint open, close, incomplete;\n\n\tfrom = to = (char *)str;\n\topen = close = 0;\n\tfor(;;) {\n\t\tc = *(str++);\n\t\tif(c == '\"') {\n\t\t\tif(open) {\n\t\t\t\tclose = 1;\n\t\t\t}\n\t\t\topen = 1;\n\t\t}\n\t\tincomplete = open - close;\n\n\t\tif((c == ' ' || !c) && !incomplete) {\n\t\t\tif(to - from < CMDL_ARG_LEN) {\n\t\t\t\tmemcpy_b(arg, from, to - from);\n\t\t\t\targ[to - from] = 0;\n\t\t\t\tif(arg[0] != 0) {\n\t\t\t\t\tif(parse_arg(arg)) {\n\t\t\t\t\t\twhile(*(from++)) {\n\t\t\t\t\t\t\tif(*from != '-' && *from != ' ') {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn from;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tmemcpy_b(arg, from, CMDL_ARG_LEN);\n\t\t\t\targ[CMDL_ARG_LEN - 1] = 0;\n\t\t\t\tprintk(\"WARNING: invalid length of the cmdline parameter '%s'.\\n\", arg);\n\t\t\t}\n\t\t\tfrom = ++to;\n\t\t\tif(!c) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tto++;\n\t}\n\n\treturn NULL;\n}\n\n#ifdef CONFIG_BGA\nstatic void parse_bgaresolution(void)\n{\n\tchar str[5], *p;\n\tint n;\n\n\tn = 0;\n\tfor(;;) {\n\t\tp = &str[0];\n\t\twhile(kparms.bgaresolution[n] && kparms.bgaresolution[n] != 'x') {\n\t\t\t*p = kparms.bgaresolution[n];\n\t\t\tp++;\n\t\t\tn++;\n\t\t}\n\t\t*p = '\\0';\n\t\tif(!video.fb_width) {\n\t\t\tvideo.fb_width = atoi(str);\n\t\t} else if(!video.fb_height) {\n\t\t\tvideo.fb_height = atoi(str);\n\t\t} else if(!video.fb_bpp) {\n\t\t\tvideo.fb_bpp = atoi(str);\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t\tn++;\n\t}\n}\n#endif /* CONFIG_BGA */\n\n/*\n * This function returns the last address used by kernel symbols or the value\n * of 'mod_end' (in the module structure) of the last module loaded by GRUB.\n *\n * In the case where there are no ELF header tables, then it returns the last\n * .bss address plus one page.\n *\n * This is intended to place the kernel stack beyond all these addresses.\n */\nunsigned int get_last_boot_addr(unsigned int magic, unsigned int info)\n{\n\tstruct multiboot_info *mbi;\n\tElf32_Shdr *shdr;\n\tstruct multiboot_elf_section_header_table *hdr;\n\tstruct multiboot_mod_list *mod;\n\tunsigned short int n;\n\tunsigned int addr;\n\n\tif(magic != MULTIBOOT_BOOTLOADER_MAGIC) {\n\t\taddr = ((unsigned int)_end & PAGE_MASK) + PAGE_SIZE;\n\t\treturn P2V(addr);\n\t}\n\n\tmbi = (struct multiboot_info *)info;\n\n\t/* ELF header tables */\n\tif(mbi->flags & MULTIBOOT_INFO_ELF_SHDR) {\n\t\tsymtab = strtab = NULL;\n\t\thdr = &(mbi->u.elf_sec);\n\t\tfor(n = 0; n < hdr->num; n++) {\n\t\t\tshdr = (Elf32_Shdr *)(hdr->addr + (n * hdr->size));\n\t\t\tif(shdr->sh_type == SHT_SYMTAB) {\n\t\t\t\tsymtab = shdr;\n\t\t\t}\n\t\t\tif(shdr->sh_type == SHT_STRTAB) {\n\t\t\t\tstrtab = shdr;\n\t\t\t}\n\t\t}\n\n\t\taddr = strtab->sh_addr + strtab->sh_size;\n\t} else {\n\t\taddr = ((unsigned int)_end & PAGE_MASK) + PAGE_SIZE;\n\t}\n\n\t/*\n\t * https://www.gnu.org/software/grub/manual/multiboot/multiboot.html\n\t *\n\t * Check if GRUB has loaded some modules and, if so, get the last\n\t * address used by the last one.\n\t */\n\tif(mbi->flags & MULTIBOOT_INFO_MODS) {\n\t\tmod = (struct multiboot_mod_list *)mbi->mods_addr;\n\t\tfor(n = 0; n < mbi->mods_count; n++, mod++) {\n\t\t\taddr = mod->mod_end;\n\t\t}\n\t}\n\n\treturn P2V(addr);\n}\n\nvoid multiboot(unsigned int magic, unsigned int info)\n{\n\tstruct multiboot_info mbi;\n\n\tmemset_b(&video, 0, sizeof(struct video_parms));\n\tmemset_b(&ramdisk_table, 0, sizeof(ramdisk_table));\n\tramdisk_minors = 0;\n\n\t/* save the BIOS Data Area (BDA) */\n\tmemcpy_b(bios_data, (unsigned char *)(PAGE_OFFSET + 0x400), 256);\n\n\tif(magic != MULTIBOOT_BOOTLOADER_MAGIC) {\n\t\tprintk(\"WARNING: invalid multiboot magic number: 0x%x. Assuming 4MB of RAM.\\n\", magic);\n\t\tmemset_b(&mbi, 0, sizeof(struct multiboot_info));\n\t\tkparms.memsize = 640;\n\t\tkparms.extmemsize = 3072;\n\t\tbios_map_init(NULL, 0);\n\t\tvideo.columns = 80;\n\t\tvideo.lines = 25;\n\t\tvideo.flags = VPF_VGA;\n\t\tvideo.memsize = 384 * 1024;\n\t\treturn;\n\t}\n\n\tmemcpy_b(&mbi, (void *)info, sizeof(struct multiboot_info));\n\n\tif(mbi.flags & MULTIBOOT_INFO_BOOT_LOADER_NAME) {\n\t\tprintk(\"bootloader                  -\\t%s\\n\", mbi.boot_loader_name);\n\t}\n\n\tif(!(mbi.flags & MULTIBOOT_INFO_MEMORY)) {\n\t\tprintk(\"WARNING: values in mem_lower and mem_upper are not valid!\\n\");\n\t}\n\tkparms.memsize = (unsigned int)mbi.mem_lower;\n\tkparms.extmemsize = (unsigned int)mbi.mem_upper;\n\n\n\tif(mbi.flags & MULTIBOOT_INFO_CMDLINE) {\n\t\tint n, len;\n\t\tchar c;\n\t\tchar *p;\n\n\t\tp = (char *)mbi.cmdline;\n\t\tlen = strlen(p);\n\t\t/* suppress 'fiwix' */\n\t\tfor(n = 0; n < len; n++) {\n\t\t\tc = *(p++);\n\t\t\tif(c == ' ') {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tstrcpy(kernel_cmdline, p);\n\t\tinit_args = parse_cmdline(kernel_cmdline);\n\t} else {\n\t\tprintk(\"WARNING: no cmdline detected!\\n\");\n\t}\n\tprintk(\"kernel    0x%08x        -\\tcmdline='%s'\\n\", KERNEL_ADDR, kernel_cmdline);\n\n\n\tif(mbi.flags & MULTIBOOT_INFO_MODS) {\n\t\tunsigned int n, size;\n\t\tstruct multiboot_mod_list *mod;\n\n\t\tmod = (struct multiboot_mod_list *)mbi.mods_addr;\n\t\tfor(n = 0; n < mbi.mods_count; n++, mod++) {\n\t\t\tif(!strcmp((char *)mod->cmdline, kparms.initrd)) {\n\t\t\t\tprintk(\"initrd    0x%08x-0x%08x file='%s' size=%dKB\\n\", mod->mod_start, mod->mod_end, mod->cmdline, (mod->mod_end - mod->mod_start) / 1024);\n\t\t\t\tsize = mod->mod_end - mod->mod_start;\n\t\t\t\tramdisk_table[0].addr = (char *)mod->mod_start;\n\t\t\t\tramdisk_table[0].size = size / 1024;\n\t\t\t\tramdisk_minors++;\n\t\t\t}\n\t\t}\n\t}\n\n\n\tif(!(mbi.flags & MULTIBOOT_INFO_ELF_SHDR)) {\n\t\tprintk(\"WARNING: ELF section header table is not valid!\\n\");\n\t}\n\n\tif(mbi.flags & MULTIBOOT_INFO_MEM_MAP) {\n\t\tbios_map_init((struct multiboot_mmap_entry *)mbi.mmap_addr, mbi.mmap_length);\n\t} else {\n\t\tbios_map_init(NULL, 0);\n\t}\n\n\tif(mbi.flags & MULTIBOOT_INFO_VBE_INFO) {\n\t\tstruct vbe_controller *vbec;\n\t\tstruct vbe_mode *vbem;\n\n\t\tvbec = (struct vbe_controller *)mbi.vbe_control_info;\n\t\tvbem = (struct vbe_mode *)mbi.vbe_mode_info;\n\n\t\tvideo.flags = VPF_VESAFB;\n\t\tvideo.address = (unsigned int *)vbem->phys_base;\n\t\tvideo.port = 0;\n\t\tvideo.memsize = vbec->total_memory * vbem->win_size * 1024;\n\t\tstrcpy((char *)video.signature, (char *)vbec->signature);\n\t\tvideo.columns = vbem->x_resolution / vbem->x_char_size;\n\t\tvideo.lines = vbem->y_resolution / vbem->y_char_size;\n\t\tvideo.fb_version = vbec->version;\n\t\tvideo.fb_width = vbem->x_resolution;\n\t\tvideo.fb_height = vbem->y_resolution;\n\t\tvideo.fb_char_width = vbem->x_char_size;\n\t\tvideo.fb_char_height = vbem->y_char_size;\n\t\tvideo.fb_bpp = vbem->bits_per_pixel;\n\t\tvideo.fb_pixelwidth = vbem->bits_per_pixel / 8;\n\t\tvideo.fb_pitch = vbem->bytes_per_scanline;\n\t\tvideo.fb_linesize = video.fb_pitch * video.fb_char_height;\n\t\tvideo.fb_size = vbem->x_resolution * vbem->y_resolution * video.fb_pixelwidth;\n\t\tvideo.fb_vsize = video.lines * video.fb_pitch * video.fb_char_height;\n\t}\n\n#ifdef CONFIG_BGA\n\tif(*kparms.bgaresolution) {\n\t\tvideo.flags = VPF_VESAFB;\n\t\tparse_bgaresolution();\n\t\tvideo.fb_char_width = 8;\n\t\tvideo.fb_char_height = 16;\n\t\tvideo.columns = video.fb_width / video.fb_char_width;\n\t\tvideo.lines = video.fb_height / video.fb_char_height;\n\t}\n#endif /* CONFIG_BGA */\n\n\tif(!video.flags) {\n\t\t/* fallback to standard VGA */\n\t\tvideo.flags = VPF_VGA;\n\t\tvideo.columns = 80;\n\t\tvideo.lines = 25;\n\t\tvideo.memsize = 384 * 1024;\n\t}\n}\n"
  },
  {
    "path": "kernel/pic.c",
    "content": "/*\n * fiwix/kernel/pic.c\n *\n * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/config.h>\n#include <fiwix/pic.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n/* interrupt vector base addresses */\n#define IRQ0_ADDR\t0x20\n#define IRQ8_ADDR\t0x28\n\n/*\n * This sends the command OCW3 to PIC (master or slave) to obtain the register\n * values. Slave is chained and represents IRQs 8-15. Master represents IRQs\n * 0-7, with IRQ 2 being the chain.\n */\nstatic unsigned short int pic_get_irq_reg(int ocw3)\n{\n\toutport_b(PIC_MASTER, ocw3);\n\toutport_b(PIC_SLAVE, ocw3);\n\treturn (inport_b(PIC_SLAVE) << 8) | inport_b(PIC_MASTER);\n}\n\nvoid enable_irq(int irq)\n{\n\tint addr;\n\n\taddr = (irq > 7) ? PIC_SLAVE + DATA : PIC_MASTER + DATA;\n\tirq &= 0x0007;\n\n\toutport_b(addr, inport_b(addr) & ~(1 << irq));\n}\n\nvoid disable_irq(int irq)\n{\n\tint addr;\n\n\taddr = (irq > 7) ? PIC_SLAVE + DATA : PIC_MASTER + DATA;\n\tirq &= 0x0007;\n\n\toutport_b(addr, inport_b(addr) | (1 << irq));\n}\n\nvoid spurious_interrupt(int irq)\n{\n\tint real;\n\n\t/* spurious interrupt treatment */\n\treal = pic_get_irq_reg(PIC_READ_ISR);\n\tif(!real) {\n\t\t/*\n\t\t * If IRQ was not real and came from slave, then send\n\t\t * an EOI to master because it doesn't know if the IRQ\n\t\t * was a spurious interrupt from slave.\n\t\t */\n\t\tif(irq > 7) {\n\t\t\toutport_b(PIC_MASTER, EOI);\n\t\t}\n\t\tif(kstat.sirqs < MAX_SPU_NOTICES) {\n\t\t\tprintk(\"WARNING: spurious interrupt detected (unregistered IRQ %d).\\n\", irq);\n\t\t} else if(kstat.sirqs == MAX_SPU_NOTICES) {\n\t\t\tprintk(\"WARNING: too many spurious interrupts; not logging any more.\\n\");\n\t\t}\n\t\tkstat.sirqs++;\n\t\treturn;\n\t}\n\tack_pic_irq(irq);\n}\n\nvoid ack_pic_irq(int irq)\n{\n\tif(irq > 7) {\n\t\toutport_b(PIC_SLAVE, EOI);\n\t}\n\toutport_b(PIC_MASTER, EOI);\n}\n\nvoid pic_init(void)\n{\n\t/* remap interrupts for PIC1 */\n\toutport_b(PIC_MASTER, ICW1_RESET);\n\toutport_b(PIC_MASTER + DATA, IRQ0_ADDR);\t/* ICW2 */\n\toutport_b(PIC_MASTER + DATA, 1 << CASCADE_IRQ);\t/* ICW3 */\n\toutport_b(PIC_MASTER + DATA, ICW4_8086EOI);\n\n\t/* remap interrupts for PIC2 */\n\toutport_b(PIC_SLAVE, ICW1_RESET);\n\toutport_b(PIC_SLAVE + DATA, IRQ8_ADDR);\t\t/* ICW2 */\n\toutport_b(PIC_SLAVE + DATA, CASCADE_IRQ);\t/* ICW3 */\n\toutport_b(PIC_SLAVE + DATA, ICW4_8086EOI);\n\n\t/* mask all IRQs except cascade */\n\toutport_b(PIC_MASTER + DATA, ~(1 << CASCADE_IRQ));\n\n\t/* mask all IRQs */\n\toutport_b(PIC_SLAVE + DATA, OCW1);\n}\n"
  },
  {
    "path": "kernel/pit.c",
    "content": "/*\n * fiwix/kernel/pit.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/pit.h>\n\nvoid pit_beep_on(void)\n{\n\toutport_b(MODEREG, SEL_CHAN2 | LSB_MSB | SQUARE_WAVE | BINARY_CTR);\n\toutport_b(CHANNEL2, (OSCIL / BEEP_FREQ) & 0xFF);\t/* LSB */\n\toutport_b(CHANNEL2, (OSCIL / BEEP_FREQ) >> 8);\t\t/* MSB */\n\toutport_b(PS2_SYSCTRL_B, inport_b(PS2_SYSCTRL_B) | ENABLE_SDATA | ENABLE_TMR2G);\n}\n\nvoid pit_beep_off(unsigned int unused)\n{\n\toutport_b(PS2_SYSCTRL_B, inport_b(PS2_SYSCTRL_B) & ~(ENABLE_SDATA | ENABLE_TMR2G));\n}\n\nint pit_getcounter0(void)\n{\n\tint count;\n\n\t/* latch counter 0 and read its value */\n\toutport_b(MODEREG, SEL_CHAN0);\n\tcount = inport_b(CHANNEL0);\n\tcount |= inport_b(CHANNEL0) << 8;\n\treturn count;\n}\n\nvoid pit_init(unsigned short int hertz)\n{\n\toutport_b(MODEREG, SEL_CHAN0 | LSB_MSB | RATE_GEN | BINARY_CTR);\n\toutport_b(CHANNEL0, (OSCIL / hertz) & 0xFF);\t/* LSB */\n\toutport_b(CHANNEL0, (OSCIL / hertz) >> 8);\t/* MSB */\n}\n"
  },
  {
    "path": "kernel/process.c",
    "content": "/*\n * fiwix/kernel/process.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/mm.h>\n#include <fiwix/errno.h>\n#include <fiwix/process.h>\n#include <fiwix/timer.h>\n#include <fiwix/sched.h>\n#include <fiwix/sleep.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n#include <fiwix/stddef.h>\n\nstruct proc *proc_table;\nstruct proc *current;\n\nstruct proc *proc_pool_head;\nstruct proc *proc_table_head;\nstruct proc *proc_table_tail;\nunsigned int free_proc_slots = 0;\n\nstatic struct resource slot_resource = { 0, 0 };\nstatic struct resource pid_resource = { 0, 0 };\n\nint nr_processes = 0;\n__pid_t lastpid = 0;\n\n/* sum up child (and its children) statistics */\nvoid add_crusage(struct proc *p, struct rusage *cru)\n{\n\tcru->ru_utime.tv_sec = p->usage.ru_utime.tv_sec + p->cusage.ru_utime.tv_sec;\n\tcru->ru_utime.tv_usec = p->usage.ru_utime.tv_usec + p->cusage.ru_utime.tv_usec;\n\tif(cru->ru_utime.tv_usec >= 1000000) {\n\t\tcru->ru_utime.tv_sec++;\n\t\tcru->ru_utime.tv_usec -= 1000000;\n\t}\n\tcru->ru_stime.tv_sec = p->usage.ru_stime.tv_sec + p->cusage.ru_stime.tv_sec;\n\tcru->ru_stime.tv_usec = p->usage.ru_stime.tv_usec + p->cusage.ru_stime.tv_usec;\n\tif(cru->ru_stime.tv_usec >= 1000000) {\n\t\tcru->ru_stime.tv_sec++;\n\t\tcru->ru_stime.tv_usec -= 1000000;\n\t}\n\tcru->ru_maxrss = p->usage.ru_maxrss + p->cusage.ru_maxrss;\n\tcru->ru_ixrss = p->usage.ru_ixrss + p->cusage.ru_ixrss;\n\tcru->ru_idrss = p->usage.ru_idrss + p->cusage.ru_idrss;\n\tcru->ru_isrss = p->usage.ru_isrss + p->cusage.ru_isrss;\n\tcru->ru_minflt = p->usage.ru_minflt + p->cusage.ru_minflt;\n\tcru->ru_majflt = p->usage.ru_majflt + p->cusage.ru_majflt;\n\tcru->ru_nswap = p->usage.ru_nswap + p->cusage.ru_nswap;\n\tcru->ru_inblock = p->usage.ru_inblock + p->cusage.ru_inblock;\n\tcru->ru_oublock = p->usage.ru_oublock + p->cusage.ru_oublock;\n\tcru->ru_msgsnd = p->usage.ru_msgsnd + p->cusage.ru_msgsnd;\n\tcru->ru_msgrcv = p->usage.ru_msgrcv + p->cusage.ru_msgrcv;\n\tcru->ru_nsignals = p->usage.ru_nsignals + p->cusage.ru_nsignals;\n\tcru->ru_nvcsw = p->usage.ru_nvcsw + p->cusage.ru_nvcsw;\n\tcru->ru_nivcsw = p->usage.ru_nivcsw + p->cusage.ru_nivcsw;\n}\n\nvoid get_rusage(struct proc *p, struct rusage *ru)\n{\n\tstruct rusage cru;\n\n\t/*\n\t * Conforms with SUSv3 which specifies that if SIGCHLD is being ignored\n\t * then the child statistics should not be added to the values returned\n\t * by RUSAGE_CHILDREN.\n\t */\n\tif(current->sigaction[SIGCHLD - 1].sa_handler == SIG_IGN) {\n\t\treturn;\n\t}\n\n\tadd_crusage(p, &cru);\n\tmemcpy_b(ru, &cru, sizeof(struct rusage));\n}\n\n/* add child statistics to parent */\nvoid add_rusage(struct proc *p)\n{\n\tstruct rusage cru;\n\n\tadd_crusage(p, &cru);\n\tcurrent->cusage.ru_utime.tv_sec += cru.ru_utime.tv_sec;\n\tcurrent->cusage.ru_utime.tv_usec += cru.ru_utime.tv_usec;\n\tif(current->cusage.ru_utime.tv_usec >= 1000000) {\n\t\tcurrent->cusage.ru_utime.tv_sec++;\n\t\tcurrent->cusage.ru_utime.tv_usec -= 1000000;\n\t}\n\tcurrent->cusage.ru_stime.tv_sec += cru.ru_stime.tv_sec;\n\tcurrent->cusage.ru_stime.tv_usec += cru.ru_stime.tv_usec;\n\tif(current->cusage.ru_stime.tv_usec >= 1000000) {\n\t\tcurrent->cusage.ru_stime.tv_sec++;\n\t\tcurrent->cusage.ru_stime.tv_usec -= 1000000;\n\t}\n\tcurrent->cusage.ru_maxrss += cru.ru_maxrss;\n\tcurrent->cusage.ru_ixrss += cru.ru_ixrss;\n\tcurrent->cusage.ru_idrss += cru.ru_idrss;\n\tcurrent->cusage.ru_isrss += cru.ru_isrss;\n\tcurrent->cusage.ru_minflt += cru.ru_minflt;\n\tcurrent->cusage.ru_majflt += cru.ru_majflt;\n\tcurrent->cusage.ru_nswap += cru.ru_nswap;\n\tcurrent->cusage.ru_inblock += cru.ru_inblock;\n\tcurrent->cusage.ru_oublock += cru.ru_oublock;\n\tcurrent->cusage.ru_msgsnd += cru.ru_msgsnd;\n\tcurrent->cusage.ru_msgrcv += cru.ru_msgrcv;\n\tcurrent->cusage.ru_nsignals += cru.ru_nsignals;\n\tcurrent->cusage.ru_nvcsw += cru.ru_nvcsw;\n\tcurrent->cusage.ru_nivcsw += cru.ru_nivcsw;\n}\n\nstruct proc *get_next_zombie(struct proc *parent)\n{\n\tstruct proc *p;\n\n\tFOR_EACH_PROCESS(p) {\n\t\tif(p->ppid == parent && p->state == PROC_ZOMBIE) {\n\t\t\treturn p;\n\t\t}\n\t\tp = p->next;\n\t}\n\n\treturn NULL;\n}\n\n__pid_t remove_zombie(struct proc *p)\n{\n\tstruct proc *pp;\n\t__pid_t pid;\n\n\tpid = p->pid;\n\tkfree(p->tss.esp0);\n\tp->rss--;\n\tkfree(P2V(p->tss.cr3));\n\tp->rss--;\n\tpp = p->ppid;\n\trelease_proc(p);\n\tif(pp) {\n\t\tpp->children--;\n\t}\n\treturn pid;\n}\n\n/*\n * An orphaned process group is a process group in which the parent of every\n * member is either itself a member of the group or is not a member of the\n * group's session.\n */\nint is_orphaned_pgrp(__pid_t pgid)\n{\n\tstruct proc *p, *pp;\n\tint retval;\n\n\tretval = 0;\n\tlock_resource(&slot_resource);\n\n\tFOR_EACH_PROCESS(p) {\n\t\tif(p->pgid == pgid) {\n\t\t\tif(p->state != PROC_ZOMBIE) {\n\t\t\t\tpp = p->ppid;\n\t\t\t\t/* return if only one is found that breaks the rule */\n\t\t\t\tif(pp->pgid != pgid || pp->sid == p->sid) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tp = p->next;\n\t}\n\n\tunlock_resource(&slot_resource);\n\treturn retval;\n}\n\nstruct proc *get_proc_free(void)\n{\n\tstruct proc *p = NULL;\n\n\tif(free_proc_slots <= SAFE_SLOTS && !IS_SUPERUSER) {\n\t\tprintk(\"WARNING: %s(): the remaining slots are only for root user!\\n\", __FUNCTION__);\n\t\treturn NULL;\n\t}\n\n\tlock_resource(&slot_resource);\n\n\tif(proc_pool_head) {\n\n\t\t/* get (remove) a process slot from the free list */\n\t\tp = proc_pool_head;\n\t\tproc_pool_head = proc_pool_head->next;\n\n\t\tfree_proc_slots--;\n\t} else {\n\t\tprintk(\"WARNING: %s(): no more slots free in proc table!\\n\", __FUNCTION__);\n\t}\n\n\tunlock_resource(&slot_resource);\n\treturn p;\n}\n\nvoid release_proc(struct proc *p)\n{\n\tlock_resource(&slot_resource);\n\n\t/* remove a process from the proc_table */\n\tif(p == proc_table_tail) {\n\t\tif(proc_table_head == proc_table_tail) {\n\t\t\tproc_table_head = proc_table_tail = NULL;\n\t\t} else {\n\t\t\tproc_table_tail = proc_table_tail->prev;\n\t\t\tproc_table_tail->next = NULL;\n\t\t}\n\t} else {\n\t\tp->prev->next = p->next;\n\t\tp->next->prev = p->prev;\n\t}\n\n\t/* initialize and put a process slot back in the free list */\n\tmemset_b(p, 0, sizeof(struct proc));\n\tp->next = proc_pool_head;\n\tproc_pool_head = p;\n\tfree_proc_slots++;\n\n\tunlock_resource(&slot_resource);\n}\n\nint get_unused_pid(void)\n{\n\tshort int loop;\n\tstruct proc *p;\n\n\tloop = 0;\n\tlock_resource(&pid_resource);\n\nloop:\n\tlastpid++;\n\tif(lastpid > MAX_PID_VALUE) {\n\t\tloop++;\n\t\tlastpid = INIT;\n\t}\n\tif(loop > 1) {\n\t\tprintk(\"WARNING: %s(): system ran out of PID numbers!\\n\");\n\t\treturn 0;\n\t}\n\tFOR_EACH_PROCESS(p) {\n\t\t/*\n\t\t * Make sure the kernel never reuses active pid, pgid\n\t\t * or sid values.\n\t\t */\n\t\tif(lastpid == p->pid || lastpid == p->pgid || lastpid == p->sid) {\n\t\t\tgoto loop;\n\t\t}\n\t\tp = p->next;\n\t}\n\n\tunlock_resource(&pid_resource);\n\treturn lastpid;\n}\n\nstruct proc *get_proc_by_pid(__pid_t pid)\n{\n\tstruct proc *p;\n\n\tFOR_EACH_PROCESS(p) {\n\t\tif(p->pid == pid) {\n\t\t\treturn p;\n\t\t}\n\t\tp = p->next;\n\t}\n\n\treturn NULL;\n}\n\nstruct proc *kernel_process(const char *name, int (*fn)(void))\n{\n\tstruct proc *p;\n\n\tp = get_proc_free();\n\tproc_slot_init(p);\n\tp->pid = get_unused_pid();\n\tp->ppid = &proc_table[IDLE];\n\tp->flags |= PF_KPROC;\n\tp->priority = DEF_PRIORITY;\n\tif(!(p->tss.esp0 = kmalloc(PAGE_SIZE))) {\n\t\trelease_proc(p);\n\t\treturn NULL;\n\t}\n\tp->entry_address = PAGE_OFFSET;\n\tp->end_code = (int)_end;\n\tp->tss.esp0 += PAGE_SIZE - 4;\n\tp->rss++;\n\tp->tss.cr3 = V2P((unsigned int)kpage_dir);\n\tp->tss.eip = (unsigned int)fn;\n\tp->tss.esp = p->tss.esp0;\n\tsprintk(p->pidstr, \"%d\", p->pid);\n\tsprintk(p->argv0, \"%s\", name);\n\trunnable(p);\n\treturn p;\n}\n\nvoid proc_slot_init(struct proc *p)\n{\n\t/* insert process at the end of proc_table */\n\tlock_resource(&slot_resource);\n\tif(proc_table_head == NULL) {\n\t\tp->prev = NULL;\n\t\tp->next = NULL;\n\t\tproc_table_head = proc_table_tail = p;\n\t} else {\n\t\tp->prev = proc_table_tail;\n\t\tp->next = NULL;\n\t\tproc_table_tail->next = p;\n\t\tproc_table_tail = p;\n\t}\n\tp->prev_sleep = p->next_sleep = NULL;\n\tp->prev_run = p->next_run = NULL;\n\tunlock_resource(&slot_resource);\n\n\tmemset_b(&p->tss, 0, sizeof(struct i386tss) - IO_BITMAP_SIZE);\n\tp->tss.io_bitmap_addr = offsetof(struct i386tss, io_bitmap);\n\n\t/* I/O permissions are not inherited by the child */\n\tmemset_l(&p->tss.io_bitmap, ~0, IO_BITMAP_SIZE / sizeof(unsigned int));\n\n\tp->tss.io_bitmap[IO_BITMAP_SIZE] = ~0;\t/* extra byte must be all 1's */\n\tp->state = PROC_IDLE;\n}\n\nvoid proc_init(void)\n{\n\tint n;\n\tstruct proc *p;\n\n\tmemset_b(proc_table, 0, proc_table_size);\n\n\t/* free list initialization */\n\tproc_pool_head = NULL;\n\tn = (proc_table_size / sizeof(struct proc)) - 1;\n\tdo {\n\t\tp = &proc_table[n];\n\n\t\t/* fill the free list */\n\t\tp->next = proc_pool_head;\n\t\tproc_pool_head = p;\n\t\tfree_proc_slots++;\n\t} while(n--);\n\tproc_table_head = proc_table_tail = NULL;\n}\n"
  },
  {
    "path": "kernel/sched.c",
    "content": "/*\n * fiwix/kernel/sched.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/sched.h>\n#include <fiwix/process.h>\n#include <fiwix/sleep.h>\n#include <fiwix/segments.h>\n#include <fiwix/timer.h>\n#include <fiwix/pic.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nextern struct seg_desc gdt[NR_GDT_ENTRIES];\nint need_resched = 0;\n\nstatic void context_switch(struct proc *next)\n{\n\tstruct proc *prev;\n\n\tCLI();\n\tkstat.ctxt++;\n\tprev = current;\n\tset_tss(next);\n\tcurrent = next;\n\tdo_switch(&prev->tss.esp, &prev->tss.eip, next->tss.esp, next->tss.eip, next->tss.cr3, TSS);\n\tSTI();\n}\n\nvoid set_tss(struct proc *p)\n{\n\tstruct seg_desc *g;\n\n\tg = &gdt[TSS / sizeof(struct seg_desc)];\n\n\tg->sd_lobase = (unsigned int)&p->tss;\n\tg->sd_loflags = SD_TSSPRESENT;\n\tg->sd_hibase = (char)(((unsigned int)&p->tss) >> 24);\n}\n\n/* Round Robin algorithm */\nvoid do_sched(void)\n{\n\tint count;\n\tstruct proc *p, *selected;\n\n\t/* let the current running process consume its time slice */\n\tif(current->state == PROC_RUNNING && current->cpu_count > 0) {\n\t\treturn;\n\t}\n\n\tneed_resched = 0;\n\tfor(;;) {\n\t\tcount = -1;\n\t\tselected = &proc_table[IDLE];\n\n\t\tFOR_EACH_PROCESS_RUNNING(p) {\n\t\t\tif(p->cpu_count > count) {\n\t\t\t\tcount = p->cpu_count;\n\t\t\t\tselected = p;\n\t\t\t}\n\t\t\tp = p->next_run;\n\t\t}\n\t\tif(count) {\n\t\t\tbreak;\n\t\t}\n\n\t\t/* reassigns new quantum to all running processes */\n\t\tFOR_EACH_PROCESS_RUNNING(p) {\n\t\t\tp->cpu_count = p->priority;\n\t\t\tp = p->next_run;\n\t\t}\n\t}\n\tif(current != selected) {\n\t\tcontext_switch(selected);\n\t}\n}\n\nvoid sched_init(void)\n{\n\tget_system_time();\n\n\t/* this should be more unpredictable */\n\tkstat.random_seed = CURRENT_TIME;\n}\n"
  },
  {
    "path": "kernel/signal.c",
    "content": "/*\n * fiwix/kernel/signal.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/errno.h>\n#include <fiwix/process.h>\n#include <fiwix/signal.h>\n#include <fiwix/sigcontext.h>\n#include <fiwix/sleep.h>\n#include <fiwix/sched.h>\n#include <fiwix/syscalls.h>\n#include <fiwix/mm.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n/* can process 'current' send a signal to process 'p'? */\nint can_signal(struct proc *p)\n{\n\tif(!IS_SUPERUSER && current->euid != p->euid && current->sid != p->sid) {\n\t\treturn 0;\n\t}\n\n\treturn 1;\n}\n\nint send_sig(struct proc *p, __sigset_t signum)\n{\n\tif(signum > NSIG || !p) {\n\t\treturn -EINVAL;\n\t}\n\n\t/* kernel processes can't receive signals */\n\tif(p->flags & PF_KPROC) {\n\t\treturn 0;\n\t}\n\n\tswitch(signum) {\n\t\tcase 0:\n\t\t\treturn 0;\n\t\tcase SIGKILL:\n\t\tcase SIGCONT:\n\t\t\tif(p->state == PROC_STOPPED) {\n\t\t\t\trunnable(p);\n\t\t\t\tneed_resched = 1;\n\t\t\t}\n\t\t\t/* discard all pending stop signals */\n\t\t\tp->sigpending &= SIG_MASK(SIGSTOP);\n\t\t\tp->sigpending &= SIG_MASK(SIGTSTP);\n\t\t\tp->sigpending &= SIG_MASK(SIGTTIN);\n\t\t\tp->sigpending &= SIG_MASK(SIGTTOU);\n\t\t\tbreak;\n\t\tcase SIGSTOP:\n\t\tcase SIGTSTP:\n\t\tcase SIGTTIN:\n\t\tcase SIGTTOU:\n\t\t\t/* discard all pending SIGCONT signals */\n\t\t\tp->sigpending &= SIG_MASK(SIGCONT);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t}\n\n\t/*\n\t * Force some signals, that a process cannot ignore, by changing its\n\t * signal disposition to SIG_DFL.\n\t */\n\tswitch(signum) {\n\t\tcase SIGFPE:\n\t\tcase SIGSEGV:\n\t\t\tif(p->sigaction[signum - 1].sa_handler == SIG_IGN) {\n\t\t\t\tp->sigaction[signum - 1].sa_handler = SIG_DFL;\n\t\t\t}\n\t\t\tbreak;\n\t}\n\n\tif(p->sigaction[signum - 1].sa_handler == SIG_DFL) {\n\t\t/*\n\t\t * INIT process is special, it only gets signals that have the\n\t\t * signal handler installed. This avoids to bring down the\n\t\t * system accidentally.\n\t\t */\n\t\tif(p->pid == INIT) {\n\t\t\treturn 0;\n\t\t}\n\n\t\t/* these signals with SIG_DFL are ignored */\n\t\tswitch(signum) {\n\t\t\tcase SIGCONT:\n\t\t\tcase SIGWINCH:\n\t\t\tcase SIGCHLD:\n\t\t\tcase SIGURG:\n\t\t\t\treturn 0;\n\t\t}\n\t}\n\n\tif(p->sigaction[signum - 1].sa_handler == SIG_IGN) {\n\t\t/* if SIGCHLD is ignored reap its children (prevent zombies) */\n\t\tif(signum == SIGCHLD) {\n\t\t\twhile(sys_waitpid(-1, NULL, WNOHANG) > 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\treturn 0;\n\t}\n\n\tp->sigpending |= 1 << (signum - 1);\n\tp->usage.ru_nsignals++;\n\n\t/* wake up the process only if the signal is not blocked */\n\tif(!(p->sigblocked & (1 << (signum - 1)))) {\n\t\twakeup_proc(p);\n\t}\n\n\treturn 0;\n}\n\nint issig(void)\n{\n\t__sigset_t signum;\n\tunsigned int mask;\n\tstruct proc *p;\n\n\tif(!(current->sigpending & ~current->sigblocked)) {\n\t\treturn 0;\n\t}\n\n\tfor(signum = 1, mask = 1; signum < NSIG; signum++, mask <<= 1) {\n\t\tif(current->sigpending & mask) {\n\t\t\tif(signum == SIGCHLD) {\n\t\t\t\tif(current->sigaction[signum - 1].sa_handler == SIG_IGN) {\n\t\t\t\t\t/* this process ignores SIGCHLD */\n\t\t\t\t\twhile((p = get_next_zombie(current))) {\n\t\t\t\t\t\tremove_zombie(p);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif(current->sigaction[signum - 1].sa_handler != SIG_DFL) {\n\t\t\t\t\t\treturn signum;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif(current->sigaction[signum - 1].sa_handler != SIG_IGN) {\n\t\t\t\t\treturn signum;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcurrent->sigpending &= ~mask;\n\t\t}\n\t}\n\treturn 0;\n}\n\nvoid psig(unsigned int stack)\n{\n\tint len;\n\t__sigset_t signum;\n\tunsigned int mask;\n\tstruct sigcontext *sc;\n\tstruct proc *p;\n\n\tsc = (struct sigcontext *)stack;\n\tfor(signum = 1, mask = 1; signum < NSIG; signum++, mask <<= 1) {\n\t\tif(current->sigpending & mask) {\n\t\t\tcurrent->sigpending &= ~mask;\n\n\t\t\tif((unsigned int)current->sigaction[signum - 1].sa_handler) {\n\n\t\t\t\t/*\n\t\t\t\t * page_not_present() may have raised a SIGSEGV if it\n\t\t\t\t * detected that this process doesn't have an stack\n\t\t\t\t * region in vma_table.\n\t\t\t\t *\n\t\t\t\t * So, this check is needed to make sure to terminate the\n\t\t\t\t * process now, otherwise the kernel would panic when using\n\t\t\t\t * 'sc->oldesp' during the 'memcpy_b' below.\n\t\t\t\t */\n\t\t\t\tif(!find_vma_region(sc->oldesp)) {\n\t\t\t\t\tprintk(\"WARNING: %s(): no stack region in vma table for process %d. Terminated.\\n\", __FUNCTION__, current->pid);\n\t\t\t\t\tdo_exit(signum);\n\t\t\t\t}\n\n\t\t\t\tcurrent->sigexecuting = mask;\n\t\t\t\tif(!(current->sigaction[signum - 1].sa_flags & SA_NODEFER)) {\n\t\t\t\t\tcurrent->sigblocked |= mask;\n\t\t\t\t}\n\n\t\t\t\t/* save the current sigcontext */\n\t\t\t\tmemcpy_b(&current->sc[signum - 1], sc, sizeof(struct sigcontext));\n\t\t\t\t/* setup the jump to the user signal handler */\n\t\t\t\tlen = ((int)end_sighandler_trampoline - (int)sighandler_trampoline);\n\t\t\t\tsc->oldesp -= len;\n\t\t\t\tsc->oldesp -= 4;\n\t\t\t\tsc->oldesp &= ~3;\t/* round up */\n\t\t\t\tmemcpy_b((void *)sc->oldesp, sighandler_trampoline, len);\n\t\t\t\tsc->ecx = (unsigned int)current->sigaction[signum - 1].sa_handler;\n\t\t\t\tsc->eax= signum;\n\t\t\t\tsc->eip = sc->oldesp;\n\n\t\t\t\tif(current->sigaction[signum - 1].sa_flags & SA_RESETHAND) {\n\t\t\t\t\tcurrent->sigaction[signum - 1].sa_handler = SIG_DFL;\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif(current->sigaction[signum - 1].sa_handler == SIG_DFL) {\n\t\t\t\tswitch(signum) {\n\t\t\t\t\tcase SIGCONT:\n\t\t\t\t\t\trunnable(current);\n\t\t\t\t\t\tneed_resched = 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase SIGSTOP:\n\t\t\t\t\tcase SIGTSTP:\n\t\t\t\t\tcase SIGTTIN:\n\t\t\t\t\tcase SIGTTOU:\n\t\t\t\t\t\tcurrent->exit_code = signum;\n\t\t\t\t\t\tnot_runnable(current, PROC_STOPPED);\n\t\t\t\t\t\tif(!(current->sigaction[signum - 1].sa_flags & SA_NOCLDSTOP)) {\n\t\t\t\t\t\t\tp = current->ppid;\n\t\t\t\t\t\t\tsend_sig(p, SIGCHLD);\n\t\t\t\t\t\t\t/* needed for job control */\n\t\t\t\t\t\t\twakeup(&sys_wait4);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tneed_resched = 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase SIGCHLD:\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tdo_exit(signum);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/* coming from a system call that needs to be restarted */\n\tif(sc->err > 0) {\n\t\tif(sc->eax == -ERESTART) {\n\t\t\tsc->eax = sc->err;\t/* syscall was saved in 'err' */\n\t\t\tsc->eip -= 2;\t\t/* point again to 'int 0x80' */\n\t\t}\n\t}\n}\n\nint kill_pid(__pid_t pid, __sigset_t signum, int sender)\n{\n\tstruct proc *p;\n\n\tFOR_EACH_PROCESS(p) {\n\t\tif(p->pid == pid && p->state != PROC_ZOMBIE) {\n\t\t\tif(sender == USER) {\n\t\t\t\tif(!can_signal(p)) {\n\t\t\t\t\treturn -EPERM;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn send_sig(p, signum);\n\t\t}\n\t\tp = p->next;\n\t}\n\treturn -ESRCH;\n}\n\nint kill_pgrp(__pid_t pgid, __sigset_t signum, int sender)\n{\n\tstruct proc *p;\n\tint found;\n\n\tfound = 0;\n\tFOR_EACH_PROCESS(p) {\n\t\tif(p->pgid == pgid && p->state != PROC_ZOMBIE) {\n\t\t\tif(sender == USER) {\n\t\t\t\tif(!can_signal(p)) {\n\t\t\t\t\tp = p->next;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tsend_sig(p, signum);\n\t\t\tfound = 1;\n\t\t}\n\t\tp = p->next;\n\t}\n\n\tif(!found) {\n\t\treturn -ESRCH;\n\t}\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/sleep.c",
    "content": "/*\n * fiwix/kernel/sleep.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/limits.h>\n#include <fiwix/sleep.h>\n#include <fiwix/sched.h>\n#include <fiwix/signal.h>\n#include <fiwix/process.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#define NR_BUCKETS\t\t(NR_PROCS >= 10 ? (NR_PROCS * 10) / 100 : 1)\n#define SLEEP_HASH(addr)\t((addr) % (NR_BUCKETS))\n\nstruct proc *sleep_hash_table[NR_BUCKETS];\nstruct proc *proc_run_head;\nstatic unsigned int area = 0;\n\nvoid runnable(struct proc *p)\n{\n\tunsigned int flags;\n\n\tif(p->state == PROC_RUNNING) {\n\t\tprintk(\"WARNING: %s(): process with pid '%d' is already running!\\n\", __FUNCTION__, p->pid);\n\t\treturn;\n\t}\n\n\tSAVE_FLAGS(flags); CLI();\n\tif(proc_run_head) {\n\t\tp->next_run = proc_run_head;\n\t\tproc_run_head->prev_run = p;\n\t}\n\tproc_run_head = p;\n\tp->state = PROC_RUNNING;\n\tRESTORE_FLAGS(flags);\n}\n\nvoid not_runnable(struct proc *p, int state)\n{\n\tunsigned int flags;\n\n\tSAVE_FLAGS(flags); CLI();\n\tif(p->next_run) {\n\t\tp->next_run->prev_run = p->prev_run;\n\t}\n\tif(p->prev_run) {\n\t\tp->prev_run->next_run = p->next_run;\n\t}\n\tif(p == proc_run_head) {\n\t\tproc_run_head = p->next_run;\n\t}\n\tp->prev_run = p->next_run = NULL;\n\tp->state = state;\n\tRESTORE_FLAGS(flags);\n}\n\nint sleep(void *address, int state)\n{\n\tunsigned int flags;\n\tstruct proc **h;\n\tint signum, i;\n\n\tSAVE_FLAGS(flags); CLI();\n\n\t/* return if it has signals */\n\tif(state == PROC_INTERRUPTIBLE) {\n\t\tif((signum = issig())) {\n\t\t\tRESTORE_FLAGS(flags);\n\t\t\treturn signum;\n\t\t}\n\t}\n\n\tif(current->state == PROC_SLEEPING) {\n\t\tprintk(\"WARNING: %s(): process with pid '%d' is already sleeping!\\n\", __FUNCTION__, current->pid);\n\t\tRESTORE_FLAGS(flags);\n\t\treturn 0;\n\t}\n\n\ti = SLEEP_HASH((unsigned int)address);\n\th = &sleep_hash_table[i];\n\n\t/* insert process in the head */\n\tif(!*h) {\n\t\t*h = current;\n\t\t(*h)->prev_sleep = (*h)->next_sleep = NULL;\n\t} else {\n\t\tcurrent->prev_sleep = NULL;\n\t\tcurrent->next_sleep = *h;\n\t\t(*h)->prev_sleep = current;\n\t\t*h = current;\n\t}\n\tcurrent->sleep_address = address;\n\tif(state == PROC_UNINTERRUPTIBLE) {\n\t\tcurrent->flags |= PF_NOTINTERRUPT;\n\t}\n\tnot_runnable(current, PROC_SLEEPING);\n\n\tdo_sched();\n\n\tsignum = 0;\n\tif(state == PROC_INTERRUPTIBLE) {\n\t\tsignum = issig();\n\t}\n\n\tRESTORE_FLAGS(flags);\n\treturn signum;\n}\n\nvoid wakeup(void *address)\n{\n\tunsigned int flags;\n\tstruct proc **h;\n\tint i, found;\n\n\tSAVE_FLAGS(flags); CLI();\n\ti = SLEEP_HASH((unsigned int)address);\n\th = &sleep_hash_table[i];\n\tfound = 0;\n\n\twhile(*h) {\n\t\tif((*h)->sleep_address == address) {\n\t\t\t(*h)->sleep_address = NULL;\n\t\t\t(*h)->flags &= ~PF_NOTINTERRUPT;\n\t\t\t(*h)->cpu_count = (*h)->priority;\n\t\t\trunnable(*h);\n\t\t\tfound = 1;\n\t\t\tif((*h)->next_sleep) {\n\t\t\t\t(*h)->next_sleep->prev_sleep = (*h)->prev_sleep;\n\t\t\t}\n\t\t\tif((*h)->prev_sleep) {\n\t\t\t\t(*h)->prev_sleep->next_sleep = (*h)->next_sleep;\n\t\t\t}\n\t\t\tif(h == &sleep_hash_table[i]) {\t/* if it's the head */\n\t\t\t\t*h = (*h)->next_sleep;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\th = &(*h)->next_sleep;\n\t}\n\tRESTORE_FLAGS(flags);\n\tif(found) {\n\t\tneed_resched = 1;\n\t}\n}\n\nvoid wakeup_proc(struct proc *p)\n{\n\tunsigned int flags;\n\tstruct proc **h;\n\tint i;\n\n\tif(p->state != PROC_SLEEPING && p->state != PROC_STOPPED) {\n\t\treturn;\n\t}\n\n\t/* return if the process is not interruptible */\n\tif(p->flags & PF_NOTINTERRUPT) {\n\t\treturn;\n\t}\n\n\tSAVE_FLAGS(flags); CLI();\n\n\t/* stopped processes don't have sleep address */\n\tif(p->sleep_address) {\n\t\tif(p->next_sleep) {\n\t\t\tp->next_sleep->prev_sleep = p->prev_sleep;\n\t\t}\n\t\tif(p->prev_sleep) {\n\t\t\tp->prev_sleep->next_sleep = p->next_sleep;\n\t\t}\n\n\t\ti = SLEEP_HASH((unsigned int)p->sleep_address);\n\t\th = &sleep_hash_table[i];\n\n\t\tif(*h == p) {\t/* if it's the head */\n\t\t\t*h = (*h)->next_sleep;\n\t\t}\n\t}\n\tp->sleep_address = NULL;\n\tp->cpu_count = p->priority;\n\trunnable(p);\n\tneed_resched = 1;\n\n\tRESTORE_FLAGS(flags);\n}\n\nvoid lock_resource(struct resource *resource)\n{\n\tunsigned int flags;\n\n\tfor(;;) {\n\t\tSAVE_FLAGS(flags); CLI();\n\t\tif(resource->locked) {\n\t\t\tresource->wanted = 1;\n\t\t\tRESTORE_FLAGS(flags);\n\t\t\tsleep(resource, PROC_UNINTERRUPTIBLE);\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t}\n\tresource->locked = 1;\n\tRESTORE_FLAGS(flags);\n}\n\nvoid unlock_resource(struct resource *resource)\n{\n\tunsigned int flags;\n\n\tSAVE_FLAGS(flags); CLI();\n\tresource->locked = 0;\n\tif(resource->wanted) {\n\t\tresource->wanted = 0;\n\t\twakeup(resource);\n\t}\n\tRESTORE_FLAGS(flags);\n}\n\nint can_lock_area(unsigned int type)\n{\n\tunsigned int flags;\n\tint retval;\n\n\tSAVE_FLAGS(flags); CLI();\n\tretval = area & type;\n\tarea |= type;\n\tRESTORE_FLAGS(flags);\n\n\treturn !retval;\n}\n\nint unlock_area(unsigned int type)\n{\n\tunsigned int flags;\n\tint retval;\n\n\tSAVE_FLAGS(flags); CLI();\n\tretval = area & type;\n\tarea &= ~type;\n\tRESTORE_FLAGS(flags);\n\n\treturn retval;\n}\n\nvoid sleep_init(void)\n{\n\tproc_run_head = NULL;\n\tmemset_b(sleep_hash_table, 0, sizeof(sleep_hash_table));\n}\n"
  },
  {
    "path": "kernel/syscalls/Makefile",
    "content": "# fiwix/kernel/syscalls/Makefile\n#\n# Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n# Distributed under the terms of the Fiwix License.\n#\n\n.c.o:\n\t$(CC) $(CFLAGS) -c -o $@ $<\n\nSRC = $(wildcard *.c)\nOBJS = $(patsubst %.c,%.o,$(SRC))\n\nall:\t$(OBJS)\n\nclean:\n\trm -f *.o\n\n"
  },
  {
    "path": "kernel/syscalls/access.c",
    "content": "/*\n * fiwix/kernel/syscalls/access.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_access(const char *filename, __mode_t mode)\n{\n\tstruct inode *i;\n\tchar *tmp_name;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_access('%s', %d)\", current->pid, filename, mode);\n#endif /*__DEBUG__ */\n\n\tif((mode & S_IRWXO) != mode) {\n\t\treturn -EINVAL;\n\t}\n\tif((errno = malloc_name(filename, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\tcurrent->flags |= PF_USEREAL;\n\tif((errno = namei(tmp_name, &i, NULL, FOLLOW_LINKS))) {\n\t\tcurrent->flags &= ~PF_USEREAL;\n\t\tfree_name(tmp_name);\n\t\treturn errno;\n\t}\n\tif(mode & TO_WRITE) {\n\t\tif(S_ISREG(i->i_mode) || S_ISDIR(i->i_mode) || S_ISLNK(i->i_mode)) {\n\t\t\tif(IS_RDONLY_FS(i)) {\n\t\t\t\tcurrent->flags &= ~PF_USEREAL;\n\t\t\t\tiput(i);\n\t\t\t\tfree_name(tmp_name);\n\t\t\t\treturn -EROFS;\n\t\t\t}\n\t\t}\n\t}\n\terrno = check_permission(mode, i);\n\n#ifdef __DEBUG__\n\tprintk(\" -> returning %d\\n\", errno);\n#endif /*__DEBUG__ */\n\n\tcurrent->flags &= ~PF_USEREAL;\n\tiput(i);\n\tfree_name(tmp_name);\n\treturn errno;\n}\n"
  },
  {
    "path": "kernel/syscalls/alarm.c",
    "content": "/*\n * fiwix/kernel/syscalls/alarm.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/time.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_alarm(unsigned int secs)\n{\n\tstruct itimerval value, ovalue;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_alarm(%d)\\n\", current->pid, secs);\n#endif /*__DEBUG__ */\n\n\tvalue.it_interval.tv_sec = 0;\n\tvalue.it_interval.tv_usec = 0;\n\tvalue.it_value.tv_sec = secs;\n\tvalue.it_value.tv_usec = 0;\n\tsetitimer(ITIMER_REAL, &value, &ovalue);\n\n\t/* \n\t * If there are still some usecs left and since the return value has\n\t * not enough granularity for them, then just add 1 second to it.\n\t */\n\tif(ovalue.it_value.tv_usec) {\n\t\tovalue.it_value.tv_sec++;\n\t}\n\n\treturn ovalue.it_value.tv_sec;\n}\n"
  },
  {
    "path": "kernel/syscalls/brk.c",
    "content": "/*\n * fiwix/kernel/syscalls/brk.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/process.h>\n#include <fiwix/mm.h>\n#include <fiwix/mman.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_brk(unsigned int brk)\n{\n\tunsigned int newbrk;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_brk(0x%08x) -> \", current->pid, brk);\n#endif /*__DEBUG__ */\n\n\tif(!brk || brk < current->brk_lower) {\n#ifdef __DEBUG__\n\t\tprintk(\"0x%08x\\n\", current->brk);\n#endif /*__DEBUG__ */\n\t\treturn current->brk;\n\t}\n\n\tnewbrk = PAGE_ALIGN(brk);\n\tif(newbrk == current->brk || newbrk < current->brk_lower) {\n#ifdef __DEBUG__\n\t\tprintk(\"0x%08x\\n\", current->brk);\n#endif /*__DEBUG__ */\n\t\treturn brk;\n\t}\n\n\tif(brk < current->brk) {\n\t\tdo_munmap(newbrk, current->brk - newbrk);\n\t\tcurrent->brk = brk;\n#ifdef __DEBUG__\n\t\tprintk(\"0x%08x\\n\", current->brk);\n#endif /*__DEBUG__ */\n\t\treturn current->brk;\n\t}\n\tif(!expand_heap(newbrk)) {\n\t\tcurrent->brk = brk;\n\t} else {\n\t\treturn -ENOMEM;\n\t}\n#ifdef __DEBUG__\n\tprintk(\"0x%08x\\n\", current->brk);\n#endif /*__DEBUG__ */\n\treturn current->brk;\n}\n"
  },
  {
    "path": "kernel/syscalls/chdir.c",
    "content": "/*\n * fiwix/kernel/syscalls/chdir.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_chdir(const char *dirname)\n{\n\tstruct inode *i;\n\tchar *tmp_name;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_chdir('%s')\\n\", current->pid, dirname);\n#endif /*__DEBUG__ */\n\n\tif((errno = malloc_name(dirname, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = namei(tmp_name, &i, NULL, FOLLOW_LINKS))) {\n\t\tfree_name(tmp_name);\n\t\treturn errno;\n\t}\n\tif(!S_ISDIR(i->i_mode)) {\n\t\tiput(i);\n\t\tfree_name(tmp_name);\n\t\treturn -ENOTDIR;\n\t}\n\tif((errno = check_permission(TO_EXEC, i))) {\n\t\tiput(i);\n\t\tfree_name(tmp_name);\n\t\treturn errno;\n\t}\n\tiput(current->pwd);\n\tcurrent->pwd = i;\n\tfree_name(tmp_name);\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/chmod.c",
    "content": "/*\n * fiwix/kernel/syscalls/chmod.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/kernel.h>\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_chmod(const char *filename, __mode_t mode)\n{\n\tstruct inode *i;\n\tchar *tmp_name;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_chmod('%s', %d)\\n\", current->pid, filename, mode);\n#endif /*__DEBUG__ */\n\n\tif((errno = malloc_name(filename, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = namei(tmp_name, &i, NULL, FOLLOW_LINKS))) {\n\t\tfree_name(tmp_name);\n\t\treturn errno;\n\t}\n\n\tif(IS_RDONLY_FS(i)) {\n\t\tiput(i);\n\t\tfree_name(tmp_name);\n\t\treturn -EROFS;\n\t}\n\tif(check_user_permission(i)) {\n\t\tiput(i);\n\t\tfree_name(tmp_name);\n\t\treturn -EPERM;\n\t}\n\n\ti->i_mode &= S_IFMT;\n\ti->i_mode |= mode & ~S_IFMT;\n\ti->i_ctime = CURRENT_TIME;\n\ti->state |= INODE_DIRTY;\n\tiput(i);\n\tfree_name(tmp_name);\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/chown.c",
    "content": "/*\n * fiwix/kernel/syscalls/chown.c\n *\n * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/kernel.h>\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_chown(const char *filename, __uid_t owner, __gid_t group)\n{\n\tstruct inode *i;\n\tchar *tmp_name;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_chown('%s', %d, %d)\\n\", current->pid, filename, owner, group);\n#endif /*__DEBUG__ */\n\n\tif((errno = malloc_name(filename, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = namei(tmp_name, &i, NULL, FOLLOW_LINKS))) {\n\t\tfree_name(tmp_name);\n\t\treturn errno;\n\t}\n\n\tif(IS_RDONLY_FS(i)) {\n\t\tiput(i);\n\t\tfree_name(tmp_name);\n\t\treturn -EROFS;\n\t}\n\tif(check_user_permission(i)) {\n\t\tiput(i);\n\t\tfree_name(tmp_name);\n\t\treturn -EPERM;\n\t}\n\n\tif(owner == (__uid_t)-1) {\n\t\towner = i->i_uid;\n\t} else {\n\t\ti->i_mode &= ~(S_ISUID);\n\t\ti->i_ctime = CURRENT_TIME;\n\t}\n\tif(group == (__gid_t)-1) {\n\t\tgroup = i->i_gid;\n\t} else {\n\t\ti->i_mode &= ~(S_ISGID);\n\t\ti->i_ctime = CURRENT_TIME;\n\t}\n\n\ti->i_uid = owner;\n\ti->i_gid = group;\n\ti->state |= INODE_DIRTY;\n\tiput(i);\n\tfree_name(tmp_name);\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/chown32.c",
    "content": "/*\n * fiwix/kernel/syscalls/chown32.c\n *\n * Copyright 2018-2023, Jordi Sanfeliu. All rights reserved.\n * Copyright 2018-2023, Richard R. Masters. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/kernel.h>\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_chown32(const char *filename, unsigned int owner, unsigned int group)\n{\n\tstruct inode *i;\n\tchar *tmp_name;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_chown32('%s', %u, %u)\\n\", current->pid, filename, owner, group);\n#endif /*__DEBUG__ */\n\n\tif((errno = malloc_name(filename, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = namei(tmp_name, &i, NULL, !FOLLOW_LINKS))) {\n\t\tfree_name(tmp_name);\n\t\treturn errno;\n\t}\n\n\tif(IS_RDONLY_FS(i)) {\n\t\tiput(i);\n\t\tfree_name(tmp_name);\n\t\treturn -EROFS;\n\t}\n\tif(check_user_permission(i)) {\n\t\tiput(i);\n\t\tfree_name(tmp_name);\n\t\treturn -EPERM;\n\t}\n\n\tif(owner == (unsigned int)-1) {\n\t\towner = i->i_uid;\n\t} else {\n\t\ti->i_mode &= ~(S_ISUID);\n\t\ti->i_ctime = CURRENT_TIME;\n\t}\n\tif(group == (unsigned int)-1) {\n\t\tgroup = i->i_gid;\n\t} else {\n\t\ti->i_mode &= ~(S_ISGID);\n\t\ti->i_ctime = CURRENT_TIME;\n\t}\n\n\ti->i_uid = owner;\n\ti->i_gid = group;\n\ti->state |= INODE_DIRTY;\n\tiput(i);\n\tfree_name(tmp_name);\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/chroot.c",
    "content": "/*\n * fiwix/kernel/syscalls/chroot.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_chroot(const char *dirname)\n{\n\tstruct inode *i;\n\tchar *tmp_name;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_chroot('%s')\\n\", current->pid, dirname);\n#endif /*__DEBUG__ */\n\n\tif((errno = malloc_name(dirname, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = namei(tmp_name, &i, NULL, FOLLOW_LINKS))) {\n\t\tfree_name(tmp_name);\n\t\treturn errno;\n\t}\n\tif(!S_ISDIR(i->i_mode)) {\n\t\tiput(i);\n\t\tfree_name(tmp_name);\n\t\treturn -ENOTDIR;\n\t}\n\tiput(current->root);\n\tcurrent->root = i;\n\tfree_name(tmp_name);\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/close.c",
    "content": "/*\n * fiwix/kernel/syscalls/close.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/syscalls.h>\n#include <fiwix/fd.h>\n#include <fiwix/locks.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n\nint sys_close(unsigned int ufd)\n{\n\tunsigned int fd;\n\tstruct inode *i;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_close(%d)\\n\", current->pid, ufd);\n#endif /*__DEBUG__ */\n\n\tCHECK_UFD(ufd);\n\tfd = current->fd[ufd];\n\trelease_user_fd(ufd);\n\n\tif(--fd_table[fd].count) {\n\t\treturn 0;\n\t}\n\ti = fd_table[fd].inode;\n\tflock_release_inode(i);\n\tif(i->fsop && i->fsop->close) {\n\t\ti->fsop->close(i, &fd_table[fd]);\n\t\trelease_fd(fd);\n\t\tiput(i);\n\t\treturn 0;\n\t}\n\tprintk(\"WARNING: %s(): ufd %d without the close() method!\\n\", __FUNCTION__, ufd);\n\treturn -EINVAL;\n}\n"
  },
  {
    "path": "kernel/syscalls/creat.c",
    "content": "/*\n * fiwix/kernel/syscalls/creat.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/syscalls.h>\n#include <fiwix/fcntl.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_creat(const char *filename, __mode_t mode)\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_creat('%s', %d)\\n\", current->pid, filename, mode);\n#endif /*__DEBUG__ */\n\treturn sys_open(filename, O_CREAT | O_WRONLY | O_TRUNC, mode);\n}\n"
  },
  {
    "path": "kernel/syscalls/dup.c",
    "content": "/*\n * fiwix/kernel/syscalls/dup.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/syscalls.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_dup(unsigned int ufd)\n{\n\tint new_ufd;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_dup(%d)\", current->pid, ufd);\n#endif /*__DEBUG__ */\n\n\tCHECK_UFD(ufd);\n\tif((new_ufd = get_new_user_fd(0)) < 0) {\n\t\treturn new_ufd;\n\t}\n\n#ifdef __DEBUG__\n\tprintk(\" -> %d\\n\", new_ufd);\n#endif /*__DEBUG__ */\n\n\tcurrent->fd[new_ufd] = current->fd[ufd];\n\tfd_table[current->fd[new_ufd]].count++;\n\treturn new_ufd;\n}\n"
  },
  {
    "path": "kernel/syscalls/dup2.c",
    "content": "/*\n * fiwix/kernel/syscalls/dup2.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/syscalls.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_dup2(unsigned int old_ufd, unsigned int new_ufd)\n{\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_dup2(%d, %d)\", current->pid, old_ufd, new_ufd);\n#endif /*__DEBUG__ */\n\n\tCHECK_UFD(old_ufd);\n\tif(new_ufd > OPEN_MAX) {\n\t\treturn -EINVAL;\n\t}\n\tif(old_ufd == new_ufd) {\n\t\treturn new_ufd;\n\t}\n\tif(current->fd[new_ufd]) {\n\t\tsys_close(new_ufd);\n\t}\n\tif((errno = get_new_user_fd(new_ufd)) < 0) {\n\t\treturn errno;\n\t}\n\tnew_ufd = errno;\n\tcurrent->fd[new_ufd] = current->fd[old_ufd];\n\tfd_table[current->fd[new_ufd]].count++;\n#ifdef __DEBUG__\n\tprintk(\" --> returning %d\\n\", new_ufd);\n#endif /*__DEBUG__ */\n\treturn new_ufd;\n}\n"
  },
  {
    "path": "kernel/syscalls/execve.c",
    "content": "/*\n * fiwix/kernel/syscalls/execve.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/syscalls.h>\n#include <fiwix/stat.h>\n#include <fiwix/buffer.h>\n#include <fiwix/mm.h>\n#include <fiwix/process.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nstatic int initialize_barg(struct binargs *barg, char *argv[], char *envp[])\n{\n\tint n, errno;\n\n\tfor(n = 0; n < ARG_MAX; n++) {\n\t\tbarg->page[n] = 0;\n\t}\n\tbarg->argv_len = barg->envp_len = 0;\n\n\tfor(n = 0; argv[n]; n++) {\n\t\tif((errno = check_user_area(VERIFY_READ, argv[n], sizeof(char *)))) {\n\t\t\treturn errno;\n\t\t}\n\t\tbarg->argv_len += strlen(argv[n]) + 1;\n\t}\n\tbarg->argc = n;\n\n\tfor(n = 0; envp[n]; n++) {\n\t\tif((errno = check_user_area(VERIFY_READ, envp[n], sizeof(char *)))) {\n\t\t\treturn errno;\n\t\t}\n\t\tbarg->envp_len += strlen(envp[n]) + 1;\n\t}\n\tbarg->envc = n;\n\n\treturn 0;\n}\n\nstatic void free_barg_pages(struct binargs *barg)\n{\n\tint n;\n\n\tfor(n = 0; n < ARG_MAX; n++) {\n\t\tif(barg->page[n]) {\n\t\t\tkfree(barg->page[n]);\n\t\t}\n\t}\n}\n\nstatic int add_strings(struct binargs *barg, char *filename, char *interpreter, char *args)\n{\n\tint n, p, offset;\n\tunsigned int ae_str_len;\n\tchar *page;\n\n\t/*\n\t * For a script we need to substitute the saved argv[0] by the original\n\t * 'filename' supplied in execve(), otherwise the interpreter won't be\n\t * able to find the script file.\n\t */\n\tp = ARG_MAX - 1;\n\tae_str_len = barg->argv_len + barg->envp_len + 4;\n\tp -= ae_str_len / PAGE_SIZE;\n\toffset = PAGE_SIZE - (ae_str_len & (PAGE_SIZE - 1));\t/* mod PAGE_SIZE */\n\tif(offset == PAGE_SIZE) {\n\t\toffset = 0;\n\t\tp++;\n\t}\n\tpage = (char *)barg->page[p];\n\twhile(*(page + offset)) {\n\t\toffset++;\n\t\tbarg->argv_len--;\n\t\tif(offset == PAGE_SIZE) {\n\t\t\tp++;\n\t\t\toffset = 0;\n\t\t\tpage = (char *)barg->page[p];\n\t\t}\n\t}\n\tbarg->argv_len--;\n\n\n\tp = ARG_MAX - 1;\n\tbarg->argv_len += strlen(interpreter) + 1;\n\tbarg->argv_len += strlen(args) ? strlen(args) + 1 : 0;\n\tbarg->argv_len += strlen(filename) + 1;\n\tbarg->argc++;\n\tif(*args) {\n\t\tbarg->argc++;\n\t}\n\tae_str_len = barg->argv_len + barg->envp_len + 4;\n\tp -= ae_str_len / PAGE_SIZE;\n\toffset = PAGE_SIZE - (ae_str_len & (PAGE_SIZE - 1));\t/* mod PAGE_SIZE */\n\tif(offset == PAGE_SIZE) {\n\t\toffset = 0;\n\t\tp++;\n\t}\n\tbarg->offset = offset;\n\tfor(n = p; n < ARG_MAX; n++) {\n\t\tif(!barg->page[n]) {\n\t\t\tif(!(barg->page[n] = kmalloc(PAGE_SIZE))) {\n\t\t\t\tfree_barg_pages(barg);\n\t\t\t\treturn -ENOMEM;\n\t\t\t}\n\t\t}\n\t}\n\n\t/* interpreter */\n\tpage = (char *)barg->page[p];\n\twhile(*interpreter) {\n\t\t*(page + offset) = *interpreter;\n\t\toffset++;\n\t\tinterpreter++;\n\t\tif(offset == PAGE_SIZE) {\n\t\t\tp++;\n\t\t\toffset = 0;\n\t\t\tpage = (char *)barg->page[p];\n\t\t}\n\t}\n\t*(page + offset++) = 0;\n\tif(offset == PAGE_SIZE) {\n\t\tp++;\n\t\toffset = 0;\n\t}\n\n\t/* args */\n\tpage = (char *)barg->page[p];\n\tif(*args) {\n\t\twhile(*args) {\n\t\t\t*(page + offset) = *args;\n\t\t\toffset++;\n\t\t\targs++;\n\t\t\tif(offset == PAGE_SIZE) {\n\t\t\t\tp++;\n\t\t\t\toffset = 0;\n\t\t\t\tpage = (char *)barg->page[p];\n\t\t\t}\n\t\t}\n\t\t*(page + offset++) = 0;\n\t\tif(offset == PAGE_SIZE) {\n\t\t\tp++;\n\t\t\toffset = 0;\n\t\t}\n\t}\n\n\t/* original script ('filename' with path) at argv[0] */\n\tpage = (char *)barg->page[p];\n\twhile(*filename) {\n\t\t*(page + offset) = *filename;\n\t\toffset++;\n\t\tfilename++;\n\t\tif(offset == PAGE_SIZE) {\n\t\t\tp++;\n\t\t\toffset = 0;\n\t\t\tpage = (char *)barg->page[p];\n\t\t}\n\t}\n\t*(page + offset) = 0;\n\n\treturn 0;\n}\n\nstatic int copy_strings(struct binargs *barg, char *argv[], char *envp[])\n{\n\tint n, p, offset;\n\tunsigned int ae_ptr_len, ae_str_len;\n\tchar *page, *str;\n\n\tp = ARG_MAX - 1;\n\tae_ptr_len = (1 + (barg->argc + 1) + (barg->envc + 1)) * sizeof(unsigned int);\n\t/* the last 4 bytes of the stack pages are not used */\n\tae_str_len = barg->argv_len + barg->envp_len + 4;\n\tif (ae_ptr_len + ae_str_len > (ARG_MAX * PAGE_SIZE)) {\n\t\treturn -E2BIG;\n\t}\n\tp -= ae_str_len / PAGE_SIZE;\n\toffset = PAGE_SIZE - (ae_str_len & (PAGE_SIZE - 1));\t/* mod PAGE_SIZE */\n\tif(offset == PAGE_SIZE) {\n\t\toffset = 0;\n\t\tp++;\n\t}\n\tbarg->offset = offset;\n\tfor(n = p; n < ARG_MAX; n++) {\n\t\tif(!(barg->page[n] = kmalloc(PAGE_SIZE))) {\n\t\t\tfree_barg_pages(barg);\n\t\t\treturn -ENOMEM;\n\t\t}\n\t}\n\tfor(n = 0; n < barg->argc; n++) {\n\t\tstr = argv[n];\n\t\tpage = (char *)barg->page[p];\n\t\twhile(*str) {\n\t\t\t*(page + offset) = *str;\n\t\t\toffset++;\n\t\t\tstr++;\n\t\t\tif(offset == PAGE_SIZE) {\n\t\t\t\tp++;\n\t\t\t\toffset = 0;\n\t\t\t\tpage = (char *)barg->page[p];\n\t\t\t}\n\t\t}\n\t\t*(page + offset++) = 0;\n\t\tif(offset == PAGE_SIZE) {\n\t\t\tp++;\n\t\t\toffset = 0;\n\t\t}\n\t}\n\tfor(n = 0; n < barg->envc; n++) {\n\t\tstr = envp[n];\n\t\tpage = (char *)barg->page[p];\n\t\twhile(*str) {\n\t\t\t*(page + offset) = *str;\n\t\t\toffset++;\n\t\t\tstr++;\n\t\t\tif(offset == PAGE_SIZE) {\n\t\t\t\tp++;\n\t\t\t\toffset = 0;\n\t\t\t\tpage = (char *)barg->page[p];\n\t\t\t}\n\t\t}\n\t\t*(page + offset++) = 0;\n\t\tif(offset == PAGE_SIZE) {\n\t\t\tp++;\n\t\t\toffset = 0;\n\t\t}\n\t}\n\n\treturn 0;\n}\n\nstatic int do_execve(const char *filename, char *argv[], char *envp[], struct sigcontext *sc)\n{\n\tchar interpreter[NAME_MAX + 1], args[NAME_MAX + 1], name[NAME_MAX + 1];\n\t__blk_t block;\n\tstruct buffer *buf;\n\tstruct inode *i;\n\tstruct binargs barg;\n\tchar *data;\n\tint errno;\n\n\tif((errno = initialize_barg(&barg, &(*argv), &(*envp))) < 0) {\n\t\treturn errno;\n\t}\n\n\t/* save 'argv' and 'envp' into the kernel address space */\n\tif((errno = copy_strings(&barg, &(*argv), &(*envp)))) {\n\t\treturn errno;\n\t}\n\n\tif(!(data = (void *)kmalloc(PAGE_SIZE))) {\n\t\treturn -ENOMEM;\n\t}\n\n\tstrcpy(name, filename);\n\nloop:\n\tif((errno = namei(name, &i, NULL, FOLLOW_LINKS))) {\n\t\tfree_barg_pages(&barg);\n\t\tkfree((unsigned int)data);\n\t\treturn errno;\n\t}\n\n\tif(!S_ISREG(i->i_mode)) {\n\t\tiput(i);\n\t\tfree_barg_pages(&barg);\n\t\tkfree((unsigned int)data);\n\t\treturn -EACCES;\n\t}\n\tif(check_permission(TO_EXEC, i) < 0) {\n\t\tiput(i);\n\t\tfree_barg_pages(&barg);\n\t\tkfree((unsigned int)data);\n\t\treturn -EACCES;\n\t}\n\n\tif((block = bmap(i, 0, FOR_READING)) < 0) {\n\t\tiput(i);\n\t\tfree_barg_pages(&barg);\n\t\tkfree((unsigned int)data);\n\t\treturn block;\n\t}\n\tif(!(buf = bread(i->dev, block, i->sb->s_blocksize))) {\n\t\tiput(i);\n\t\tfree_barg_pages(&barg);\n\t\tkfree((unsigned int)data);\n\t\treturn -EIO;\n\t}\n\n\t/*\n\t * The contents of the buffer is copied and then freed immediately to\n\t * make sure that it won't conflict while zeroing the BSS fractional\n\t * page, in case that the same block is requested during the page fault.\n\t */\n\tmemcpy_b(data, buf->data, i->sb->s_blocksize);\n\tbrelse(buf);\n\n\terrno = elf_load(i, &barg, sc, data);\n\tif(errno == -ENOEXEC) {\n\t\t/* OK, looks like it was not an ELF binary; let's see if it is a script */\n\t\tmemset_b(interpreter, 0, NAME_MAX + 1);\n\t\tmemset_b(args, 0, NAME_MAX + 1);\n\t\terrno = script_load(interpreter, args, data);\n\t\tif(!errno) {\n\t\t\t/* yes, it is! */\n\t\t\tiput(i);\n\t\t\tif((errno = add_strings(&barg, name, interpreter, args))) {\n\t\t\t\tfree_barg_pages(&barg);\n\t\t\t\tkfree((unsigned int)data);\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tstrcpy(name, interpreter);\n\t\t\tgoto loop;\n\t\t}\n\t}\n\n\tif(!errno) {\n\t\tif(i->i_mode & S_ISUID) {\n\t\t\tcurrent->euid = i->i_uid;\n\t\t}\n\t\tif(i->i_mode & S_ISGID) {\n\t\t\tcurrent->egid = i->i_gid;\n\t\t}\n\t}\n\n\tiput(i);\n\tfree_barg_pages(&barg);\n\tkfree((unsigned int)data);\n\treturn errno;\n}\n\n#ifdef CONFIG_SYSCALL_6TH_ARG\nint sys_execve(const char *filename, char *argv[], char *envp[], int arg4, int arg5, int arg6, struct sigcontext *sc)\n#else\nint sys_execve(const char *filename, char *argv[], char *envp[], int arg4, int arg5, struct sigcontext *sc)\n#endif /* CONFIG_SYSCALL_6TH_ARG */\n{\n\tchar *tmp_name;\n\tint n, errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_execve('%s', ...)\\n\", current->pid, filename);\n#endif /*__DEBUG__ */\n\n\tif((errno = malloc_name(filename, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = do_execve(tmp_name, &(*argv), &(*envp), sc))) {\n\t\tfree_name(tmp_name);\n\t\treturn errno;\n\t}\n\n\tstrncpy(current->argv0, tmp_name, NAME_MAX);\n\tfor(n = 0; n < OPEN_MAX; n++) {\n\t\tif(current->fd[n] && (current->fd_flags[n] & FD_CLOEXEC)) {\n\t\t\tsys_close(n);\n\t\t}\n\t}\n\n\tcurrent->suid = current->euid;\n\tcurrent->sgid = current->egid;\n\tcurrent->sigpending = 0;\n\tcurrent->sigexecuting = 0;\n\tfor(n = 0; n < NSIG; n++) {\n\t\tcurrent->sigaction[n].sa_mask = 0;\n\t\tcurrent->sigaction[n].sa_flags = 0;\n\t\tif(current->sigaction[n].sa_handler != SIG_IGN) {\n\t\t\tcurrent->sigaction[n].sa_handler = SIG_DFL;\n\t\t}\n\t}\n\tcurrent->sleep_address = NULL;\n\tcurrent->flags |= PF_PEXEC;\n\tfree_name(tmp_name);\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/exit.c",
    "content": "/*\n * fiwix/kernel/syscalls/exit.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/syscalls.h>\n#include <fiwix/process.h>\n#include <fiwix/sched.h>\n#include <fiwix/mman.h>\n#include <fiwix/sleep.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n#include <fiwix/buffer.h>\n#include <fiwix/filesystems.h>\n#ifdef CONFIG_SYSVIPC\n#include <fiwix/sem.h>\n#endif /* CONFIG_SYSVIPC */\n\nvoid do_exit(int exit_code)\n{\n\tint n;\n\tstruct proc *p, *init;\n\n#ifdef __DEBUG__\n\tprintk(\"\\n\");\n\tprintk(\"sys_exit(pid %d, ppid %d)\\n\", current->pid, current->ppid->pid);\n\tprintk(\"------------------------------\\n\");\n#endif /*__DEBUG__ */\n\n#ifdef CONFIG_SYSVIPC\n\tif(current->semundo) {\n\t\tsemexit();\n\t}\n#endif /* CONFIG_SYSVIPC */\n\n\trelease_binary();\n\tcurrent->argv = NULL;\n\tcurrent->envp = NULL;\n\n\tinit = &proc_table[INIT];\n\tFOR_EACH_PROCESS(p) {\n\t\tif(SESS_LEADER(current)) {\n\t\t\tif(p->sid == current->sid && p->state != PROC_ZOMBIE) {\n\t\t\t\tp->pgid = 0;\n\t\t\t\tp->sid = 0;\n\t\t\t\tp->ctty = NULL;\n\t\t\t\tsend_sig(p, SIGHUP);\n\t\t\t\tsend_sig(p, SIGCONT);\n\t\t\t}\n\t\t}\n\n\t\t/* make INIT inherit the children of this exiting process */\n\t\tif(p->ppid == current) {\n\t\t\tp->ppid = init;\n\t\t\tinit->children++;\n\t\t\tcurrent->children--;\n\t\t\tif(p->state == PROC_ZOMBIE) {\n\t\t\t\tsend_sig(init, SIGCHLD);\n\t\t\t\tif(init->sleep_address == &sys_wait4) {\n\t\t\t\t\twakeup_proc(init);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tp = p->next;\n\t}\n\n\tif(SESS_LEADER(current)) {\n\t\tdisassociate_ctty(current->ctty);\n\t}\n\n\tfor(n = 0; n < OPEN_MAX; n++) {\n\t\tif(current->fd[n]) {\n\t\t\tsys_close(n);\n\t\t}\n\t}\n\n\tiput(current->root);\n\tcurrent->root = NULL;\n\tiput(current->pwd);\n\tcurrent->pwd = NULL;\n\tcurrent->exit_code = exit_code;\n\tif(!--nr_processes) {\n\t\tprintk(\"\\n\");\n\t\tprintk(\"WARNING: the last user process has exited. The kernel will stop itself.\\n\");\n\t\tsync_superblocks(0);    /* in all devices */\n\t\tsync_inodes(0);         /* in all devices */\n\t\tsync_buffers(0);        /* in all devices */\n\t\tstop_kernel();\n\t}\n\n\t/* notify the parent about the child's death */\n\tp = current->ppid;\n\tsend_sig(p, SIGCHLD);\n\tif(p->sleep_address == &sys_wait4) {\n\t\twakeup_proc(p);\n\t}\n\n\tcurrent->sigpending = 0;\n\tcurrent->sigblocked = 0;\n\tcurrent->sigexecuting = 0;\n\tfor(n = 0; n < NSIG; n++) {\n\t\tcurrent->sigaction[n].sa_mask = 0;\n\t\tcurrent->sigaction[n].sa_flags = 0;\n\t\tcurrent->sigaction[n].sa_handler = SIG_IGN;\n\t}\n\n\tnot_runnable(current, PROC_ZOMBIE);\n\tdo_sched();\n}\n\nint sys_exit(int exit_code)\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_exit()\\n\", current->pid);\n#endif /*__DEBUG__ */\n\n\t/* exit code in the second byte.\n\t *  15                8 7                 0\n\t * +-------------------+-------------------+\n\t * | exit code (0-255) |         0         |\n\t * +-------------------+-------------------+\n\t */\n\tdo_exit((exit_code & 0xFF) << 8);\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/fchdir.c",
    "content": "/*\n * fiwix/kernel/syscalls/fchdir.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/process.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_fchdir(unsigned int ufd)\n{\n\tstruct inode *i;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_fchdir(%d)\\n\", current->pid, ufd);\n#endif /*__DEBUG__ */\n\n\tCHECK_UFD(ufd);\n\ti = fd_table[current->fd[ufd]].inode;\n\tif(!S_ISDIR(i->i_mode)) {\n\t\treturn -ENOTDIR;\n\t}\n\tiput(current->pwd);\n\tcurrent->pwd = i;\n\tcurrent->pwd->count++;\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/fchmod.c",
    "content": "/*\n * fiwix/kernel/syscalls/fchmod.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_fchmod(unsigned int ufd, __mode_t mode)\n{\n\tstruct inode *i;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_fchmod(%d, %d)\\n\", current->pid, ufd, mode);\n#endif /*__DEBUG__ */\n\n\tCHECK_UFD(ufd);\n\ti = fd_table[current->fd[ufd]].inode;\n\n\tif(IS_RDONLY_FS(i)) {\n\t\treturn -EROFS;\n\t}\n\tif(check_user_permission(i)) {\n\t\treturn -EPERM;\n\t}\n\n\ti->i_mode &= S_IFMT;\n\ti->i_mode |= mode & ~S_IFMT;\n\ti->i_ctime = CURRENT_TIME;\n\ti->state |= INODE_DIRTY;\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/fchown.c",
    "content": "/*\n * fiwix/kernel/syscalls/fchown.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_fchown(unsigned int ufd, __uid_t owner, __gid_t group)\n{\n\tstruct inode *i;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_fchown(%d, %d, %d)\\n\", current->pid, ufd, owner, group);\n#endif /*__DEBUG__ */\n\n\tCHECK_UFD(ufd);\n\ti = fd_table[current->fd[ufd]].inode;\n\n\tif(IS_RDONLY_FS(i)) {\n\t\treturn -EROFS;\n\t}\n\tif(check_user_permission(i)) {\n\t\treturn -EPERM;\n\t}\n\n\tif(owner == (__uid_t)-1) {\n\t\towner = i->i_uid;\n\t} else {\n\t\ti->i_mode &= ~(S_ISUID);\n\t}\n\tif(group == (__gid_t)-1) {\n\t\tgroup = i->i_gid;\n\t} else {\n\t\ti->i_mode &= ~(S_ISGID);\n\t}\n\n\ti->i_uid = owner;\n\ti->i_gid = group;\n\ti->i_ctime = CURRENT_TIME;\n\ti->state |= INODE_DIRTY;\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/fcntl.c",
    "content": "/*\n * fiwix/kernel/syscalls/fcntl.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/syscalls.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/locks.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_fcntl(unsigned int ufd, int cmd, unsigned int arg)\n{\n\tint new_ufd, errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_fcntl(%d, %d, 0x%08x)\\n\", current->pid, ufd, cmd, arg);\n#endif /*__DEBUG__ */\n\n\tCHECK_UFD(ufd);\n\tswitch(cmd) {\n\t\tcase F_DUPFD:\n\t\tcase F_DUPFD_CLOEXEC:\n\t\t\tif(arg >= OPEN_MAX) {\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\tif((new_ufd = get_new_user_fd(arg)) < 0) {\n\t\t\t\treturn new_ufd;\n\t\t\t}\n\t\t\tcurrent->fd[new_ufd] = current->fd[ufd];\n\t\t\tif (cmd == F_DUPFD_CLOEXEC) {\n\t\t\t\tcurrent->fd_flags[new_ufd] |= FD_CLOEXEC;\n\t\t\t}\n\t\t\tfd_table[current->fd[new_ufd]].count++;\n#ifdef __DEBUG__\n\t\t\tprintk(\"\\t--> returning %d\\n\", new_ufd);\n#endif /*__DEBUG__ */\n\t\t\treturn new_ufd;\n\t\tcase F_GETFD:\n\t\t\treturn (current->fd_flags[ufd] & FD_CLOEXEC);\n\t\tcase F_SETFD:\n\t\t\tcurrent->fd_flags[ufd] = (arg & FD_CLOEXEC);\n\t\t\tbreak;\n\t\tcase F_GETFL:\n\t\t\treturn fd_table[current->fd[ufd]].flags;\n\t\tcase F_SETFL:\n\t\t\tfd_table[current->fd[ufd]].flags &= ~(O_APPEND | O_NONBLOCK);\n\t\t\tfd_table[current->fd[ufd]].flags |= arg & (O_APPEND | O_NONBLOCK);\n\t\t\tbreak;\n\t\tcase F_GETLK:\n\t\tcase F_SETLK:\n\t\tcase F_SETLKW:\n\t\t\tif((errno = check_user_area(VERIFY_READ, (void *)arg, sizeof(struct flock)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\treturn posix_lock(ufd, cmd, (struct flock *)arg);\n\t\tdefault:\n\t\t\treturn -EINVAL;\n\t}\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/fcntl64.c",
    "content": "/*\n * fiwix/kernel/syscalls/fcntl64.c\n *\n * Copyright 2018-2023, Jordi Sanfeliu. All rights reserved.\n * Copyright 2023, Richard R. Masters.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/syscalls.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/locks.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n\nint sys_fcntl64(unsigned int ufd, int cmd, unsigned int arg)\n{\n\tint new_ufd;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_fcntl64(%d, %d, 0x%08x)\\n\", current->pid, ufd, cmd, arg);\n#endif /*__DEBUG__ */\n\n\tCHECK_UFD(ufd);\n\tswitch(cmd) {\n\t\tcase F_DUPFD_CLOEXEC:\n\t\tcase F_DUPFD:\n\t\t\tif(arg >= OPEN_MAX) {\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\tif((new_ufd = get_new_user_fd(arg)) < 0) {\n\t\t\t\treturn new_ufd;\n\t\t\t}\n\t\t\tcurrent->fd[new_ufd] = current->fd[ufd];\n\t\t\tif (cmd == F_DUPFD_CLOEXEC) {\n\t\t\t\tcurrent->fd_flags[new_ufd] |= FD_CLOEXEC;\n\t\t\t}\n\t\t\tfd_table[current->fd[new_ufd]].count++;\n#ifdef __DEBUG__\n\t\t\tprintk(\"\\t--> returning %d\\n\", new_ufd);\n#endif /*__DEBUG__ */\n\t\t\treturn new_ufd;\n\t\tcase F_GETFD:\n\t\t\treturn (current->fd_flags[ufd] & FD_CLOEXEC);\n\t\tcase F_SETFD:\n\t\t\tcurrent->fd_flags[ufd] = (arg & FD_CLOEXEC);\n\t\t\tbreak;\n\t\tcase F_GETFL:\n\t\t\treturn fd_table[current->fd[ufd]].flags;\n\t\tcase F_SETFL:\n\t\t\tfd_table[current->fd[ufd]].flags &= ~(O_APPEND | O_NONBLOCK);\n\t\t\tfd_table[current->fd[ufd]].flags |= arg & (O_APPEND | O_NONBLOCK);\n\t\t\tbreak;\n\t\tcase F_GETLK64:\n\t\tcase F_SETLK64:\n\t\tcase F_SETLKW64:\n\t\t\tprintk(\"(pid %d) sys_fcntl64: WARNING: locks not implemented!\\n\", current->pid);\n\t\t\treturn 0;\n\t\tdefault:\n\t\t\treturn -EINVAL;\n\t}\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/fdatasync.c",
    "content": "/*\n * fiwix/kernel/syscalls/fdatasync.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/syscalls.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_fdatasync(int ufd)\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_fdatasync(%d)\\n\", current->pid, ufd);\n#endif /*__DEBUG__ */\n\n\treturn sys_fsync(ufd);\n}\n"
  },
  {
    "path": "kernel/syscalls/flock.c",
    "content": "/*\n * fiwix/kernel/syscalls/flock.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/process.h>\n#include <fiwix/locks.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_flock(unsigned int ufd, int op)\n{\n\tstruct inode *i;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_flock(%d, %d)\\n\", current->pid, ufd, op);\n#endif /*__DEBUG__ */\n\n\tCHECK_UFD(ufd);\n\ti = fd_table[current->fd[ufd]].inode;\n\treturn flock_inode(i, op);\n}\n"
  },
  {
    "path": "kernel/syscalls/fork.c",
    "content": "/*\n * fiwix/kernel/syscalls/fork.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/types.h>\n#include <fiwix/segments.h>\n#include <fiwix/sigcontext.h>\n#include <fiwix/process.h>\n#include <fiwix/sched.h>\n#include <fiwix/sleep.h>\n#include <fiwix/mm.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstatic void free_vma_table(struct proc *p)\n{\n\tstruct vma *vma, *tmp;\n\n\tvma = p->vma_table;\n\twhile(vma) {\n\t\ttmp = vma;\n\t\tvma = vma->next;\n\t\tkfree((unsigned int)tmp);\n\t}\n}\n\n#ifdef CONFIG_SYSCALL_6TH_ARG\nint sys_fork(int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, struct sigcontext *sc)\n#else\nint sys_fork(int arg1, int arg2, int arg3, int arg4, int arg5, struct sigcontext *sc)\n#endif /* CONFIG_SYSCALL_6TH_ARG */\n{\n\tint count, pages;\n\tunsigned int n;\n\tunsigned int *child_pgdir;\n\tstruct sigcontext *stack;\n\tstruct proc *child, *p;\n\tstruct vma *vma, *child_vma;\n\t__pid_t pid;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_fork()\\n\", current->pid);\n#endif /*__DEBUG__ */\n\n\t/* check the number of processes already allocated by this UID */\n\tcount = 0;\n\tFOR_EACH_PROCESS(p) {\n\t\tif(p->uid == current->uid) {\n\t\t\tcount++;\n\t\t}\n\t\tp = p->next;\n\t}\n\tif(count > current->rlim[RLIMIT_NPROC].rlim_cur) {\n\t\tprintk(\"WARNING: %s(): RLIMIT_NPROC exceeded.\\n\", __FUNCTION__);\n\t\treturn -EAGAIN;\n\t}\n\n\tif(!(pid = get_unused_pid())) {\n\t\treturn -EAGAIN;\n\t}\n\tif(!(child = get_proc_free())) {\n\t\treturn -EAGAIN;\n\t}\n\n\t/* \n\t * This memcpy() will overwrite the prev and next pointers, so that's\n\t * the reason why proc_slot_init() is separated from get_proc_free().\n\t */\n\tmemcpy_b(child, current, sizeof(struct proc));\n\n\tproc_slot_init(child);\n\tchild->pid = pid;\n\tsprintk(child->pidstr, \"%d\", child->pid);\n\n\tif(!(child_pgdir = (void *)kmalloc(PAGE_SIZE))) {\n\t\trelease_proc(child);\n\t\treturn -ENOMEM;\n\t}\n\tchild->rss++;\n\tmemcpy_b(child_pgdir, kpage_dir, PAGE_SIZE);\n\tchild->tss.cr3 = V2P((unsigned int)child_pgdir);\n\n\tchild->ppid = current;\n\tchild->flags = 0;\n\tchild->children = 0;\n\tchild->cpu_count = (current->cpu_count >>= 1);\n\tchild->start_time = CURRENT_TICKS;\n\tchild->sleep_address = NULL;\n\n\tvma = current->vma_table;\n\tchild->vma_table = NULL;\n\twhile(vma) {\n\t\tif(!(child_vma = (struct vma *)kmalloc(sizeof(struct vma)))) {\n\t\t\tkfree((unsigned int)child_pgdir);\n\t\t\tfree_vma_table(child);\n\t\t\trelease_proc(child);\n\t\t\treturn -ENOMEM;\n\t\t}\n\t\t*child_vma = *vma;\n\t\tchild_vma->prev = child_vma->next = NULL;\n\t\tif(child_vma->inode) {\n\t\t\tchild_vma->inode->count++;\n\t\t}\n\t\tif(!child->vma_table) {\n\t\t\tchild->vma_table = child_vma;\n\t\t} else {\n\t\t\tchild_vma->prev = child->vma_table->prev;\n\t\t\tchild->vma_table->prev->next = child_vma;\n\t\t}\n\t\tchild->vma_table->prev = child_vma;\n\t\tvma = vma->next;\n\t}\n\n\tchild->sigpending = 0;\n\tchild->sigexecuting = 0;\n\tmemset_b(&child->sc, 0, sizeof(struct sigcontext));\n\tmemset_b(&child->usage, 0, sizeof(struct rusage));\n\tmemset_b(&child->cusage, 0, sizeof(struct rusage));\n\tchild->it_real_interval = 0;\n\tchild->it_real_value = 0;\n\tchild->it_virt_interval = 0;\n\tchild->it_virt_value = 0;\n\tchild->it_prof_interval = 0;\n\tchild->it_prof_value = 0;\n#ifdef CONFIG_SYSVIPC\n\tcurrent->semundo = NULL;\n#endif /* CONFIG_SYSVIPC */\n\n\n\tif(!(child->tss.esp0 = kmalloc(PAGE_SIZE))) {\n\t\tkfree((unsigned int)child_pgdir);\n\t\tfree_vma_table(child);\n\t\trelease_proc(child);\n\t\treturn -ENOMEM;\n\t}\n\n\tif(!(pages = clone_pages(child))) {\n\t\tprintk(\"WARNING: %s(): not enough memory when cloning pages.\\n\", __FUNCTION__);\n\t\tfree_page_tables(child);\n\t\tkfree((unsigned int)child_pgdir);\n\t\tfree_vma_table(child);\n\t\trelease_proc(child);\n\t\treturn -ENOMEM;\n\t}\n\tchild->rss += pages;\n\tinvalidate_tlb();\n\n\tchild->tss.esp0 += PAGE_SIZE - 4;\n\tchild->rss++;\n\tchild->tss.ss0 = KERNEL_DS;\n\n\tmemcpy_b((unsigned int *)(child->tss.esp0 & PAGE_MASK), (void *)((unsigned int)(sc) & PAGE_MASK), PAGE_SIZE);\n\tstack = (struct sigcontext *)((child->tss.esp0 & PAGE_MASK) + ((unsigned int)(sc) & ~PAGE_MASK));\n\n\tchild->tss.eip = (unsigned int)return_from_syscall;\n\tchild->tss.esp = (unsigned int)stack;\n\tstack->eax = 0;\t\t/* child returns 0 */\n\n\t/* increase file descriptors usage */\n\tfor(n = 0; n < OPEN_MAX; n++) {\n\t\tif(current->fd[n]) {\n\t\t\tfd_table[current->fd[n]].count++;\n\t\t}\n\t}\n\tif(current->root) {\n\t\tcurrent->root->count++;\n\t}\n\tif(current->pwd) {\n\t\tcurrent->pwd->count++;\n\t}\n\n\tkstat.processes++;\n\tnr_processes++;\n\tcurrent->children++;\n\trunnable(child);\n\n\treturn child->pid;\t/* parent returns child's PID */\n}\n"
  },
  {
    "path": "kernel/syscalls/fstat.c",
    "content": "/*\n * fiwix/kernel/syscalls/fstat.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/syscalls.h>\n#include <fiwix/statbuf.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_fstat(unsigned int ufd, struct old_stat *statbuf)\n{\n\tstruct inode *i;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_fstat(%d, 0x%08x) -> returning structure\\n\", current->pid, ufd, (unsigned int )statbuf);\n#endif /*__DEBUG__ */\n\n\tCHECK_UFD(ufd);\n\tif((errno = check_user_area(VERIFY_WRITE, statbuf, sizeof(struct old_stat)))) {\n\t\treturn errno;\n\t}\n\ti = fd_table[current->fd[ufd]].inode;\n\tstatbuf->st_dev = i->dev;\n\tstatbuf->st_ino = i->inode;\n\tstatbuf->st_mode = i->i_mode;\n\tstatbuf->st_nlink = i->i_nlink;\n\tstatbuf->st_uid = i->i_uid;\n\tstatbuf->st_gid = i->i_gid;\n\tstatbuf->st_rdev = i->rdev;\n\tstatbuf->st_size = i->i_size;\n\tstatbuf->st_atime = i->i_atime;\n\tstatbuf->st_mtime = i->i_mtime;\n\tstatbuf->st_ctime = i->i_ctime;\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/fstat64.c",
    "content": "/*\n * fiwix/kernel/syscalls/fstat64.c\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Copyright 2023, Richard R. Masters.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/syscalls.h>\n#include <fiwix/statbuf.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_fstat64(unsigned int ufd, struct stat64 *statbuf)\n{\n\tstruct inode *i;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_fstat64(%d, 0x%08x) -> returning structure\\n\", current->pid, ufd, (unsigned int)statbuf);\n#endif /*__DEBUG__ */\n\n\tCHECK_UFD(ufd);\n\tif((errno = check_user_area(VERIFY_WRITE, statbuf, sizeof(struct stat64)))) {\n\t\treturn errno;\n\t}\n\ti = fd_table[current->fd[ufd]].inode;\n\tstatbuf->st_dev = i->dev;\n\tstatbuf->st_ino = i->inode;\n\tstatbuf->st_mode = i->i_mode;\n\tstatbuf->st_nlink = i->i_nlink;\n\tstatbuf->st_uid = i->i_uid;\n\tstatbuf->st_gid = i->i_gid;\n\tstatbuf->st_rdev = i->rdev;\n\tstatbuf->st_size = i->i_size;\n\tstatbuf->st_atime = i->i_atime;\n\tstatbuf->st_mtime = i->i_mtime;\n\tstatbuf->st_ctime = i->i_ctime;\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/fstatfs.c",
    "content": "/*\n * fiwix/kernel/syscalls/fstatfs.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/statfs.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_fstatfs(unsigned int ufd, struct statfs *statfsbuf)\n{\n\tstruct inode *i;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_fstatfs(%d, 0x%08x)\\n\", current->pid, ufd, (unsigned int)statfsbuf);\n#endif /*__DEBUG__ */\n\n\tCHECK_UFD(ufd);\n\tif((errno = check_user_area(VERIFY_WRITE, statfsbuf, sizeof(struct statfs)))) {\n\t\treturn errno;\n\t}\n\ti = fd_table[current->fd[ufd]].inode;\n\tif(i->sb && i->sb->fsop && i->sb->fsop->statfs) {\n\t\ti->sb->fsop->statfs(i->sb, statfsbuf);\n\t\treturn 0;\n\t}\n\treturn -ENOSYS;\n}\n"
  },
  {
    "path": "kernel/syscalls/fsync.c",
    "content": "/*\n * fiwix/kernel/syscalls/fsync.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/process.h>\n#include <fiwix/stat.h>\n#include <fiwix/buffer.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_fsync(unsigned int ufd)\n{\n\tstruct inode *i;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_fsync(%d)\\n\", current->pid, ufd);\n#endif /*__DEBUG__ */\n\n\tCHECK_UFD(ufd);\n\ti = fd_table[current->fd[ufd]].inode;\n\tif(!S_ISREG(i->i_mode)) {\n\t\treturn -EINVAL;\n\t}\n\tif(IS_RDONLY_FS(i)) {\n\t\treturn -EROFS;\n\t}\n\tsync_superblocks(i->dev);\n\tsync_inodes(i->dev);\n\tsync_buffers(i->dev);\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/ftime.c",
    "content": "/*\n * fiwix/kernel/syscalls/ftime.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/fs.h>\n#include <fiwix/timeb.h>\n#include <fiwix/timer.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_ftime(struct timeb *tp)\n{\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_ftime()\\n\", current->pid);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_user_area(VERIFY_WRITE, tp, sizeof(struct timeb)))) {\n\t\treturn errno;\n\t}\n\ttp->time = CURRENT_TIME;\n\ttp->millitm = ((CURRENT_TICKS % HZ) * 1000000) / HZ;\n\t/* FIXME: 'timezone' and 'dstflag' fields are not used */\n\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/ftruncate.c",
    "content": "/*\n * fiwix/kernel/syscalls/ftruncate.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_ftruncate(unsigned int ufd, __off_t length)\n{\n\tstruct inode *i;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_ftruncate(%d, %d)\\n\", current->pid, ufd, length);\n#endif /*__DEBUG__ */\n\n\tCHECK_UFD(ufd);\n\ti = fd_table[current->fd[ufd]].inode;\n\tif((fd_table[current->fd[ufd]].flags & O_ACCMODE) == O_RDONLY) {\n\t\treturn -EINVAL;\n\t}\n\tif(S_ISDIR(i->i_mode)) {\n\t\treturn -EISDIR;\n\t}\n\tif(IS_RDONLY_FS(i)) {\n\t\treturn -EROFS;\n\t}\n\tif(check_permission(TO_WRITE, i) < 0) {\n\t\treturn -EPERM;\n\t}\n\tif(length == i->i_size) {\n\t\treturn 0;\n\t}\n\n\tif(i->fsop && i->fsop->truncate) {\n\t\tinode_lock(i);\n\t\terrno = i->fsop->truncate(i, length);\n\t\tinode_unlock(i);\n\t\treturn errno;\n\t}\n\treturn -EINVAL;\n}\n"
  },
  {
    "path": "kernel/syscalls/ftruncate64.c",
    "content": "/*\n * fiwix/kernel/syscalls/ftruncate64.c\n *\n * Copyright 2018-2023, Jordi Sanfeliu. All rights reserved.\n * Copyright 2023, Richard R. Masters.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_ftruncate64(unsigned int ufd, __loff_t length)\n{\n\tstruct inode *i;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_ftruncate64(%d, %llu)\\n\", current->pid, ufd, length);\n#endif /*__DEBUG__ */\n\n\tCHECK_UFD(ufd);\n\ti = fd_table[current->fd[ufd]].inode;\n\tif((fd_table[current->fd[ufd]].flags & O_ACCMODE) == O_RDONLY) {\n\t\treturn -EINVAL;\n\t}\n\tif(S_ISDIR(i->i_mode)) {\n\t\treturn -EISDIR;\n\t}\n\tif(IS_RDONLY_FS(i)) {\n\t\treturn -EROFS;\n\t}\n\tif(check_permission(TO_WRITE, i) < 0) {\n\t\treturn -EPERM;\n\t}\n\tif((__off_t)length == i->i_size) {\n\t\treturn 0;\n\t}\n\n\terrno = 0;\n\tif(i->fsop && i->fsop->truncate) {\n\t\tinode_lock(i);\n\t\terrno = i->fsop->truncate(i, (__off_t)length);\n\t\tinode_unlock(i);\n\t}\n\treturn errno;\n}\n"
  },
  {
    "path": "kernel/syscalls/getcwd.c",
    "content": "/*\n * fiwix/kernel/syscalls/getcwd.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Copyright 2022, Alwin Berger. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n#include <fiwix/mm.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_getcwd(char *buf, __size_t size)\n{\n\tint errno;\n\tstruct dirent *dirent_buf;\n\tstruct dirent *d_ptr;\n\tstruct inode *cur;\n\tstruct inode *up;\n\tstruct inode *tmp_ino;\n\tint tmp_fd, done;\n\tint namelength, bytes_read;\n\tint diff_dev;\n\t__size_t marker;\n\t__size_t x;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_getcwd(0x%08x, %d)\\n\", current->pid, (unsigned int)buf, size);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_user_area(VERIFY_WRITE, buf, size))) {\n\t\treturn errno;\n\t}\n\t/* buffer self-allocation not supported */\n\tif(size == 0 || buf == NULL) {\n\t\treturn -EINVAL;\n\t}\n\t/* the shortest possible path is \"/\" */\n\tif(size < 2) {\n\t\treturn -ERANGE;\n\t}\n\n\tcur = current->pwd;\n\tup = cur;\n\tmarker = size - 2;\t/* reserve '\\0' at the end */\n\tbuf[size - 1] = 0;\n\n\tif(cur == current->root) {\n\t\t/* this case needs special handling, otherwise the loop skips over root */\n\t\tbuf[0] = '/';\n\t\tbuf[1] = '\\0';\n\t\treturn 2;\n\t}\n\tif(!(dirent_buf = (void *)kmalloc(PAGE_SIZE))) {\n\t\treturn -ENOMEM;\n\t}\n\n\tdo {\n\t\tif((errno = parse_namei(\"..\", cur, &up, 0, FOLLOW_LINKS))) {\n\t\t\tif(cur != current->pwd) {\n\t\t\t\tiput(cur);\n\t\t\t}\n\t\t\tkfree((unsigned int)dirent_buf);\n\t\t\treturn errno;\n\t\t}\n\t\tif((tmp_fd = get_new_fd(up)) < 0) {\n\t\t\tiput(up);\n\t\t\tif(cur != current->pwd) {\n\t\t\t\tiput(cur);\n\t\t\t}\n\t\t\tkfree((unsigned int)dirent_buf);\n\t\t\treturn tmp_fd;\n\t\t}\n\t\tdo {\n\t\t\tdone = 0;\n\t\t\tbytes_read = up->fsop->readdir(up, &fd_table[tmp_fd], dirent_buf, PAGE_SIZE);\n\t\t\tif(bytes_read < 0) {\n\t\t\t\trelease_fd(tmp_fd);\n\t\t\t\tiput(up);\n\t\t\t\tif(cur != current->pwd) {\n\t\t\t\t\tiput(cur);\n\t\t\t\t}\n\t\t\t\tkfree((unsigned int)dirent_buf);\n\t\t\t\treturn bytes_read;\n\t\t\t}\n\t\t\td_ptr = dirent_buf;\n\t\t\twhile((void *) d_ptr < ((void *) dirent_buf + bytes_read)) {\n\t\t\t\t/*\n\t\t\t\t * If the child is on the same device as the parent the d_ptr->d_ino should be correct.\n\t\t\t\t * In this case there is no need to call a namei again.\n\t\t\t\t */\n\t\t\t\tdiff_dev = up->dev != cur->dev;\n\t\t\t\tif(diff_dev) {\n\t\t\t\t\tif(parse_namei(d_ptr->d_name, up, &tmp_ino, 0, FOLLOW_LINKS)) {\n\t\t\t\t\t\t/* keep going if sibling dirents fail */\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif((!diff_dev && d_ptr->d_ino == cur->inode) || (diff_dev && tmp_ino->inode == cur->inode)) {\n\t\t\t\t\tif(strcmp(\"..\", d_ptr->d_name)) {\n\t\t\t\t\t\tnamelength = strlen(d_ptr->d_name);\n\t\t\t\t\t\tif(marker < namelength + 1) {\n\t\t\t\t\t\t\trelease_fd(tmp_fd);\n\t\t\t\t\t\t\tiput(up);\n\t\t\t\t\t\t\tif(cur != current->pwd) {\n\t\t\t\t\t\t\t\tiput(cur);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(diff_dev) {\n\t\t\t\t\t\t\t\tiput(tmp_ino);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tkfree((unsigned int)dirent_buf);\n\t\t\t\t\t\t\treturn -ERANGE;\n\t\t\t\t\t\t}\n\t\t\t\t\t\twhile(--namelength >= 0) {\n\t\t\t\t\t\t\tbuf[marker--] = d_ptr->d_name[namelength];\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbuf[marker--] = '/';\n\t\t\t\t\t\tif(diff_dev) {\n\t\t\t\t\t\t\tiput(tmp_ino);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdone = 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(diff_dev) {\n\t\t\t\t\tiput(tmp_ino);\n\t\t\t\t}\n\t\t\t\td_ptr = (struct dirent *) ((void *)d_ptr + d_ptr->d_reclen);\n\t\t\t}\n\t\t} while(bytes_read != 0 && !done);\n\n\t\trelease_fd(tmp_fd);\n\t\tif(!done) {\n\t\t\t/* parent dir was fully read, child still not found */\n\t\t\tiput(up);\n\t\t\tif(cur != current->pwd) {\n\t\t\t\tiput(cur);\n\t\t\t}\n\t\t\tkfree((unsigned int)dirent_buf);\n\t\t\treturn -ENOENT;\n\t\t}\n\t\tif(cur != current->pwd) {\n\t\t\tiput(cur);\n\t\t}\n\t\tcur = up;\n\t} while(cur != current->root);\n\n\tkfree((unsigned int)dirent_buf);\n\tiput(cur);\n\t/* move the string to the start of the buffer */\n\tfor(x = ++marker; x < size; x++) {\n\t\tbuf[x - marker] = buf[x];\n\t}\n\t/* linux returns the length of the string, so do we */\n\treturn size - marker;\n}\n"
  },
  {
    "path": "kernel/syscalls/getdents.c",
    "content": "/*\n * fiwix/kernel/syscalls/getdents.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/dirent.h>\n#include <fiwix/process.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_getdents(unsigned int ufd, struct dirent *dirent, unsigned int count)\n{\n\tstruct inode *i;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_getdents(%d, 0x%08x, %d)\", current->pid, ufd, (unsigned int)dirent, count);\n#endif /*__DEBUG__ */\n\n\tCHECK_UFD(ufd);\n\tif((errno = check_user_area(VERIFY_WRITE, dirent, sizeof(struct dirent)))) {\n\t\treturn errno;\n\t}\n\ti = fd_table[current->fd[ufd]].inode;\n\n\tif(!S_ISDIR(i->i_mode)) {\n\t\treturn -ENOTDIR;\n\t}\n\n\tif(i->fsop && i->fsop->readdir) {\n\t\terrno = i->fsop->readdir(i, &fd_table[current->fd[ufd]], dirent, count);\n\t#ifdef __DEBUG__\n\t\tprintk(\" -> returning %d\\n\", errno);\n\t#endif /*__DEBUG__ */\n\t\treturn errno;\n\t}\n\treturn -EINVAL;\n}\n"
  },
  {
    "path": "kernel/syscalls/getdents64.c",
    "content": "/*\n * fiwix/kernel/syscalls/getdents64.c\n *\n * Copyright 2018-2023, Jordi Sanfeliu. All rights reserved.\n * Copyright 2023, Richard R. Masters.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/dirent.h>\n#include <fiwix/process.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_getdents64(unsigned int ufd, struct dirent64 *dirent, unsigned int count)\n{\n\tstruct inode *i;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_getdents64(%d, 0x%08x, %d)\", current->pid, ufd, (unsigned int)dirent, count);\n#endif /*__DEBUG__ */\n\n\tCHECK_UFD(ufd);\n\tif((errno = check_user_area(VERIFY_WRITE, dirent, sizeof(struct dirent64)))) {\n\t\treturn errno;\n\t}\n\ti = fd_table[current->fd[ufd]].inode;\n\n\tif(!S_ISDIR(i->i_mode)) {\n\t\treturn -ENOTDIR;\n\t}\n\n\tif(i->fsop && i->fsop->readdir64) {\n\t\terrno = i->fsop->readdir64(i, &fd_table[current->fd[ufd]], dirent, count);\n\t#ifdef __DEBUG__\n\t\tprintk(\" -> returning %d\\n\", errno);\n\t#endif /*__DEBUG__ */\n\t\treturn errno;\n\t}\n\treturn -EINVAL;\n}\n"
  },
  {
    "path": "kernel/syscalls/getegid.c",
    "content": "/*\n * fiwix/kernel/syscalls/getegid.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/process.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_getegid(void)\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_getegid() -> %d\\n\", current->pid, current->egid);\n#endif /*__DEBUG__ */\n\treturn current->egid;\n}\n"
  },
  {
    "path": "kernel/syscalls/geteuid.c",
    "content": "/*\n * fiwix/kernel/syscalls/geteuid.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/process.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_geteuid(void)\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_geteuid() -> %d\\n\", current->pid, current->euid);\n#endif /*__DEBUG__ */\n\treturn current->euid;\n}\n"
  },
  {
    "path": "kernel/syscalls/getgid.c",
    "content": "/*\n * fiwix/kernel/syscalls/getgid.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/process.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_getgid(void)\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_getgid() -> %d\\n\", current->pid, current->gid);\n#endif /*__DEBUG__ */\n\treturn current->gid;\n}\n"
  },
  {
    "path": "kernel/syscalls/getgroups.c",
    "content": "/*\n * fiwix/kernel/syscalls/getgroups.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_getgroups(__ssize_t size, __gid_t *list)\n{\n\tint n, errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_getgroups(%d, 0x%08x)\\n\", current->pid, size, (unsigned int)list);\n#endif /*__DEBUG__ */\n\n\t/*\n\t * If size is 0, sys_getgroups() shall return the number of group IDs\n\t * that it would otherwise return without modifying the array pointed\n\t * to by list.\n\t */\n\tif(!size) {\n\t\tfor(n = 0; n < NGROUPS_MAX; n++) {\n\t\t\tif(current->groups[n] == -1) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn n;\n\t}\n\n\tif((errno = check_user_area(VERIFY_WRITE, list, sizeof(__gid_t)))) {\n\t\treturn errno;\n\t}\n\tfor(n = 0; n < NGROUPS_MAX; n++) {\n\t\tif(current->groups[n] == -1) {\n\t\t\tbreak;\n\t\t}\n\t\tif(size) {\n\t\t\tif(n > size) {\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\tlist[n] = (__gid_t)current->groups[n];\n\t\t}\n\t}\n\treturn n;\n}\n"
  },
  {
    "path": "kernel/syscalls/getitimer.c",
    "content": "/*\n * fiwix/kernel/syscalls/getitimer.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/time.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_getitimer(int which, struct itimerval *curr_value)\n{\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_getitimer(%d, 0x%08x) -> \\n\", current->pid, which, (unsigned int)curr_value);\n#endif /*__DEBUG__ */\n\n\tif((unsigned int)curr_value) {\n\t\tif((errno = check_user_area(VERIFY_WRITE, curr_value, sizeof(struct itimerval)))) {\n\t\t\treturn errno;\n\t\t}\n\t}\n\n\tswitch(which) {\n\t\tcase ITIMER_REAL:\n\t\t\tticks2tv(current->it_real_interval, &curr_value->it_interval);\n\t\t\tticks2tv(current->it_real_value, &curr_value->it_value);\n\t\t\tbreak;\n\t\tcase ITIMER_VIRTUAL:\n\t\t\tticks2tv(current->it_virt_interval, &curr_value->it_interval);\n\t\t\tticks2tv(current->it_virt_value, &curr_value->it_value);\n\t\t\tbreak;\n\t\tcase ITIMER_PROF:\n\t\t\tticks2tv(current->it_prof_interval, &curr_value->it_interval);\n\t\t\tticks2tv(current->it_prof_value, &curr_value->it_value);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\treturn -EINVAL;\n\t}\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/getpgid.c",
    "content": "/*\n * fiwix/kernel/syscalls/getpgid.c\n *\n * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/process.h>\n#include <fiwix/sched.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_getpgid(__pid_t pid)\n{\n\tstruct proc *p;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_getpgid(%d)\\n\", current->pid, pid);\n#endif /*__DEBUG__ */\n\n\tif(pid < 0) {\n\t\treturn -EINVAL;\n\t}\n\tif(!pid) {\n\t\treturn current->pgid;\n\t}\n\tFOR_EACH_PROCESS(p) {\n\t\tif(p->pid == pid) {\n\t\t\treturn p->pgid;\n\t\t}\n\t\tp = p->next;\n\t}\n\treturn -ESRCH;\n}\n"
  },
  {
    "path": "kernel/syscalls/getpgrp.c",
    "content": "/*\n * fiwix/kernel/syscalls/getpgrp.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/process.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_getpgrp(void)\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_getpgrp() -> %d\\n\", current->pid, current->pgid);\n#endif /*__DEBUG__ */\n\treturn current->pgid;\n}\n"
  },
  {
    "path": "kernel/syscalls/getpid.c",
    "content": "/*\n * fiwix/kernel/syscalls/getpid.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/process.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_getpid(void)\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_getpid() -> %d\\n\", current->pid, current->pid);\n#endif /*__DEBUG__ */\n\treturn current->pid;\n}\n"
  },
  {
    "path": "kernel/syscalls/getppid.c",
    "content": "/*\n * fiwix/kernel/syscalls/getppid.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/process.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_getppid(void)\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_getppid() -> %d\\n\", current->pid, current->ppid->pid);\n#endif /*__DEBUG__ */\n\treturn current->ppid->pid;\n}\n"
  },
  {
    "path": "kernel/syscalls/getrlimit.c",
    "content": "/*\n * fiwix/kernel/syscalls/getrlimit.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/resource.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_getrlimit(int resource, struct rlimit *rlim)\n{\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_getrlimit(%d, 0x%08x)\\n\", current->pid, resource, (unsigned int)rlim);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_user_area(VERIFY_WRITE, rlim, sizeof(struct rlimit)))) {\n\t\treturn errno;\n\t}\n\tif(resource < 0 || resource >= RLIM_NLIMITS) {\n\t\treturn -EINVAL;\n\t}\n\n\trlim->rlim_cur = current->rlim[resource].rlim_cur;\n\trlim->rlim_max = current->rlim[resource].rlim_max;\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/getrusage.c",
    "content": "/*\n * fiwix/kernel/syscalls/getrusage.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/resource.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_getrusage(int who, struct rusage *usage)\n{\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_getrusage(%d, 0x%08x)\\n\", current->pid, who, (unsigned int)usage);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_user_area(VERIFY_WRITE, usage, sizeof(struct rusage)))) {\n\t\treturn errno;\n\t}\n\tswitch(who) {\n\t\tcase RUSAGE_SELF:\n\t\t\tmemcpy_b(usage, &current->usage, sizeof(struct rusage));\n\t\t\tbreak;\n\t\tcase RUSAGE_CHILDREN:\n\t\t\tmemcpy_b(usage, &current->cusage, sizeof(struct rusage));\n\t\t\tbreak;\n\t\tdefault:\n\t\t\treturn -EINVAL;\n\t}\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/getsid.c",
    "content": "/*\n * fiwix/kernel/syscalls/getsid.c\n *\n * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/process.h>\n#include <fiwix/sched.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_getsid(__pid_t pid)\n{\n\tstruct proc *p;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_getsid(%d)\\n\", current->pid, pid);\n#endif /*__DEBUG__ */\n\n\tif(pid < 0) {\n\t\treturn -EINVAL;\n\t}\n\tif(!pid) {\n\t\treturn current->sid;\n\t}\n\n\tFOR_EACH_PROCESS(p) {\n\t\tif(p->pid == pid) {\n\t\t\treturn p->sid;\n\t\t}\n\t\tp = p->next;\n\t}\n\treturn -ESRCH;\n}\n"
  },
  {
    "path": "kernel/syscalls/gettimeofday.c",
    "content": "/*\n * fiwix/kernel/syscalls/gettimeofday.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/fs.h>\n#include <fiwix/process.h>\n#include <fiwix/time.h>\n#include <fiwix/timer.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_gettimeofday(struct timeval *tv, struct timezone *tz)\n{\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_gettimeofday()\\n\", current->pid);\n#endif /*__DEBUG__ */\n\n\tif(tv) {\n\t\tif((errno = check_user_area(VERIFY_WRITE, tv, sizeof(struct timeval)))) {\n\t\t\treturn errno;\n\t\t}\n\t\ttv->tv_sec = CURRENT_TIME;\n\t\ttv->tv_usec = ((CURRENT_TICKS % HZ) * 1000000) / HZ;\n\t\ttv->tv_usec += gettimeoffset();\n\t}\n\tif(tz) {\n\t\tif((errno = check_user_area(VERIFY_WRITE, tz, sizeof(struct timezone)))) {\n\t\t\treturn errno;\n\t\t}\n\t\ttz->tz_minuteswest = kstat.tz_minuteswest;\n\t\ttz->tz_dsttime = kstat.tz_dsttime;\n\t}\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/getuid.c",
    "content": "/*\n * fiwix/kernel/syscalls/getuid.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/process.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_getuid(void)\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_getuid() -> %d\\n\", current->pid, current->uid);\n#endif /*__DEBUG__ */\n\n\treturn current->uid;\n}\n"
  },
  {
    "path": "kernel/syscalls/ioctl.c",
    "content": "/*\n * fiwix/kernel/syscalls/ioctl.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_ioctl(unsigned int ufd, int cmd, unsigned int arg)\n{\n\tint errno;\n\tstruct inode *i;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_ioctl(%d, 0x%x, 0x%08x) -> \", current->pid, ufd, cmd, arg);\n#endif /*__DEBUG__ */\n\n\tCHECK_UFD(ufd);\n\ti = fd_table[current->fd[ufd]].inode;\n\tif(i->fsop && i->fsop->ioctl) {\n\t\terrno = i->fsop->ioctl(i, &fd_table[current->fd[ufd]], cmd, arg);\n\n#ifdef __DEBUG__\n\t\tprintk(\"%d\\n\", errno);\n#endif /*__DEBUG__ */\n\n\t\treturn errno;\n\t}\n\n#ifdef __DEBUG__\n\tprintk(\"%d\\n\", -ENOTTY);\n#endif /*__DEBUG__ */\n\n\treturn -ENOTTY;\n}\n"
  },
  {
    "path": "kernel/syscalls/ioperm.c",
    "content": "/*\n * fiwix/kernel/syscalls/ioperm.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\n/*\n * This sys_ioperm() implementation, unlike what Linux 2.0 API said, covers all\n * the I/O address space. That is, up to 65536 I/O ports can be specified using\n * this system call, which makes sys_iopl() not needed anymore.\n */\nint sys_ioperm(unsigned int from, unsigned int num, int turn_on)\n{\n\tunsigned int n;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_ioperm(0x%08x, 0x%08x, 0x%08x)\\n\", current->pid, from, num, turn_on);\n#endif /*__DEBUG__ */\n\n\tif(!IS_SUPERUSER) {\n\t\treturn -EPERM;\n\t}\n\tif(from + num >= (IO_BITMAP_SIZE * 8)) {\n\t\treturn -EINVAL;\n\t}\n\n\t/*\n\t * The Linux 2.0 API states that if 'turn_on' is non-zero the access to\n\t * port must be guaranteed, otherwise the access must be denied.\n\t *\n\t * The Intel specification works in the opposite way. That is, if bit\n\t * is zero the access to port is guaranteed, otherwise is not.\n\t *\n\t * That's the reason why we need to negate the value of 'turn_on' before\n\t * changing the I/O permission bitmap.\n\t */\n\tturn_on = !turn_on;\n\n\tfor(n = from; n < (from + num); n++) {\n\t\tif(!turn_on) {\n\t\t\tcurrent->tss.io_bitmap[n / 8] &= ~(1 << (n % 8));\n\t\t} else {\n\t\t\tcurrent->tss.io_bitmap[n / 8] |= ~(1 << (n % 8));\n\t\t}\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/iopl.c",
    "content": "/*\n * fiwix/kernel/syscalls/iopl.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n/*\n * Chapter Input/Output of IA-32 Intel(R) Architecture Software Developer's\n * Manual Volume 1 Basic Architecture, says the processor permits applications\n * to access I/O ports in either of two ways: by using I/O address space or by\n * using memory-mapped I/O. Linux 2.0 and Fiwix uses the first one.\n *\n * This system call sets the IOPL field in the EFLAGS register to the value of\n * 'level' (which is pressumably zero), so the current process will have\n * privileges to use any port, even when the port is denied by the I/O bitmap\n * in TSS.  Otherwise the processor would check the I/O permission bitmap to\n * determine if access to a specific I/O port is allowed.\n *\n * This system call is dangerous and must not be used because it permits the\n * process to execute the Assembly instruction 'cli', which would freeze the\n * kernel.\n */\n\n#include <fiwix/process.h>\n#include <fiwix/segments.h>\n#include <fiwix/sigcontext.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\n#ifdef CONFIG_SYSCALL_6TH_ARG\nint sys_iopl(int level, int arg2, int arg3, int arg4, int arg5, int arg6, struct sigcontext *sc)\n#else\nint sys_iopl(int level, int arg2, int arg3, int arg4, int arg5, struct sigcontext *sc)\n#endif /* CONFIG_SYSCALL_6TH_ARG */\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_iopl(%d) -> \", current->pid, level);\n#endif /*__DEBUG__ */\n\tif(level > USER_PL) {\n#ifdef __DEBUG__\n\tprintk(\"-EINVAL\\n\");\n#endif /*__DEBUG__ */\n\t\treturn -EINVAL;\n\t}\n\tif(!IS_SUPERUSER) {\n#ifdef __DEBUG__\n\tprintk(\"-EPERM\\n\");\n#endif /*__DEBUG__ */\n\t\treturn -EPERM;\n\t}\n\n\tsc->eflags = (sc->eflags & 0xFFFFCFFF) | (level << EF_IOPL);\n#ifdef __DEBUG__\n\tprintk(\"0\\n\");\n#endif /*__DEBUG__ */\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/ipc.c",
    "content": "/*\n * fiwix/kernel/syscalls/ipc.c\n *\n * Copyright 2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/config.h>\n#include <fiwix/types.h>\n#include <fiwix/errno.h>\n#include <fiwix/process.h>\n#include <fiwix/string.h>\n#include <fiwix/ipc.h>\n#include <fiwix/sem.h>\n#include <fiwix/msg.h>\n#include <fiwix/shm.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\n#ifdef CONFIG_SYSVIPC\nstruct resource ipcmsg_resource = { 0, 0 };\n\nvoid ipc_init(void)\n{\n\tsem_init();\n\tmsg_init();\n\tshm_init();\n}\n\nint ipc_has_perms(struct ipc_perm *perm, int mode)\n{\n\tif(IS_SUPERUSER) {\n\t\treturn 1;\n\t}\n\n\tif(current->euid != perm->uid || current->euid != perm->cuid) {\n\t\tmode >>= 3;\n\t\tif(current->egid != perm->gid || current->egid != perm->cgid) {\n\t\t\tmode >>= 3;\n\t\t}\n\t}\n\n\t/*\n\t * The user may specify zero for the second argument in xxxget() to\n\t * bypass this check, and be able to obtain an identifier for an IPC\n\t * object even when the user don't has read or write access to that\n\t * IPC object. Later specific IPC calls will return error if the\n\t * program attempted an operation requiring read or write permission\n\t * on the IPC object.\n\t */\n\tif(!mode) {\n\t\treturn 1;\n\t}\n\n\tif(perm->mode & mode) {\n\t\treturn 1;\n\t}\n\n\treturn 0;\n}\n\n/*\n * This implementation follows basically the same semantics as in Linux 2.0\n * ABI. That is, the sys_ipc() system call acts as a common entry point for\n * the System V IPC calls for semaphores, message queues and shared memory.\n *\n * The only exception is that Fiwix, by default, uses a structure that holds\n * all arguments needed by all System V IPC functions. This, of course, breaks\n * compatibility with the Linux 2.0 ABI, unless you rebuild the program under\n * FiwixOS. For those that are unable to rebuild an old program (no source code\n * available, etc.), you must rebuild the Fiwix kernel with the configuration\n * option CONFIG_SYSCALL_6TH_ARG enabled. This will enable full Linux 2.0 ABI\n * compatibility and the program will run successfully.\n */\n\n#ifdef CONFIG_SYSCALL_6TH_ARG\n/*\n * This option adds more Linux 2.0 ABI compatibility to support the original\n * sys_ipc() system call, which requires up to 6 arguments.\n *\n * Fiwix by default uses a maximum of 5 arguments per system call, so any\n * binary built on FiwixOS will use a different implementation of the\n * sys_ipc(), and also any other system call that requires more than 5\n * arguments. This breaks compatibility with Linux 2.0 ABI.\n *\n * In order to include the 6th argument, Fiwix will use the register 'ebp'\n * which might lead to some problems. Use this with caution.\n *\n * This configuration option should only be used if you need to execute a\n * Linux 2.0 binary and, for some reason, you cannot rebuild it on FiwixOS.\n */\nint sys_ipc(unsigned int call, int first, int second, int third, void *ptr, int fifth)\n{\n\tstruct sysvipc_args orig_args, *args;\n\tstruct ipc_kludge {\n\t\tstruct msgbuf *msgp;\n\t\tint msgtyp;\n\t} tmp;\n\tint version, errno;\n\tunion semun *arg;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_ipc(%d, %d, %d, %d, 0x%08x, %d)\\n\", current->pid, call, first, second, third, (int)ptr, fifth);\n#endif /*__DEBUG__ */\n\n\torig_args.arg1 = first;\n\torig_args.arg2 = second;\n\torig_args.arg3 = third;\n\torig_args.ptr = ptr;\n\torig_args.arg5 = fifth;\n\n\tswitch(call) {\n\t\tcase SEMCTL:\n\t\t\tif(!ptr) {\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\tif((errno = check_user_area(VERIFY_READ, ptr, sizeof(tmp)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\targ = ptr;\n\t\t\torig_args.ptr = arg->array;\n\t\t\tbreak;\n\t\tcase MSGRCV:\n\t\t\tversion = call >> 16;\n\t\t\tswitch(version) {\n\t\t\t\tcase 0:\n\t\t\t\t\tif(!ptr) {\n\t\t\t\t\t\treturn -EINVAL;\n\t\t\t\t\t}\n\t\t\t\t\tif((errno = check_user_area(VERIFY_READ, ptr, sizeof(tmp)))) {\n\t\t\t\t\t\treturn errno;\n\t\t\t\t\t}\n\t\t\t\t\tmemcpy_b(&tmp, (struct ipc_kludge *)ptr, sizeof(tmp));\n\t\t\t\t\torig_args.arg3 = tmp.msgtyp;\n\t\t\t\t\torig_args.ptr = tmp.msgp;\n\t\t\t\t\torig_args.arg5 = third;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\torig_args.arg3 = fifth;\n\t\t\t\t\torig_args.arg5 = third;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase SHMAT:\n\t\t\tversion = call >> 16;\n\t\t\tswitch(version) {\n\t\t\t\tcase 0:\n\t\t\t\t\tif((errno = check_user_area(VERIFY_WRITE, (unsigned int *)third, sizeof(unsigned int)))) {\n\t\t\t\t\t\treturn errno;\n\t\t\t\t\t}\n\t\t\t\t\torig_args.arg3 = (int)&third;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\tbreak;\n\t}\n\targs = &orig_args;\n#else\nint sys_ipc(unsigned int call, struct sysvipc_args *args)\n{\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_ipc(%d, 0x%08x)\\n\", current->pid, call, (int)args);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_user_area(VERIFY_READ, args, sizeof(struct sysvipc_args)))) {\n\t\treturn errno;\n\t}\n\n#endif /* CONFIG_SYSCALL_6TH_ARG */\n\tswitch(call) {\n\t\tcase SEMOP:\n\t\t\treturn sys_semop(args->arg1, args->ptr, args->arg2);\n\t\tcase SEMGET:\n\t\t\treturn sys_semget(args->arg1, args->arg2, args->arg3);\n\t\tcase SEMCTL:\n\t\t\treturn sys_semctl(args->arg1, args->arg2, args->arg3, args->ptr);\n\t\tcase MSGSND:\n\t\t\treturn sys_msgsnd(args->arg1, args->ptr, args->arg2, args->arg3);\n\t\tcase MSGRCV:\n\t\t\treturn sys_msgrcv(args->arg1, args->ptr, args->arg2, args->arg3, args->arg5);\n\t\tcase MSGGET:\n\t\t\treturn sys_msgget((key_t)args->arg1, args->arg2);\n\t\tcase MSGCTL:\n\t\t\treturn sys_msgctl(args->arg1, args->arg2, args->ptr);\n\t\tcase SHMAT:\n\t\t\tif((errno = sys_shmat(args->arg1, args->ptr, args->arg2, (unsigned int *)&args->arg3))) {\n\t\t\t\treturn errno;\n\t\t\t}\n#ifdef CONFIG_SYSCALL_6TH_ARG\n\t\t\tmemcpy_l((unsigned int *)third, &args->arg3, 1);\n\t\t\treturn 0;\n#else\n\t\t\treturn args->arg3;\n#endif /* CONFIG_SYSCALL_6TH_ARG */\n\t\tcase SHMDT:\n\t\t\treturn sys_shmdt(args->ptr);\n\t\tcase SHMGET:\n\t\t\treturn sys_shmget(args->arg1, args->arg2, args->arg3);\n\t\tcase SHMCTL:\n\t\t\treturn sys_shmctl(args->arg1, args->arg2, args->ptr);\n\t}\n\treturn -EINVAL;\n}\n#endif /* CONFIG_SYSVIPC */\n"
  },
  {
    "path": "kernel/syscalls/kill.c",
    "content": "/*\n * fiwix/kernel/syscalls/kill.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/process.h>\n#include <fiwix/signal.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_kill(__pid_t pid, __sigset_t signum)\n{\n\tint count;\n\tstruct proc *p;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_kill(%d, %d)\\n\", current->pid, pid, signum);\n#endif /*__DEBUG__ */\n\n\tif(signum > NSIG) {\n\t\treturn -EINVAL;\n\t}\n\tif(pid == -1) {\n\t\tcount = 0;\n\t\tFOR_EACH_PROCESS(p) {\n\t\t\tif(p->pid == INIT || p == current || !can_signal(p)) {\n\t\t\t\tp = p->next;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tcount++;\n\t\t\tsend_sig(p, signum);\n\t\t\tp = p->next;\n\t\t}\n\t\treturn count ? 0 : -ESRCH;\n\t}\n\tif(!pid) {\n\t\treturn kill_pgrp(current->pgid, signum, USER);\n\t}\n\tif(pid < 1) {\n\t\treturn kill_pgrp(-pid, signum, USER);\n\t}\n\n\treturn kill_pid(pid, signum, USER);\n}\n"
  },
  {
    "path": "kernel/syscalls/lchown.c",
    "content": "/*\n * fiwix/kernel/syscalls/lchown.c\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/kernel.h>\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_lchown(const char *filename, __uid_t owner, __gid_t group)\n{\n\tstruct inode *i;\n\tchar *tmp_name;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_lchown('%s', %d, %d)\\n\", current->pid, filename, owner, group);\n#endif /*__DEBUG__ */\n\n\tif((errno = malloc_name(filename, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = namei(tmp_name, &i, NULL, !FOLLOW_LINKS))) {\n\t\tfree_name(tmp_name);\n\t\treturn errno;\n\t}\n\n\tif(IS_RDONLY_FS(i)) {\n\t\tiput(i);\n\t\tfree_name(tmp_name);\n\t\treturn -EROFS;\n\t}\n\tif(check_user_permission(i)) {\n\t\tiput(i);\n\t\tfree_name(tmp_name);\n\t\treturn -EPERM;\n\t}\n\n\tif(owner == (__uid_t)-1) {\n\t\towner = i->i_uid;\n\t} else {\n\t\ti->i_mode &= ~(S_ISUID);\n\t\ti->i_ctime = CURRENT_TIME;\n\t}\n\tif(group == (__gid_t)-1) {\n\t\tgroup = i->i_gid;\n\t} else {\n\t\ti->i_mode &= ~(S_ISGID);\n\t\ti->i_ctime = CURRENT_TIME;\n\t}\n\n\ti->i_uid = owner;\n\ti->i_gid = group;\n\ti->state |= INODE_DIRTY;\n\tiput(i);\n\tfree_name(tmp_name);\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/link.c",
    "content": "/*\n * fiwix/kernel/syscalls/link.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_link(const char *oldname, const char *newname)\n{\n\tstruct inode *i, *dir, *i_new, *dir_new;\n\tchar *tmp_oldname, *tmp_newname, *basename;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_link('%s', '%s')\\n\", current->pid, oldname, newname);\n#endif /*__DEBUG__ */\n\n\tif((errno = malloc_name(oldname, &tmp_oldname)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = malloc_name(newname, &tmp_newname)) < 0) {\n\t\tfree_name(tmp_oldname);\n\t\treturn errno;\n\t}\n\n\tif((errno = namei(tmp_oldname, &i, &dir, !FOLLOW_LINKS))) {\n\t\tif(dir) {\n\t\t\tiput(dir);\n\t\t}\n\t\tfree_name(tmp_oldname);\n\t\tfree_name(tmp_newname);\n\t\treturn errno;\n\t}\n\tif(S_ISDIR(i->i_mode)) {\n\t\tiput(i);\n\t\tiput(dir);\n\t\tfree_name(tmp_oldname);\n\t\tfree_name(tmp_newname);\n\t\treturn -EPERM;\n\t}\n\tif(IS_RDONLY_FS(i)) {\n\t\tiput(i);\n\t\tiput(dir);\n\t\tfree_name(tmp_oldname);\n\t\tfree_name(tmp_newname);\n\t\treturn -EROFS;\n\t}\n\tif(i->i_nlink == LINK_MAX) {\n\t\tiput(i);\n\t\tiput(dir);\n\t\tfree_name(tmp_oldname);\n\t\tfree_name(tmp_newname);\n\t\treturn -EMLINK;\n\t}\n\n\tbasename = get_basename(tmp_newname);\n\tif((errno = namei(tmp_newname, &i_new, &dir_new, !FOLLOW_LINKS))) {\n\t\tif(!dir_new) {\n\t\t\tiput(i);\n\t\t\tiput(dir);\n\t\t\tfree_name(tmp_oldname);\n\t\t\tfree_name(tmp_newname);\n\t\t\treturn errno;\n\t\t}\n\t}\n\tif(!errno) {\n\t\tiput(i);\n\t\tiput(dir);\n\t\tiput(i_new);\n\t\tiput(dir_new);\n\t\tfree_name(tmp_oldname);\n\t\tfree_name(tmp_newname);\n\t\treturn -EEXIST;\n\t}\n\tif(i->dev != dir_new->dev) {\n\t\tiput(i);\n\t\tiput(dir);\n\t\tiput(dir_new);\n\t\tfree_name(tmp_oldname);\n\t\tfree_name(tmp_newname);\n\t\treturn -EXDEV;\n\t}\n\tif(check_permission(TO_EXEC | TO_WRITE, dir_new) < 0) {\n\t\tiput(i);\n\t\tiput(dir);\n\t\tiput(dir_new);\n\t\tfree_name(tmp_oldname);\n\t\tfree_name(tmp_newname);\n\t\treturn -EACCES;\n\t}\n\n\tif(dir_new->fsop && dir_new->fsop->link) {\n\t\terrno = dir_new->fsop->link(i, dir_new, basename);\n\t} else {\n\t\terrno = -EPERM;\n\t}\n\tiput(i);\n\tiput(dir);\n\tiput(dir_new);\n\tfree_name(tmp_oldname);\n\tfree_name(tmp_newname);\n\treturn errno;\n}\n"
  },
  {
    "path": "kernel/syscalls/llseek.c",
    "content": "/*\n * fiwix/kernel/syscalls/llseek.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_llseek(unsigned int ufd, unsigned int offset_high, unsigned int offset_low, __loff_t *result, unsigned int whence)\n{\n\tstruct inode *i;\n\t__loff_t offset, new_offset;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_llseek(%d, %u, %u, %08x, %d)\", current->pid, ufd, offset_high, offset_low, result, whence);\n#endif /*__DEBUG__ */\n\n\tCHECK_UFD(ufd);\n\tif((errno = check_user_area(VERIFY_WRITE, result, sizeof(__loff_t)))) {\n\t\treturn errno;\n\t}\n\ti = fd_table[current->fd[ufd]].inode;\n\toffset = (__loff_t)(((__loff_t)offset_high << 32) | offset_low);\n\tswitch(whence) {\n\t\tcase SEEK_SET:\n\t\t\tnew_offset = offset;\n\t\t\tbreak;\n\t\tcase SEEK_CUR:\n\t\t\tnew_offset = fd_table[current->fd[ufd]].offset + offset;\n\t\t\tbreak;\n\t\tcase SEEK_END:\n\t\t\tnew_offset = i->i_size + offset;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\treturn -EINVAL;\n\t}\n\tif(i->fsop && i->fsop->llseek) {\n\t\tfd_table[current->fd[ufd]].offset = new_offset;\n\t\tif((new_offset = i->fsop->llseek(i, new_offset)) < 0) {\n\t\t\treturn (int)new_offset;\n\t\t}\n\t} else {\n\t\treturn -EPERM;\n\t}\n\tmemcpy_b(result, &new_offset, sizeof(__loff_t));\n\n#ifdef __DEBUG__\n\tprintk(\" -> returning %lu\\n\", *result);\n#endif /*__DEBUG__ */\n\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/lseek.c",
    "content": "/*\n * fiwix/kernel/syscalls/lseek.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/syscalls.h>\n#include <fiwix/fs.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_lseek(unsigned int ufd, __off_t offset, unsigned int whence)\n{\n\tstruct inode *i;\n\t__off_t new_offset;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_lseek(%d, %d, %d)\", current->pid, ufd, offset, whence);\n#endif /*__DEBUG__ */\n\n\tCHECK_UFD(ufd);\n\n\ti = fd_table[current->fd[ufd]].inode;\n\tswitch(whence) {\n\t\tcase SEEK_SET:\n\t\t\tnew_offset = offset;\n\t\t\tbreak;\n\t\tcase SEEK_CUR:\n\t\t\tnew_offset = fd_table[current->fd[ufd]].offset + offset;\n\t\t\tbreak;\n\t\tcase SEEK_END:\n\t\t\tnew_offset = i->i_size + offset;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\treturn -EINVAL;\n\t}\n\tif((int)new_offset < 0) {\n\t\treturn -EINVAL;\n\t}\n\tif(i->fsop && i->fsop->llseek) {\n\t\tfd_table[current->fd[ufd]].offset = new_offset;\n\t\tnew_offset = i->fsop->llseek(i, new_offset);\n\t} else {\n\t\treturn -EPERM;\n\t}\n\n#ifdef __DEBUG__\n\tprintk(\" -> returning %d\\n\", new_offset);\n#endif /*__DEBUG__ */\n\n\treturn new_offset;\n}\n"
  },
  {
    "path": "kernel/syscalls/lstat.c",
    "content": "/*\n * fiwix/kernel/syscalls/lstat.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_lstat(const char *filename, struct old_stat *statbuf)\n{\n\tstruct inode *i;\n\tchar *tmp_name;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_lstat('%s', 0x%08x) -> returning structure\\n\", current->pid, filename, (unsigned int )statbuf);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_user_area(VERIFY_WRITE, statbuf, sizeof(struct old_stat)))) {\n\t\treturn errno;\n\t}\n\tif((errno = malloc_name(filename, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = namei(tmp_name, &i, NULL, !FOLLOW_LINKS))) {\n\t\tfree_name(tmp_name);\n\t\treturn errno;\n\t}\n\tstatbuf->st_dev = i->dev;\n\tstatbuf->st_ino = i->inode;\n\tstatbuf->st_mode = i->i_mode;\n\tstatbuf->st_nlink = i->i_nlink;\n\tstatbuf->st_uid = i->i_uid;\n\tstatbuf->st_gid = i->i_gid;\n\tstatbuf->st_rdev = i->rdev;\n\tstatbuf->st_size = i->i_size;\n\tstatbuf->st_atime = i->i_atime;\n\tstatbuf->st_mtime = i->i_mtime;\n\tstatbuf->st_ctime = i->i_ctime;\n\tiput(i);\n\tfree_name(tmp_name);\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/lstat64.c",
    "content": "/*\n * fiwix/kernel/syscalls/lstat64.c\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Copyright 2023, Richard R. Masters.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/statbuf.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_lstat64(const char *filename, struct stat64 *statbuf)\n{\n\tstruct inode *i;\n\tchar *tmp_name;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_lstat64('%s', 0x%08x) -> returning structure\\n\", current->pid, filename, (unsigned int)statbuf);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_user_area(VERIFY_WRITE, statbuf, sizeof(struct stat64)))) {\n\t\treturn errno;\n\t}\n\tif((errno = malloc_name(filename, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = namei(tmp_name, &i, NULL, !FOLLOW_LINKS))) {\n\t\tfree_name(tmp_name);\n\t\treturn errno;\n\t}\n\tstatbuf->st_dev = i->dev;\n\tstatbuf->__st_dev_padding = 0;\n\tstatbuf->st_ino = i->inode;\n\tstatbuf->st_mode = i->i_mode;\n\tstatbuf->st_nlink = i->i_nlink;\n\tstatbuf->st_uid = i->i_uid;\n\tstatbuf->st_gid = i->i_gid;\n\tstatbuf->st_rdev = i->rdev;\n\tstatbuf->__st_rdev_padding = 0;\n\tstatbuf->st_size = i->i_size;\n\tstatbuf->st_blksize = i->sb->s_blocksize;\n\tstatbuf->st_blocks = i->i_blocks;\n\tif(!i->i_blocks) {\n\t\tstatbuf->st_blocks = (i->i_size / i->sb->s_blocksize) * 2;\n\t\tstatbuf->st_blocks++;\n\t}\n\tstatbuf->st_atime = i->i_atime;\n\tstatbuf->st_mtime = i->i_mtime;\n\tstatbuf->st_ctime = i->i_ctime;\n\tiput(i);\n\tfree_name(tmp_name);\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/mkdir.c",
    "content": "/*\n * fiwix/kernel/syscalls/mkdir.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_mkdir(const char *dirname, __mode_t mode)\n{\n\tstruct inode *i, *dir;\n\tchar *tmp_dirname, *basename;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_mkdir('%s', %o)\\n\", current->pid, dirname, mode);\n#endif /*__DEBUG__ */\n\n\tif((errno = malloc_name(dirname, &tmp_dirname)) < 0) {\n\t\treturn errno;\n\t}\n\tbasename = remove_trailing_slash(tmp_dirname);\n\tif((errno = namei(basename, &i, &dir, !FOLLOW_LINKS))) {\n\t\tif(!dir) {\n\t\t\tfree_name(tmp_dirname);\n\t\t\treturn errno;\n\t\t}\n\t}\n\tif(!errno) {\n\t\tiput(i);\n\t\tiput(dir);\n\t\tfree_name(tmp_dirname);\n\t\treturn -EEXIST;\n\t}\n\tif(IS_RDONLY_FS(dir)) {\n\t\tiput(dir);\n\t\tfree_name(tmp_dirname);\n\t\treturn -EROFS;\n\t}\n\n\tif(check_permission(TO_EXEC | TO_WRITE, dir) < 0) {\n\t\tiput(dir);\n\t\tfree_name(tmp_dirname);\n\t\treturn -EACCES;\n\t}\n\n\tbasename = get_basename(basename);\n\tif(dir->fsop && dir->fsop->mkdir) {\n\t\terrno = dir->fsop->mkdir(dir, basename, mode);\n\t} else {\n\t\terrno = -EPERM;\n\t}\n\tiput(dir);\n\tfree_name(tmp_dirname);\n\treturn errno;\n}\n"
  },
  {
    "path": "kernel/syscalls/mknod.c",
    "content": "/*\n * fiwix/kernel/syscalls/mknod.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint do_mknod(char *pathname, __mode_t mode, __dev_t dev)\n{\n\tstruct inode *i, *dir;\n\tchar *basename;\n\tint errno;\n\n\tbasename = get_basename(pathname);\n\tif((errno = namei(pathname, &i, &dir, !FOLLOW_LINKS))) {\n\t\tif(!dir) {\n\t\t\treturn errno;\n\t\t}\n\t}\n\tif(!errno) {\n\t\tiput(i);\n\t\tiput(dir);\n\t\treturn -EEXIST;\n\t}\n\tif(IS_RDONLY_FS(dir)) {\n\t\tiput(dir);\n\t\treturn -EROFS;\n\t}\n\tif(check_permission(TO_EXEC | TO_WRITE, dir) < 0) {\n\t\tiput(dir);\n\t\treturn -EACCES;\n\t}\n\n\tif(dir->fsop && dir->fsop->mknod) {\n\t\terrno = dir->fsop->mknod(dir, basename, mode, dev);\n\t} else {\n\t\terrno = -EPERM;\n\t}\n\tiput(dir);\n\treturn errno;\n}\n\nint sys_mknod(const char *pathname, __mode_t mode, __dev_t dev)\n{\n\tchar *tmp_name;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_mknod('%s', %d, %x)\\n\", current->pid, pathname, mode, dev);\n#endif /*__DEBUG__ */\n\n\tif(!S_ISCHR(mode) && !S_ISBLK(mode) && !S_ISFIFO(mode)) {\n\t\treturn -EINVAL;\n\t}\n\tif(!S_ISFIFO(mode) && !IS_SUPERUSER) {\n\t\treturn -EPERM;\n\t}\n\n\tif((errno = malloc_name(pathname, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\terrno = do_mknod(tmp_name, mode, dev);\n\tfree_name(tmp_name);\n\treturn errno;\n}\n"
  },
  {
    "path": "kernel/syscalls/mmap2.c",
    "content": "/*\n * fiwix/kernel/syscalls/mmap2.c\n *\n * Copyright 2018-2023, Jordi Sanfeliu. All rights reserved.\n * Copyright 2023, Richard R. Masters. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/mman.h>\n#include <fiwix/mm.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\n#ifdef CONFIG_SYSCALL_6TH_ARG\n#ifdef CONFIG_MMAP2\nint sys_mmap2(unsigned int start, unsigned int length, unsigned int prot, unsigned int user_flags, int fd, unsigned int offset)\n{\n\tunsigned int page;\n\tstruct inode *i;\n\tchar flags;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_mmap2(0x%08x, %d, 0x%02x, 0x%02x, %d, 0x%08x) -> \", current->pid, start, length, prot, user_flags, fd, offset);\n#endif /*__DEBUG__ */\n\n\tif(!length) {\n\t\treturn -EINVAL;\n\t}\n\n\ti = NULL;\n\tflags = 0;\n\tif(!(user_flags & MAP_ANONYMOUS)) {\n\t\tCHECK_UFD(fd);\n\t\tif(!(i = fd_table[current->fd[fd]].inode)) {\n\t\t\treturn -EBADF;\n\t\t}\n\t\tflags = fd_table[current->fd[fd]].flags & O_ACCMODE;\n\t}\n\tpage = do_mmap(i, start, length, prot, user_flags, offset*4096, P_MMAP, flags, NULL);\n#ifdef __DEBUG__\n\tprintk(\"0x%08x\\n\", page);\n#endif /*__DEBUG__ */\n\treturn page;\n}\n#endif /* CONFIG_MMAP2 */\n#endif /* CONFIG_SYSCALL_6TH_ARG */\n"
  },
  {
    "path": "kernel/syscalls/mount.c",
    "content": "/*\n * fiwix/kernel/syscalls/mount.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/buffer.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_mount(const char *source, const char *target, const char *fstype, unsigned int flags, const void *data)\n{\n\tstruct inode *i_source, *i_target;\n\tstruct mount *mp;\n\tstruct filesystems *fs;\n\tchar *tmp_source, *tmp_target, *tmp_fstype;\n\t__dev_t dev;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_mount(%s, %s, %s, 0x%08x, 0x%08x\\n\", current->pid, source, target, (int)fstype ? fstype : \"<NULL>\", flags, data);\n#endif /* __DEBUG__ */\n\n\tif(!IS_SUPERUSER) {\n\t\treturn -EPERM;\n\t}\n\n\tif((errno = malloc_name(target, &tmp_target)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = namei(tmp_target, &i_target, NULL, FOLLOW_LINKS))) {\n\t\tfree_name(tmp_target);\n\t\treturn errno;\n\t}\n\tif(!S_ISDIR(i_target->i_mode)) {\n\t\tiput(i_target);\n\t\tfree_name(tmp_target);\n\t\treturn -ENOTDIR;\n\t}\n\tif((flags & MS_MGC_VAL) == MS_MGC_VAL) {\n\t\tflags &= ~MS_MGC_MSK;\n\t}\n\n\tif(flags & MS_REMOUNT) {\n\t\tif(!(mp = get_mount_point(i_target))) {\n\t\t\tiput(i_target);\n\t\t\tfree_name(tmp_target);\n\t\t\treturn -EINVAL;\n\t\t}\n\t\tfs = mp->fs;\n\t\tif(fs->fsop && fs->fsop->remount_fs) {\n\t\t\tif((errno = fs->fsop->remount_fs(&mp->sb, flags))) {\n\t\t\t\tiput(i_target);\n\t\t\t\tfree_name(tmp_target);\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t} else {\n\t\t\tiput(i_target);\n\t\t\tfree_name(tmp_target);\n\t\t\treturn -EINVAL;\n\t\t}\n\n\t\t/* switching from RW to RO */\n\t\tif(flags & MS_RDONLY && !(mp->sb.flags & MS_RDONLY)) {\n\t\t\tdev = mp->dev;\n\t\t\t/* \n\t\t\t * FIXME: if there are files opened in RW mode then\n\t\t\t * we can't continue and must return -EBUSY.\n\t\t\t */\n\t\t\tif(fs->fsop && fs->fsop->release_superblock) {\n\t\t\t\tfs->fsop->release_superblock(&mp->sb);\n\t\t\t}\n\t\t\tsync_superblocks(dev);\n\t\t\tsync_inodes(dev);\n\t\t\tsync_buffers(dev);\n\t\t}\n\n\t\tmp->sb.flags &= ~MS_RDONLY;\n\t\tmp->sb.flags |= (flags & MS_RDONLY);\n\t\tiput(i_target);\n\t\tfree_name(tmp_target);\n\t\treturn 0;\n\t}\n\n\tif(i_target->mount_point) {\n\t\tiput(i_target);\n\t\tfree_name(tmp_target);\n\t\treturn -EBUSY;\n\t}\n\n\tif((errno = malloc_name(fstype, &tmp_fstype)) < 0) {\n\t\tiput(i_target);\n\t\tfree_name(tmp_target);\n\t\treturn errno;\n\t}\n\tif(!(fs = get_filesystem(tmp_fstype))) {\n\t\tiput(i_target);\n\t\tfree_name(tmp_target);\n\t\tfree_name(tmp_fstype);\n\t\treturn -ENODEV;\n\t}\n\tdev = fs->fsop->fsdev;\n\n\tif((errno = malloc_name(source, &tmp_source)) < 0) {\n\t\tiput(i_target);\n\t\tfree_name(tmp_target);\n\t\tfree_name(tmp_fstype);\n\t\treturn errno;\n\t}\n\tif(fs->fsop->flags == FSOP_REQUIRES_DEV) {\n\t\tif((errno = namei(tmp_source, &i_source, NULL, FOLLOW_LINKS))) {\n\t\t\tiput(i_target);\n\t\t\tfree_name(tmp_target);\n\t\t\tfree_name(tmp_fstype);\n\t\t\tfree_name(tmp_source);\n\t\t\treturn errno;\n\t\t}\n\t\tif(!S_ISBLK(i_source->i_mode)) {\n\t\t\tiput(i_target);\n\t\t\tiput(i_source);\n\t\t\tfree_name(tmp_target);\n\t\t\tfree_name(tmp_fstype);\n\t\t\tfree_name(tmp_source);\n\t\t\treturn -ENOTBLK;\n\t\t}\n\t\tif(i_source->fsop && i_source->fsop->open) {\n\t\t\tif((errno = i_source->fsop->open(i_source, NULL))) {\n\t\t\t\tiput(i_target);\n\t\t\t\tiput(i_source);\n\t\t\t\tfree_name(tmp_target);\n\t\t\t\tfree_name(tmp_fstype);\n\t\t\t\tfree_name(tmp_source);\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t} else {\n\t\t\tiput(i_target);\n\t\t\tiput(i_source);\n\t\t\tfree_name(tmp_target);\n\t\t\tfree_name(tmp_fstype);\n\t\t\tfree_name(tmp_source);\n\t\t\treturn -EINVAL;\n\t\t}\n\t\tdev = i_source->rdev;\n\t}\n\n\tif(!(mp = add_mount_point(dev, tmp_source, tmp_target))) {\n\t\tif(fs->fsop->flags == FSOP_REQUIRES_DEV) {\n\t\t\ti_source->fsop->close(i_source, NULL);\n\t\t\tiput(i_source);\n\t\t}\n\t\tiput(i_target);\n\t\tfree_name(tmp_target);\n\t\tfree_name(tmp_fstype);\n\t\tfree_name(tmp_source);\n\t\treturn -EBUSY;\n\t}\n\n\tmp->sb.flags = flags;\n\tif(fs->fsop->read_superblock) {\n\t\tif((errno = fs->fsop->read_superblock(dev, &mp->sb))) {\n\t\t\ti_source->fsop->close(i_source, NULL);\n\t\t\tif(fs->fsop->flags == FSOP_REQUIRES_DEV) {\n\t\t\t\tiput(i_source);\n\t\t\t}\n\t\t\tiput(i_target);\n\t\t\tdel_mount_point(mp);\n\t\t\tfree_name(tmp_target);\n\t\t\tfree_name(tmp_fstype);\n\t\t\tfree_name(tmp_source);\n\t\t\treturn errno;\n\t\t}\n\t} else {\n\t\tif(fs->fsop->flags == FSOP_REQUIRES_DEV) {\n\t\t\tiput(i_source);\n\t\t}\n\t\tiput(i_target);\n\t\tdel_mount_point(mp);\n\t\tfree_name(tmp_target);\n\t\tfree_name(tmp_fstype);\n\t\tfree_name(tmp_source);\n\t\treturn -EINVAL;\n\t}\n\n\tmp->sb.dir = i_target;\n\tmp->fs = fs;\n\tfs->mp = mp;\n\ti_target->mount_point = mp->sb.root;\n\tfree_name(tmp_target);\n\tfree_name(tmp_fstype);\n\tfree_name(tmp_source);\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/mprotect.c",
    "content": "/*\n * fiwix/kernel/syscalls/mprotect.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/mman.h>\n#include <fiwix/mm.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_mprotect(unsigned int addr, __size_t length, int prot)\n{\n\tstruct vma *vma;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_mprotect(0x%08x, %d, %d)\\n\", current->pid, addr, length, prot);\n#endif /*__DEBUG__ */\n\n\tif(addr & ~PAGE_MASK) {\n\t\treturn -EINVAL;\n\t}\n\tif(prot > (PROT_READ | PROT_WRITE | PROT_EXEC)) {\n\t\treturn -EINVAL;\n\t}\n\tlength = PAGE_ALIGN(length);\n\tif((addr + length) < addr) {\n\t\treturn -EINVAL;\n\t}\n\tif(!(vma = find_vma_region(addr))) {\n\t\treturn -ENOMEM;\n\t}\n\tif((addr + length) > vma->end) {\n\t\treturn -ENOMEM;\n\t}\n\tif(vma->inode && (vma->flags & MAP_SHARED)) {\n\t\tif(prot & PROT_WRITE) {\n\t\t\tif(!(vma->o_mode & (O_WRONLY | O_RDWR))) {\n\t\t\t\treturn -EACCES;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn do_mprotect(vma, addr, length, prot);\n}\n"
  },
  {
    "path": "kernel/syscalls/msgctl.c",
    "content": "/*\n * fiwix/kernel/syscalls/msgctl.c\n *\n * Copyright 2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/config.h>\n#include <fiwix/kernel.h>\n#include <fiwix/types.h>\n#include <fiwix/string.h>\n#include <fiwix/process.h>\n#include <fiwix/sched.h>\n#include <fiwix/errno.h>\n#include <fiwix/ipc.h>\n#include <fiwix/msg.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\n#ifdef CONFIG_SYSVIPC\nint sys_msgctl(int msqid, int cmd, struct msqid_ds *buf)\n{\n\tstruct msqid_ds *mq;\n\tstruct msginfo *mi;\n\tstruct ipc_perm *perm;\n\tstruct msg *m, *mn;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_msgctl(%d, %d, 0x%x)\\n\", current->pid, msqid, cmd, (int)buf);\n#endif /*__DEBUG__ */\n\n\tif(msqid < 0) {\n\t\treturn -EINVAL;\n\t}\n\n\tswitch(cmd) {\t\n\t\tcase MSG_STAT:\n\t\tcase IPC_STAT:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, buf, sizeof(struct msqid_ds)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tmq = msgque[msqid % MSGMNI];\n\t\t\tif(mq == IPC_UNUSED) {\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\tif(!ipc_has_perms(&mq->msg_perm, IPC_R)) {\n\t\t\t\treturn -EACCES;\n\t\t\t}\n\t\t\tmemcpy_b(buf, mq, sizeof(struct msqid_ds));\n\t\t\tif(cmd == MSG_STAT) {\n\t\t\t\treturn (mq->msg_perm.seq * MSGMNI) + msqid;\n\t\t\t}\n\t\t\treturn 0;\n\n\t\tcase IPC_SET:\n\t\t\tif((errno = check_user_area(VERIFY_READ, buf, sizeof(struct msqid_ds)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tmq = msgque[msqid % MSGMNI];\n\t\t\tif(mq == IPC_UNUSED) {\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\tperm = &mq->msg_perm;\n\t\t\tif(!IS_SUPERUSER && current->euid != perm->uid && current->euid != perm->cuid) {\n\t\t\t\treturn -EPERM;\n\t\t\t}\n\t\t\tif(!IS_SUPERUSER && buf->msg_qbytes > MSGMNB) {\n\t\t\t\treturn -EPERM;\n\t\t\t}\n\t\t\tmq->msg_qbytes = buf->msg_qbytes;\n\t\t\tperm->uid = buf->msg_perm.uid;\n\t\t\tperm->gid = buf->msg_perm.gid;\n\t\t\tperm->mode = (perm->mode & ~0777) | (buf->msg_perm.mode & 0777);\n\t\t\tmq->msg_ctime = CURRENT_TIME;\n\t\t\treturn 0;\n\n\t\tcase IPC_RMID:\n\t\t\tmq = msgque[msqid % MSGMNI];\n\t\t\tif(mq == IPC_UNUSED) {\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\tperm = &mq->msg_perm;\n\t\t\tif(!IS_SUPERUSER && current->euid != perm->uid && current->euid != perm->cuid) {\n\t\t\t\treturn -EPERM;\n\t\t\t}\n\t\t\tif((m = mq->msg_first)) {\n\t\t\t\tdo {\n\t\t\t\t\tmq->msg_qnum--;\n\t\t\t\t\tmq->msg_cbytes -= m->msg_ts;\n\t\t\t\t\tnum_msgs--;\n\t\t\t\t\tmn = m->msg_next;\n\t\t\t\t\tmsg_release_md(m);\n\t\t\t\t\tm = mn;\n\t\t\t\t} while(m);\n\t\t\t}\n\t\t\tmsg_release_mq(mq);\n\t\t\tmsgque[msqid % MSGMNI] = (struct msqid_ds *)IPC_UNUSED;\n\t\t\tnum_queues--;\n\t\t\tmsg_seq++;\n\t\t\tif((msqid % MSGMNI) == max_mqid) {\n\t\t\t\twhile(max_mqid) {\n\t\t\t\t\tif(msgque[max_mqid] != IPC_UNUSED) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tmax_mqid--;\n\t\t\t\t}\n\t\t\t}\n\t\t\twakeup(mq);\n\t\t\treturn 0;\n\n\t\tcase MSG_INFO:\n\t\tcase IPC_INFO:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, buf, sizeof(struct msqid_ds)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tmi = (struct msginfo *)buf;\n\t\t\tif(cmd == MSG_INFO) {\n\t\t\t\tmi->msgpool = num_queues;\n\t\t\t\tmi->msgmap = num_msgs;\n\t\t\t\tmi->msgssz = 0;\t\t/* FIXME: pending to do */\n\t\t\t\tmi->msgtql = 0;\t\t/* FIXME: pending to do */\n\t\t\t\tmi->msgseg = 0;\t\t/* FIXME: pending to do */\n\t\t\t} else {\n\t\t\t\tmi->msgpool = 0;\t/* FIXME: pending to do */\n\t\t\t\tmi->msgmap = 0;\t\t/* FIXME: pending to do */\n\t\t\t\tmi->msgssz = 0;\t\t/* FIXME: pending to do */\n\t\t\t\tmi->msgtql = MSGTQL;\n\t\t\t\tmi->msgseg = 0;\t\t/* FIXME: pending to do */\n\t\t\t}\n\t\t\tmi->msgmax = MSGMAX;\n\t\t\tmi->msgmnb = MSGMNB;\n\t\t\tmi->msgmni = MSGMNI;\n\t\t\treturn max_mqid;\n\t}\n\n\treturn -EINVAL;\n}\n#endif /* CONFIG_SYSVIPC */\n"
  },
  {
    "path": "kernel/syscalls/msgget.c",
    "content": "/*\n * fiwix/kernel/syscalls/msgget.c\n *\n * Copyright 2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/types.h>\n#include <fiwix/string.h>\n#include <fiwix/errno.h>\n#include <fiwix/process.h>\n#include <fiwix/ipc.h>\n#include <fiwix/msg.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\n#ifdef CONFIG_SYSVIPC\nstruct msqid_ds *msgque[MSGMNI];\nunsigned int num_queues;\nunsigned int num_msgs;\nunsigned int max_mqid;\nunsigned int msg_seq;\n\n/* FIXME: this should be allocated dynamically */\nstatic struct msqid_ds msgque_pool[MSGMNI];\nstruct msqid_ds *msg_get_new_mq(void)\n{\n\tint n;\n\n\tfor(n = 0; n < MSGMNI; n++) {\n\t\tif(msgque_pool[n].msg_ctime == 0) {\n\t\t\tmsgque_pool[n].msg_ctime = 1;\n\t\t\treturn &msgque_pool[n];\n\t\t}\n\t}\n\treturn NULL;\n}\n\nvoid msg_release_mq(struct msqid_ds *mq)\n{\n\tmemset_b(mq, 0, sizeof(struct msqid_ds));\n}\n\nstruct msg msg_pool[MSGTQL];\nstruct msg *msg_get_new_md(void)\n{\n\tunsigned int n;\n\n\tlock_resource(&ipcmsg_resource);\n\n\tfor(n = 0; n < MSGTQL; n++) {\n\t\tif(msg_pool[n].msg_stime == 0) {\n\t\t\tmsg_pool[n].msg_stime = 1;\n\t\t\tunlock_resource(&ipcmsg_resource);\n\t\t\treturn &msg_pool[n];\n\t\t}\n\t}\n\n\tunlock_resource(&ipcmsg_resource);\n\treturn NULL;\n}\n\nvoid msg_release_md(struct msg *msg)\n{\n\tlock_resource(&ipcmsg_resource);\n\tmemset_b(msg, 0, sizeof(struct msg));\n\tunlock_resource(&ipcmsg_resource);\n}\n\nvoid msg_init(void)\n{\n\tint n;\n\n\tfor(n = 0; n < MSGMNI; n++) {\n\t\tmsgque[n] = (struct msqid_ds *)IPC_UNUSED;\n\t}\n\tmemset_b(msgque_pool, 0, sizeof(msgque_pool));\n\tmemset_b(msg_pool, 0, sizeof(msg_pool));\n\tnum_queues = num_msgs = max_mqid = msg_seq = 0;\n}\n\nint sys_msgget(key_t key, int msgflg)\n{\n\tstruct msqid_ds *mq;\n\tstruct ipc_perm *perm;\n\tint n;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_msgget(%d, 0x%x)\\n\", current->pid, (int)key, msgflg);\n#endif /*__DEBUG__ */\n\n\tif(key == IPC_PRIVATE) {\n\t\t/* create a new message queue */\n\t\tif(!(mq = msg_get_new_mq())) {\n\t\t\treturn -ENOMEM;\n\t\t}\n\t\tfor(n = 0; n < MSGMNI; n++) {\n\t\t\tif(msgque[n] == (struct msqid_ds *)IPC_UNUSED) {\n\t\t\t\tgoto init;\n\t\t\t}\n\t\t}\n\t\tmsg_release_mq(mq);\n\t\treturn -ENOSPC;\n\t}\n\n\tmq = NULL;\n\n\tfor(n = 0; n < MSGMNI; n++) {\n\t\tif(msgque[n] == (struct msqid_ds *)IPC_UNUSED) {\n\t\t\tcontinue;\n\t\t}\n\t\tif(key == msgque[n]->msg_perm.key) {\n\t\t\tmq = msgque[n];\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif(!mq) {\n\t\tif(!(msgflg & IPC_CREAT)) {\n\t\t\treturn -ENOENT;\n\t\t}\n\n\t\t/* create a new message queue */\n\t\tif(!(mq = msg_get_new_mq())) {\n\t\t\treturn -ENOMEM;\n\t\t}\n\t\tfor(n = 0; n < MSGMNI; n++) {\n\t\t\tif(msgque[n] == (struct msqid_ds *)IPC_UNUSED) {\n\t\t\t\tgoto init;\n\t\t\t}\n\t\t}\n\t\tmsg_release_mq(mq);\n\t\treturn -ENOSPC;\n\t} else {\n\t\tif((msgflg & (IPC_CREAT | IPC_EXCL)) == (IPC_CREAT | IPC_EXCL)) {\n\t\t\treturn -EEXIST;\n\t\t}\n\t\tif(!ipc_has_perms(&mq->msg_perm, msgflg)) {\n\t\t\treturn -EACCES;\n\t\t}\n\t\treturn (mq->msg_perm.seq * MSGMNI) + n;\n\t}\n\ninit:\n\tperm = &mq->msg_perm;\n\tperm->key = key;\n\tperm->uid = perm->cuid = current->euid;\n\tperm->gid = perm->cgid = current->egid;\n\tperm->mode = msgflg & 0777;\n\tperm->seq = msg_seq;\n\tmq->msg_first = mq->msg_last = NULL;\n\tmq->msg_stime = mq->msg_rtime = 0;\n\tmq->msg_ctime = CURRENT_TIME;\n\tmq->unused1 = mq->unused2 = 0;\n\tmq->msg_cbytes = mq->msg_qnum = 0;\n\tmq->msg_qbytes = MSGMNB;\n\tmq->msg_lspid = mq->msg_lrpid = 0;\n\tmsgque[n] = mq;\n\tif(n > max_mqid) {\n\t\tmax_mqid = n;\n\t}\n\tnum_queues++;\n\treturn (mq->msg_perm.seq * MSGMNI) + n;\n}\n#endif /* CONFIG_SYSVIPC */\n"
  },
  {
    "path": "kernel/syscalls/msgrcv.c",
    "content": "/*\n * fiwix/kernel/syscalls/msgrcv.c\n *\n * Copyright 2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/config.h>\n#include <fiwix/kernel.h>\n#include <fiwix/types.h>\n#include <fiwix/string.h>\n#include <fiwix/errno.h>\n#include <fiwix/process.h>\n#include <fiwix/sleep.h>\n#include <fiwix/sched.h>\n#include <fiwix/mm.h>\n#include <fiwix/ipc.h>\n#include <fiwix/msg.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\n#ifdef CONFIG_SYSVIPC\nint sys_msgrcv(int msqid, void *msgp, __size_t msgsz, int msgtyp, int msgflg)\n{\n\tstruct msqid_ds *mq;\n\tstruct msgbuf *mb;\n\tstruct msg *m, *mprev;\n\tint errno, found, count;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_msgrcv(%d, 0x%08x, %d, %d, 0x%x)\\n\", current->pid, msqid, (int)msgp, msgsz, msgtyp, msgflg);\n#endif /*__DEBUG__ */\n\n\tif(msqid < 0) {\n\t\treturn -EINVAL;\n\t}\n\tif((errno = check_user_area(VERIFY_WRITE, msgp, sizeof(void *)))) {\n\t\treturn errno;\n\t}\n\tmq = msgque[msqid % MSGMNI];\n\tif(mq == IPC_UNUSED) {\n\t\treturn -EINVAL;\n\t}\n\tfound = 0;\n\tmprev = NULL;\n\tfor(;;) {\n\t\tif(!ipc_has_perms(&mq->msg_perm, IPC_R)) {\n\t\t\treturn -EACCES;\n\t\t}\n\t\tif((m = mq->msg_first)) {\n\t\t\tif(!msgtyp) {\n\t\t\t\tbreak;\n\t\t\t} else if(msgtyp > 0) {\n\t\t\t\tif(msgflg & MSG_EXCEPT) {\n\t\t\t\t\twhile(m) {\n\t\t\t\t\t\tif(m->msg_type != msgtyp) {\n\t\t\t\t\t\t\tfound = 1;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmprev = m;\n\t\t\t\t\t\tm = m->msg_next;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\twhile(m) {\n\t\t\t\t\t\tif(m->msg_type == msgtyp) {\n\t\t\t\t\t\t\tfound = 1;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmprev = m;\n\t\t\t\t\t\tm = m->msg_next;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t/* FIXME: pending to do */\n\t\t\t}\n\t\t}\n\t\tif(found) {\n\t\t\tbreak;\n\t\t}\n\t\tif(msgflg & IPC_NOWAIT) {\n\t\t\treturn -ENOMSG;\n\t\t}\n\t\tif(sleep(mq, PROC_INTERRUPTIBLE)) {\n\t\t\treturn -EINTR;\n\t\t}\n\t\tmq = msgque[msqid % MSGMNI];\n\t\tif(mq == IPC_UNUSED) {\n\t\t\treturn -EIDRM;\n\t\t}\n\t}\n\n\tif(msgsz < m->msg_ts) {\n\t\tif(!(msgflg & MSG_NOERROR)) {\n\t\t\treturn -E2BIG;\n\t\t}\n\t\tcount = msgsz;\n\t} else {\n\t\tcount = m->msg_ts;\n\t}\n\n\tmb = (struct msgbuf *)msgp;\n\tmb->mtype = m->msg_type;\n\tmemcpy_b(mb->mtext, m->msg_spot, count);\n\n\tlock_resource(&ipcmsg_resource);\n\tkfree((unsigned int)m->msg_spot);\n\tif(!mprev) {\n\t\tmq->msg_first = m->msg_next;\n\t} else {\n\t\tmprev->msg_next = m->msg_next;\n\t}\n\tmq->msg_rtime = mq->msg_ctime = CURRENT_TIME;\n\tmq->msg_qnum--;\n\tmq->msg_cbytes -= m->msg_ts;\n\tmq->msg_lrpid = current->pid;\n\tnum_msgs--;\n\tunlock_resource(&ipcmsg_resource);\n\tmsg_release_md(m);\n\twakeup(mq);\n\treturn count;\n}\n#endif /* CONFIG_SYSVIPC */\n"
  },
  {
    "path": "kernel/syscalls/msgsnd.c",
    "content": "/*\n * fiwix/kernel/syscalls/msgsnd.c\n *\n * Copyright 2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/config.h>\n#include <fiwix/kernel.h>\n#include <fiwix/types.h>\n#include <fiwix/string.h>\n#include <fiwix/errno.h>\n#include <fiwix/process.h>\n#include <fiwix/sleep.h>\n#include <fiwix/sched.h>\n#include <fiwix/mm.h>\n#include <fiwix/ipc.h>\n#include <fiwix/msg.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\n#ifdef CONFIG_SYSVIPC\nint sys_msgsnd(int msqid, const void *msgp, __size_t msgsz, int msgflg)\n{\n\tstruct msqid_ds *mq;\n\tstruct msgbuf *mb;\n\tstruct msg *m;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_msgsnd(%d, 0x%08x, %d, 0x%x)\\n\", current->pid, msqid, (int)msgp, msgsz, msgflg);\n#endif /*__DEBUG__ */\n\n\tif(msqid < 0 || msgsz > MSGMAX) {\n\t\treturn -EINVAL;\n\t}\n\tif((errno = check_user_area(VERIFY_READ, msgp, sizeof(void *)))) {\n\t\treturn errno;\n\t}\n\tmb = (struct msgbuf *)msgp;\n\tif(mb->mtype < 0) {\n\t\treturn -EINVAL;\n\t}\n\tif((errno = check_user_area(VERIFY_READ, mb->mtext, msgsz))) {\n\t\treturn errno;\n\t}\n\n\tmq = msgque[msqid % MSGMNI];\n\tif(mq == IPC_UNUSED) {\n\t\treturn -EINVAL;\n\t}\n\tfor(;;) {\n\t\tif(!ipc_has_perms(&mq->msg_perm, IPC_W)) {\n\t\t\treturn -EACCES;\n\t\t}\n\t\tif(mq->msg_cbytes + msgsz > mq->msg_qbytes || mq->msg_qnum + 1 > mq->msg_qbytes) {\n\t\t\tif(msgflg & IPC_NOWAIT) {\n\t\t\t\treturn -EAGAIN;\n\t\t\t}\n\t\t\tif(sleep(mq, PROC_INTERRUPTIBLE)) {\n\t\t\t\treturn -EINTR;\n\t\t\t}\n\t\t}\n\t\tif(mq == IPC_UNUSED) {\n\t\t\treturn -EIDRM;\n\t\t}\n\t\tbreak;\n\t}\n\n\tif(!(m = msg_get_new_md())) {\n\t\treturn -ENOMEM;\n\t}\n\tm->msg_next = NULL;\n\tm->msg_type = mb->mtype;\n\tif(!(m->msg_spot = (void *)kmalloc(PAGE_SIZE))) {\n\t\tmsg_release_md(m);\n\t\treturn -ENOMEM;\n\t}\n\tmemcpy_b(m->msg_spot, mb->mtext, msgsz);\n\tm->msg_stime = CURRENT_TIME;\n\tm->msg_ts = msgsz;\n\tlock_resource(&ipcmsg_resource);\n\tif(!mq->msg_first) {\n\t\tmq->msg_first = mq->msg_last = m;\n\t} else {\n\t\tmq->msg_last->msg_next = m;\n\t\tmq->msg_last = m;\n\t}\n\tmq->msg_stime = mq->msg_ctime = CURRENT_TIME;\n\tmq->msg_qnum++;\n\tmq->msg_cbytes += msgsz;\n\tmq->msg_lspid = current->pid;\n\tnum_msgs++;\n\tunlock_resource(&ipcmsg_resource);\n\twakeup(mq);\n\treturn 0;\n}\n#endif /* CONFIG_SYSVIPC */\n"
  },
  {
    "path": "kernel/syscalls/munmap.c",
    "content": "/*\n * fiwix/kernel/syscalls/munmap.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/mman.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_munmap(unsigned int addr, __size_t length)\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_munmap(0x%08x, %d)\\n\", current->pid, addr, length);\n#endif /*__DEBUG__ */\n\treturn do_munmap(addr, length);\n}\n"
  },
  {
    "path": "kernel/syscalls/nanosleep.c",
    "content": "/*\n * fiwix/kernel/syscalls/nanosleep.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/fs.h>\n#include <fiwix/time.h>\n#include <fiwix/timer.h>\n#include <fiwix/process.h>\n#include <fiwix/sched.h>\n#include <fiwix/sleep.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_nanosleep(const struct timespec *req, struct timespec *rem)\n{\n\tint errno, nsec;\n\tunsigned int timeout, flags;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_nanosleep(0x%08x, 0x%08x)\\n\", current->pid, (unsigned int)req, (unsigned int)rem);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_user_area(VERIFY_READ, req, sizeof(struct timespec)))) {\n\t\treturn errno;\n\t}\n\tif(req->tv_sec < 0 || req->tv_nsec >= 1000000000L || req->tv_nsec < 0) {\n\t\treturn -EINVAL;\n\t}\n\n\t/*\n\t * Since the current maximum precision of the kernel is only 10ms, we\n\t * need to convert any lower request to a minimum of 10ms, even knowing\n\t * that this might increase the sleep a bit more than the requested.\n\t */\n\tnsec = req->tv_nsec;\n\tif(nsec < 10000000L) {\n\t\tnsec *= 10;\n\t}\n\n\t/*\n\t * Interrupts must be disabled before setting current->timeout in order\n\t * to avoid a race condition. Otherwise it might occur that timeout is\n\t * so small that it would reach zero before the call to sleep(). In this\n\t * case, the process would miss the wakeup() and would stay in the sleep\n\t * queue forever.\n\t */\n\ttimeout = (req->tv_sec * HZ) + (nsec * HZ / 1000000000L);\n\tif(timeout) {\n\t\tSAVE_FLAGS(flags); CLI();\n\t\tcurrent->timeout = timeout;\n\t\tsleep(&sys_nanosleep, PROC_INTERRUPTIBLE);\n\t\tRESTORE_FLAGS(flags);\n\t\tif(current->timeout) {\n\t\t\tif(rem) {\n\t\t\t\tif((errno = check_user_area(VERIFY_WRITE, rem, sizeof(struct timespec)))) {\n\t\t\t\t\treturn errno;\n\t\t\t\t}\n\t\t\t\trem->tv_sec = current->timeout / HZ;\n\t\t\t\trem->tv_nsec = (current->timeout % HZ) * 1000000000L / HZ;\n\t\t\t}\n\t\t\treturn -EINTR;\n\t\t}\n\t}\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/newfstat.c",
    "content": "/*\n * fiwix/kernel/syscalls/newfstat.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/statbuf.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_newfstat(unsigned int ufd, struct new_stat *statbuf)\n{\n\tstruct inode *i;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_newfstat(%d, 0x%08x) -> returning structure\\n\", current->pid, ufd, (unsigned int )statbuf);\n#endif /*__DEBUG__ */\n\n\tCHECK_UFD(ufd);\n\tif((errno = check_user_area(VERIFY_WRITE, statbuf, sizeof(struct new_stat)))) {\n\t\treturn errno;\n\t}\n\ti = fd_table[current->fd[ufd]].inode;\n\tstatbuf->st_dev = i->dev;\n\tstatbuf->__pad1 = 0;\n\tstatbuf->st_ino = i->inode;\n\tstatbuf->st_mode = i->i_mode;\n\tstatbuf->st_nlink = i->i_nlink;\n\tstatbuf->st_uid = i->i_uid;\n\tstatbuf->st_gid = i->i_gid;\n\tstatbuf->st_rdev = i->rdev;\n\tstatbuf->__pad2 = 0;\n\tstatbuf->st_size = i->i_size;\n\tstatbuf->st_blksize = i->sb->s_blocksize;\n\tstatbuf->st_blocks = i->i_blocks;\n\tif(!i->i_blocks) {\n\t\tstatbuf->st_blocks = (i->i_size / i->sb->s_blocksize * 2);\n\t\tstatbuf->st_blocks++;\n\t}\n\tstatbuf->st_atime = i->i_atime;\n\tstatbuf->__unused1 = 0;\n\tstatbuf->st_mtime = i->i_mtime;\n\tstatbuf->__unused2 = 0;\n\tstatbuf->st_ctime = i->i_ctime;\n\tstatbuf->__unused3 = 0;\n\tstatbuf->__unused4 = 0;\n\tstatbuf->__unused5 = 0;\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/newlstat.c",
    "content": "/*\n * fiwix/kernel/syscalls/newlstat.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/statbuf.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_newlstat(const char *filename, struct new_stat *statbuf)\n{\n\tstruct inode *i;\n\tchar *tmp_name;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_newlstat('%s', 0x%08x) -> returning structure\\n\", current->pid, filename, (unsigned int )statbuf);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_user_area(VERIFY_WRITE, statbuf, sizeof(struct new_stat)))) {\n\t\treturn errno;\n\t}\n\tif((errno = malloc_name(filename, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = namei(tmp_name, &i, NULL, !FOLLOW_LINKS))) {\n\t\tfree_name(tmp_name);\n\t\treturn errno;\n\t}\n\tstatbuf->st_dev = i->dev;\n\tstatbuf->__pad1 = 0;\n\tstatbuf->st_ino = i->inode;\n\tstatbuf->st_mode = i->i_mode;\n\tstatbuf->st_nlink = i->i_nlink;\n\tstatbuf->st_uid = i->i_uid;\n\tstatbuf->st_gid = i->i_gid;\n\tstatbuf->st_rdev = i->rdev;\n\tstatbuf->__pad2 = 0;\n\tstatbuf->st_size = i->i_size;\n\tstatbuf->st_blksize = i->sb->s_blocksize;\n\tstatbuf->st_blocks = i->i_blocks;\n\tif(!i->i_blocks) {\n\t\tstatbuf->st_blocks = (i->i_size / i->sb->s_blocksize) * 2;\n\t\tstatbuf->st_blocks++;\n\t}\n\tstatbuf->st_atime = i->i_atime;\n\tstatbuf->__unused1 = 0;\n\tstatbuf->st_mtime = i->i_mtime;\n\tstatbuf->__unused2 = 0;\n\tstatbuf->st_ctime = i->i_ctime;\n\tstatbuf->__unused3 = 0;\n\tstatbuf->__unused4 = 0;\n\tstatbuf->__unused5 = 0;\n\tiput(i);\n\tfree_name(tmp_name);\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/newstat.c",
    "content": "/*\n * fiwix/kernel/syscalls/newstat.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/statbuf.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_newstat(const char *filename, struct new_stat *statbuf)\n{\n\tstruct inode *i;\n\tchar *tmp_name;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_newstat('%s', 0x%08x) -> returning structure\\n\", current->pid, filename, (unsigned int )statbuf);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_user_area(VERIFY_WRITE, statbuf, sizeof(struct new_stat)))) {\n\t\treturn errno;\n\t}\n\tif((errno = malloc_name(filename, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = namei(tmp_name, &i, NULL, FOLLOW_LINKS))) {\n\t\tfree_name(tmp_name);\n\t\treturn errno;\n\t}\n\tstatbuf->st_dev = i->dev;\n\tstatbuf->__pad1 = 0;\n\tstatbuf->st_ino = i->inode;\n\tstatbuf->st_mode = i->i_mode;\n\tstatbuf->st_nlink = i->i_nlink;\n\tstatbuf->st_uid = i->i_uid;\n\tstatbuf->st_gid = i->i_gid;\n\tstatbuf->st_rdev = i->rdev;\n\tstatbuf->__pad2 = 0;\n\tstatbuf->st_size = i->i_size;\n\tstatbuf->st_blksize = i->sb->s_blocksize;\n\tstatbuf->st_blocks = i->i_blocks;\n\tif(!i->i_blocks) {\n\t\tstatbuf->st_blocks = (i->i_size / i->sb->s_blocksize) * 2;\n\t\tstatbuf->st_blocks++;\n\t}\n\tstatbuf->st_atime = i->i_atime;\n\tstatbuf->__unused1 = 0;\n\tstatbuf->st_mtime = i->i_mtime;\n\tstatbuf->__unused2 = 0;\n\tstatbuf->st_ctime = i->i_ctime;\n\tstatbuf->__unused3 = 0;\n\tstatbuf->__unused4 = 0;\n\tstatbuf->__unused5 = 0;\n\tiput(i);\n\tfree_name(tmp_name);\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/newuname.c",
    "content": "/*\n * fiwix/kernel/syscalls/newuname.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/utsname.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_newuname(struct new_utsname *uname)\n{\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_newuname(0x%08x)\\n\", current->pid, (int)uname);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_user_area(VERIFY_WRITE, uname, sizeof(struct new_utsname)))) {\n\t\treturn errno;\n\t}\n\tif(!uname) {\n\t\treturn -EFAULT;\n\t}\n\tmemcpy_b(uname, &sys_utsname, sizeof(struct new_utsname));\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/old_mmap.c",
    "content": "/*\n * fiwix/kernel/syscalls/old_mmap.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/mman.h>\n#include <fiwix/mm.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint old_mmap(struct mmap *mmap)\n{\n\tunsigned int page;\n\tstruct inode *i;\n\tchar flags;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) old_mmap(0x%08x, %d, 0x%02x, 0x%02x, %d, 0x%08x) -> \", current->pid, mmap->start, mmap->length, mmap->prot, mmap->flags, mmap->fd, mmap->offset);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_user_area(VERIFY_READ, mmap, sizeof(struct mmap)))) {\n\t\treturn errno;\n\t}\n\tif(!mmap->length) {\n\t\treturn -EINVAL;\n\t}\n\n\ti = NULL;\n\tflags = 0;\n\tif(!(mmap->flags & MAP_ANONYMOUS)) {\n\t\tCHECK_UFD(mmap->fd);\n\t\tif(!(i = fd_table[current->fd[mmap->fd]].inode)) {\n\t\t\treturn -EBADF;\n\t\t}\n\t\tflags = fd_table[current->fd[mmap->fd]].flags & O_ACCMODE;\n\t}\n\tpage = do_mmap(i, mmap->start, mmap->length, mmap->prot, mmap->flags, mmap->offset, P_MMAP, flags, NULL);\n#ifdef __DEBUG__\n\tprintk(\"0x%08x\\n\", page);\n#endif /*__DEBUG__ */\n\treturn page;\n}\n"
  },
  {
    "path": "kernel/syscalls/old_select.c",
    "content": "/*\n * fiwix/kernel/syscalls/old_select.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/syscalls.h>\n#include <fiwix/fs.h>\n#include <fiwix/sleep.h>\n#include <fiwix/sched.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint old_select(unsigned int *params)\n{\n\tint nfds;\n\tfd_set *readfds;\n\tfd_set *writefds;\n\tfd_set *exceptfds;\n\tstruct timeval *timeout;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) old_select(0x%08x)\\n\", current->pid, (int)params);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_user_area(VERIFY_READ, (void *)params, sizeof(unsigned int) * 5))) {\n\t\treturn errno;\n\t}\n\tnfds = *(int *)params;\n\treadfds = *(fd_set **)(params + 1);\n\twritefds = *(fd_set **)(params + 2);\n\texceptfds = *(fd_set **)(params + 3);\n\ttimeout = *(struct timeval **)(params + 4);\n\n\treturn sys_select(nfds, readfds, writefds, exceptfds, timeout);\n}\n"
  },
  {
    "path": "kernel/syscalls/olduname.c",
    "content": "/*\n * fiwix/kernel/syscalls/olduname.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/utsname.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_olduname(struct oldold_utsname *uname)\n{\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_olduname(0x%0x)\", current->pid, uname);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_user_area(VERIFY_WRITE, uname, sizeof(struct oldold_utsname)))) {\n\t\treturn errno;\n\t}\n\tmemcpy_b(&uname->sysname, &sys_utsname.sysname, _OLD_UTSNAME_LENGTH);\n\tmemset_b(&uname->sysname + _OLD_UTSNAME_LENGTH, 0, 1);\n\tmemcpy_b(&uname->nodename, &sys_utsname.nodename, _OLD_UTSNAME_LENGTH);\n\tmemset_b(&uname->nodename + _OLD_UTSNAME_LENGTH, 0, 1);\n\tmemcpy_b(&uname->release, &sys_utsname.release, _OLD_UTSNAME_LENGTH);\n\tmemset_b(&uname->release + _OLD_UTSNAME_LENGTH, 0, 1);\n\tmemcpy_b(&uname->version, &sys_utsname.version, _OLD_UTSNAME_LENGTH);\n\tmemset_b(&uname->version + _OLD_UTSNAME_LENGTH, 0, 1);\n\tmemcpy_b(&uname->machine, &sys_utsname.machine, _OLD_UTSNAME_LENGTH);\n\tmemset_b(&uname->machine + _OLD_UTSNAME_LENGTH, 0, 1);\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/open.c",
    "content": "/*\n * fiwix/kernel/syscalls/open.c\n *\n * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/syscalls.h>\n#include <fiwix/stat.h>\n#include <fiwix/types.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nint sys_open(const char *filename, int flags, __mode_t mode)\n{\n\tint fd, ufd;\n\tstruct inode *i, *dir;\n\tchar *tmp_name, *basename;\n\tint errno, follow_links, perms;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_open('%s', %o, %o)\\n\", current->pid, filename, flags, mode);\n#endif /*__DEBUG__ */\n\n\tif((errno = malloc_name(filename, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\n\tbasename = get_basename(tmp_name);\n\tfollow_links = (flags & O_NOFOLLOW) ? !FOLLOW_LINKS : FOLLOW_LINKS;\n\tif((errno = namei(tmp_name, &i, &dir, follow_links))) {\n\t\tif(!dir) {\n\t\t\tfree_name(tmp_name);\n\t\t\tif(flags & O_CREAT) {\n\t\t\t\treturn -ENOENT;\n\t\t\t}\n\t\t\treturn errno;\n\t\t}\n\t}\n\n#ifdef __DEBUG__\n\tprintk(\"\\t(inode = %d)\\n\", i ? i->inode : -1);\n#endif /*__DEBUG__ */\n\n\tif(!errno) {\n\t\tif(S_ISLNK(i->i_mode) && (flags & O_NOFOLLOW)) {\n\t\t\tiput(i);\n\t\t\tiput(dir);\n\t\t\tfree_name(tmp_name);\n\t\t\treturn -ELOOP;\n\t\t}\n\t\tif(!S_ISDIR(i->i_mode) && (flags & O_DIRECTORY)) {\n\t\t\tiput(i);\n\t\t\tiput(dir);\n\t\t\tfree_name(tmp_name);\n\t\t\treturn -ENOTDIR;\n\t\t}\n\t}\n\n\tif(flags & O_CREAT) {\n\t\tif(!errno && S_ISDIR(i->i_mode)) {\n\t\t\tiput(i);\n\t\t\tiput(dir);\n\t\t\tfree_name(tmp_name);\n\t\t\treturn -EISDIR;\n\t\t}\n\t\tif(!errno && (flags & O_EXCL)) {\n\t\t\tiput(i);\n\t\t\tiput(dir);\n\t\t\tfree_name(tmp_name);\n\t\t\treturn -EEXIST;\n\t\t}\n\t\tif(!i) {\n\t\t\t/*\n\t\t\t * If the file does not exist, you need enough\n\t\t\t * permission in the directory to create it.\n\t\t\t */\n\t\t\tif(check_permission(TO_EXEC | TO_WRITE, dir) < 0) {\n\t\t\t\tiput(i);\n\t\t\t\tiput(dir);\n\t\t\t\tfree_name(tmp_name);\n\t\t\t\treturn -EACCES;\n\t\t\t}\n\t\t}\n\t\tif(IS_RDONLY_FS(dir)) {\n\t\t\tif(!i || S_ISREG(i->i_mode)) {\n\t\t\t\tif(flags & (O_RDWR | O_WRONLY | O_TRUNC)) {\n\t\t\t\t\tiput(i);\n\t\t\t\t\tiput(dir);\n\t\t\t\t\tfree_name(tmp_name);\n\t\t\t\t\treturn -EROFS;\n\t\t\t\t}\n\t\t\t\tflags &= ~(O_RDWR | O_WRONLY | O_TRUNC);\n\t\t\t\tflags |= O_RDONLY;\n\t\t\t}\n\t\t}\n\t\tif(errno) {\t/* assumes -ENOENT */\n\t\t\tif(dir->fsop && dir->fsop->create) {\n\t\t\t\terrno = dir->fsop->create(dir, basename, flags, mode, &i);\n\t\t\t\tif(errno) {\n\t\t\t\t\tiput(dir);\n\t\t\t\t\tfree_name(tmp_name);\n\t\t\t\t\treturn errno;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tiput(dir);\n\t\t\t\tfree_name(tmp_name);\n\t\t\t\treturn -EACCES;\n\t\t\t}\n\t\t}\n\t} else {\n\t\tif(errno) {\n\t\t\tiput(dir);\n\t\t\tfree_name(tmp_name);\n\t\t\treturn errno;\n\t\t}\n\t\tif(flags & (O_RDWR | O_WRONLY | O_TRUNC)) {\n\t\t\tif(S_ISDIR(i->i_mode)) {\n\t\t\t\tiput(i);\n\t\t\t\tiput(dir);\n\t\t\t\tfree_name(tmp_name);\n\t\t\t\treturn -EISDIR;\n\t\t\t}\n\t\t\tif(S_ISREG(i->i_mode) && IS_RDONLY_FS(dir)) {\n\t\t\t\tiput(i);\n\t\t\t\tiput(dir);\n\t\t\t\tfree_name(tmp_name);\n\t\t\t\treturn -EROFS;\n\t\t\t}\n\t\t}\n\t\tmode = 0;\n\t}\n\n\tif((flags & O_ACCMODE) == O_RDONLY) {\n\t\tperms = TO_READ;\n\t} else if((flags & O_ACCMODE) == O_WRONLY) {\n\t\tperms = TO_WRITE;\n\t} else {\n\t\tperms = TO_READ | TO_WRITE;\n\t}\n\tif((errno = check_permission(perms, i))) {\n\t\tiput(i);\n\t\tiput(dir);\n\t\tfree_name(tmp_name);\n\t\treturn errno;\n\t}\n\tif((fd = get_new_fd(i)) < 0) {\n\t\tiput(i);\n\t\tiput(dir);\n\t\tfree_name(tmp_name);\n\t\treturn fd;\n\t}\n\tif((ufd = get_new_user_fd(0)) < 0) {\n\t\trelease_fd(fd);\n\t\tiput(i);\n\t\tiput(dir);\n\t\tfree_name(tmp_name);\n\t\treturn ufd;\n\t}\n\n#ifdef __DEBUG__\n\tprintk(\"\\t(ufd = %d)\\n\", ufd);\n#endif /*__DEBUG__ */\n\n\tfd_table[fd].flags = flags;\n\tcurrent->fd[ufd] = fd;\n\tif(i->fsop && i->fsop->open) {\n\t\tif((errno = i->fsop->open(i, &fd_table[fd])) < 0) {\n\t\t\trelease_fd(fd);\n\t\t\trelease_user_fd(ufd);\n\t\t\tiput(i);\n\t\t\tiput(dir);\n\t\t\tfree_name(tmp_name);\n\t\t\treturn errno;\n\t\t}\n\t\tiput(dir);\n\t\tfree_name(tmp_name);\n\t\treturn ufd;\n\t}\n\n\tprintk(\"WARNING: %s(): file '%s' (inode %d) without the open() method!\\n\", __FUNCTION__, tmp_name, i->inode);\n\trelease_fd(fd);\n\trelease_user_fd(ufd);\n\tiput(i);\n\tiput(dir);\n\tfree_name(tmp_name);\n\treturn -EINVAL;\n}\n"
  },
  {
    "path": "kernel/syscalls/pause.c",
    "content": "/*\n * fiwix/kernel/syscalls/pause.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/syscalls.h>\n#include <fiwix/sched.h>\n#include <fiwix/sleep.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_pause(void)\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_pause()\\n\", current->pid);\n#endif /*__DEBUG__ */\n\n\tfor(;;) {\n\t\tif(sleep(&sys_pause, PROC_INTERRUPTIBLE)) {\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn -EINTR;\n}\n"
  },
  {
    "path": "kernel/syscalls/personality.c",
    "content": "/*\n * fiwix/kernel/syscalls/personality.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_personality(unsigned int persona)\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_personality(%d) -> %d\\n\", current->pid, persona, persona);\n#endif /*__DEBUG__ */\n\treturn persona;\n}\n"
  },
  {
    "path": "kernel/syscalls/pipe.c",
    "content": "/*\n * fiwix/kernel/syscalls/pipe.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n\nint sys_pipe(int pipefd[2])\n{\n\tint rfd, rufd;\n\tint wfd, wufd;\n\tstruct filesystems *fs;\n\tstruct inode *i;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_pipe()\", current->pid);\n#endif /*__DEBUG__ */\n\n\tif(!(fs = get_filesystem(\"pipefs\"))) {\n\t\tprintk(\"WARNING: %s(): pipefs filesystem is not registered!\\n\", __FUNCTION__);\n\t\treturn -EINVAL;\n\t}\n\tif((errno = check_user_area(VERIFY_WRITE, pipefd, sizeof(int) * 2))) {\n\t\treturn errno;\n\t}\n\tif(!(i = ialloc(&fs->mp->sb, S_IFIFO))) {\n\t\treturn -EINVAL;\n\t}\n\tif((rfd = get_new_fd(i)) < 0) {\n\t\tiput(i);\n\t\treturn -ENFILE;\n\t}\n\tif((wfd = get_new_fd(i)) < 0) {\n\t\trelease_fd(rfd);\n\t\tiput(i);\n\t\treturn -ENFILE;\n\t}\n\tif((rufd = get_new_user_fd(0)) < 0) {\n\t\trelease_fd(rfd);\n\t\trelease_fd(wfd);\n\t\tiput(i);\n\t\treturn -EMFILE;\n\t}\n\tif((wufd = get_new_user_fd(0)) < 0) {\n\t\trelease_fd(rfd);\n\t\trelease_fd(wfd);\n\t\trelease_user_fd(rufd);\n\t\tiput(i);\n\t\treturn -EMFILE;\n\t}\n\n\tpipefd[0] = rufd;\n\tpipefd[1] = wufd;\n\tcurrent->fd[rufd] = rfd;\n\tcurrent->fd[wufd] = wfd;\n\tfd_table[rfd].flags = O_RDONLY;\n\tfd_table[wfd].flags = O_WRONLY;\n\n#ifdef __DEBUG__\n\tprintk(\" -> inode=%d, rufd=%d wufd=%d (rfd=%d wfd=%d)\\n\", i->inode, rufd, wufd, rfd, wfd);\n#endif /*__DEBUG__ */\n\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/read.c",
    "content": "/*\n * fiwix/kernel/syscalls/read.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_read(unsigned int ufd, char *buf, int count)\n{\n\tstruct inode *i;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_read(%d, 0x%08x, %d) -> \", current->pid, ufd, buf, count);\n#endif /*__DEBUG__ */\n\n\tCHECK_UFD(ufd);\n\tif((errno = check_user_area(VERIFY_WRITE, buf, count))) {\n\t\treturn errno;\n\t}\n\tif(fd_table[current->fd[ufd]].flags & O_WRONLY) {\n\t\treturn -EBADF;\n\t}\n\tif(!count) {\n\t\treturn 0;\n\t}\n\tif(count < 0) {\n\t\treturn -EINVAL;\n\t}\n\n\ti = fd_table[current->fd[ufd]].inode;\n\tif(i->fsop && i->fsop->read) {\n\t\terrno = i->fsop->read(i, &fd_table[current->fd[ufd]], buf, count);\n#ifdef __DEBUG__\n\t\tprintk(\"%d\\n\", errno);\n#endif /*__DEBUG__ */\n\t\treturn errno;\n\t}\n\treturn -EINVAL;\n}\n"
  },
  {
    "path": "kernel/syscalls/readlink.c",
    "content": "/*\n * fiwix/kernel/syscalls/readlink.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_readlink(const char *filename, char *buffer, __size_t bufsize)\n{\n\tstruct inode *i;\n\tchar *tmp_name;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_readlink(%s, 0x%08x, %d)\\n\", current->pid, filename, (unsigned int)buffer, bufsize);\n#endif /*__DEBUG__ */\n\n\tif(bufsize <= 0) {\n\t\treturn -EINVAL;\n\t}\n\tif((errno = check_user_area(VERIFY_WRITE, buffer, bufsize))) {\n\t\treturn errno;\n\t}\n\tif((errno = malloc_name(filename, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = namei(tmp_name, &i, NULL, !FOLLOW_LINKS))) {\n\t\tfree_name(tmp_name);\n\t\treturn errno;\n\t}\n\tfree_name(tmp_name);\n\n\tif(!S_ISLNK(i->i_mode)) {\n\t\tiput(i);\n\t\treturn -EINVAL;\n\t}\n\n\tif(i->fsop && i->fsop->readlink) {\n\t\terrno = i->fsop->readlink(i, buffer, bufsize);\n\t\tiput(i);\n\t\treturn errno;\n\t}\n\tiput(i);\n\treturn -EINVAL;\n}\n"
  },
  {
    "path": "kernel/syscalls/readv.c",
    "content": "/*\n * fiwix/kernel/syscalls/readv.c\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Copyright 2023, Richard R. Masters.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_readv(unsigned int ufd, const struct iovec *iov, int iovcnt)\n{\n\tstruct inode *i;\n\tint errno;\n\tint bytes_read = 0;\n\tint vi;\t/* vector index */\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_readv(%d, 0x%08x, %d) -> \", current->pid, ufd, iov, iovcnt);\n#endif /*__DEBUG__ */\n\n\tCHECK_UFD(ufd);\n\tif(iovcnt < 0 || iovcnt > UIO_MAXIOV) {\n\t\treturn -EINVAL;\n\t}\n\tfor (vi = 0; vi < iovcnt; vi++) {\n\t\tconst struct iovec *io_read = &iov[vi];\n\t\tif((errno = check_user_area(VERIFY_WRITE, io_read->iov_base, io_read->iov_len))) {\n\t\t\treturn errno;\n\t\t}\n\t\tif(fd_table[current->fd[ufd]].flags & O_WRONLY) {\n\t\t\treturn -EBADF;\n\t\t}\n\t\tif(!io_read->iov_len) {\n\t\t\tcontinue;\n\t\t}\n\t\tif(io_read->iov_len < 0) {\n\t\t\treturn -EINVAL;\n\t\t}\n\n\t\ti = fd_table[current->fd[ufd]].inode;\n\t\tif(i->fsop && i->fsop->read) {\n\t\t\terrno = i->fsop->read(i, &fd_table[current->fd[ufd]], io_read->iov_base, io_read->iov_len);\n\t\t\tif (errno < 0) {\n\t\t\t    return errno;\n\t\t\t}\n\t\t\tbytes_read += errno;\n\t\t\tif (errno < io_read->iov_len) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} else {\n\t\t\treturn -EINVAL;\n\t\t}\n\t}\n#ifdef __DEBUG__\n\tprintk(\"%d\\n\", bytes_read);\n#endif /*__DEBUG__ */\n\treturn bytes_read;\n}\n"
  },
  {
    "path": "kernel/syscalls/reboot.c",
    "content": "/*\n * fiwix/kernel/syscalls/reboot.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/syscalls.h>\n#include <fiwix/reboot.h>\n#include <fiwix/signal.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_reboot(int magic1, int magic2, int flag)\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_reboot(0x%08x, %d, 0x%08x)\\n\", current->pid, magic1, magic2, flag);\n#endif /*__DEBUG__ */\n\n\tif(!IS_SUPERUSER) {\n\t\treturn -EPERM;\n\t}\n\tif((magic1 != BMAGIC_1) || (magic2 != BMAGIC_2)) {\n\t\treturn -EINVAL;\n\t}\n\tswitch(flag) {\n\t\tcase BMAGIC_SOFT:\n\t\t\tctrl_alt_del = 0;\n\t\t\tbreak;\n\t\tcase BMAGIC_HARD:\n\t\t\tctrl_alt_del = 1;\n\t\t\tbreak;\n\t\tcase BMAGIC_REBOOT:\n\t\t\treboot();\n\t\t\tbreak;\n\t\tcase BMAGIC_HALT:\n\t\t\tsys_kill(-1, SIGKILL);\n\t\t\tstop_kernel();\n\t\t\tbreak;\n\t\tdefault:\n\t\t\treturn -EINVAL;\n\t}\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/rename.c",
    "content": "/*\n * fiwix/kernel/syscalls/rename.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_rename(const char *oldpath, const char *newpath)\n{\n\tstruct inode *i, *dir, *i_new, *dir_new;\n\tchar *tmp_oldpath, *tmp_newpath;\n\tchar *oldbasename, *newbasename;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_rename('%s', '%s')\\n\", current->pid, oldpath, newpath);\n#endif /*__DEBUG__ */\n\n\tif((errno = malloc_name(oldpath, &tmp_oldpath)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = namei(tmp_oldpath, &i, &dir, !FOLLOW_LINKS))) {\n\t\tif(dir) {\n\t\t\tiput(dir);\n\t\t}\n\t\tfree_name(tmp_oldpath);\n\t\treturn errno;\n\t}\n\tif(IS_RDONLY_FS(i)) {\n\t\tiput(i);\n\t\tiput(dir);\n\t\tfree_name(tmp_oldpath);\n\t\treturn -EROFS;\n\t}\n\n\tif((errno = malloc_name(newpath, &tmp_newpath)) < 0) {\n\t\tiput(i);\n\t\tiput(dir);\n\t\tfree_name(tmp_oldpath);\n\t\treturn errno;\n\t}\n\tnewbasename = remove_trailing_slash(tmp_newpath);\n\tif((errno = namei(newbasename, &i_new, &dir_new, !FOLLOW_LINKS))) {\n\t\tif(!dir_new) {\n\t\t\tiput(i);\n\t\t\tiput(dir);\n\t\t\tfree_name(tmp_oldpath);\n\t\t\tfree_name(tmp_newpath);\n\t\t\treturn errno;\n\t\t}\n\t}\n\tif(dir->dev != dir_new->dev) {\n\t\terrno = -EXDEV;\n\t\tgoto end;\n\t}\n\tnewbasename = get_basename(newbasename);\n\tif((newbasename[0] == '.' && newbasename[1] == '\\0') || (newbasename[0] == '.' && newbasename[1] == '.' && newbasename[2] == '\\0')) {\n\t\terrno = -EINVAL;\n\t\tgoto end;\n\t}\n\n\toldbasename = get_basename(tmp_oldpath);\n\toldbasename = remove_trailing_slash(oldbasename);\n\tif((oldbasename[0] == '.' && oldbasename[1] == '\\0') || (oldbasename[0] == '.' && oldbasename[1] == '.' && oldbasename[2] == '\\0')) {\n\t\terrno = -EINVAL;\n\t\tgoto end;\n\t}\n\n\tif(i_new) {\n\t\tif(S_ISREG(i->i_mode)) {\n\t\t\tif(S_ISDIR(i_new->i_mode)) {\n\t\t\t\terrno = -EISDIR;\n\t\t\t\tgoto end;\n\t\t\t}\n\t\t}\n\t\tif(S_ISDIR(i->i_mode)) {\n\t\t\tif(!S_ISDIR(i_new->i_mode)) {\n\t\t\t\terrno = -ENOTDIR;\n\t\t\t\tgoto end;\n\t\t\t}\n\t\t}\n\t\tif(i->inode == i_new->inode) {\n\t\t\terrno = 0;\n\t\t\tgoto end;\n\t\t}\n\t}\n\n\tif(check_permission(TO_EXEC | TO_WRITE, dir_new) < 0) {\n\t\terrno = -EACCES;\n\t\tgoto end;\n\t}\n\n\tif(dir_new->fsop && dir_new->fsop->rename) {\n\t\terrno = dir_new->fsop->rename(i, dir, i_new, dir_new, oldbasename, newbasename);\n\t} else {\n\t\terrno = -EPERM;\n\t}\n\nend:\n\tiput(i);\n\tiput(dir);\n\tiput(i_new);\n\tiput(dir_new);\n\tfree_name(tmp_oldpath);\n\tfree_name(tmp_newpath);\n\treturn errno;\n}\n"
  },
  {
    "path": "kernel/syscalls/rmdir.c",
    "content": "/*\n * fiwix/kernel/syscalls/rmdir.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_rmdir(const char *dirname)\n{\n\tstruct inode *i, *dir;\n\tchar *tmp_dirname;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_rmdir(%s)\\n\", current->pid, dirname);\n#endif /*__DEBUG__ */\n\n\tif((errno = malloc_name(dirname, &tmp_dirname)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = namei(tmp_dirname, &i, &dir, !FOLLOW_LINKS))) {\n\t\tif(dir) {\n\t\t\tiput(dir);\n\t\t}\n\t\tfree_name(tmp_dirname);\n\t\treturn errno;\n\t}\n\tfree_name(tmp_dirname);\n\n\tif(!S_ISDIR(i->i_mode)) {\n\t\tiput(i);\n\t\tiput(dir);\n\t\treturn -ENOTDIR;\n\t}\n\tif(i == current->root || i->mount_point) {\n\t\tiput(i);\n\t\tiput(dir);\n\t\treturn -EBUSY;\n\t}\n\tif(IS_RDONLY_FS(i)) {\n\t\tiput(i);\n\t\tiput(dir);\n\t\treturn -EROFS;\n\t}\n\tif(i == dir) {\n\t\tiput(i);\n\t\tiput(dir);\n\t\treturn -EPERM;\n\t}\n\tif(check_permission(TO_EXEC | TO_WRITE, dir) < 0) {\n\t\tiput(i);\n\t\tiput(dir);\n\t\treturn -EACCES;\n\t}\n\n\t/* check sticky permission bit */\n\tif(dir->i_mode & S_ISVTX) {\n\t\tif(check_user_permission(i)) {\n\t\t\tiput(i);\n\t\t\tiput(dir);\n\t\t\treturn -EPERM;\n\t\t}\n\t}\n\n\tif(i->fsop && i->fsop->rmdir) {\n\t\terrno = i->fsop->rmdir(dir, i);\n\t} else {\n\t\terrno = -EPERM;\n\t}\n\tiput(i);\n\tiput(dir);\n\treturn errno;\n}\n"
  },
  {
    "path": "kernel/syscalls/select.c",
    "content": "/*\n * fiwix/kernel/syscalls/select.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/process.h>\n#include <fiwix/timer.h>\n#include <fiwix/sched.h>\n#include <fiwix/sleep.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstatic int check_fds(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds)\n{\n\tint n, bit;\n\tunsigned int set;\n\n\tn = 0;\n\tfor(;;) {\n\t\tbit = n * __NFDBITS;\n\t\tif(bit >= nfds) {\n\t\t\tbreak;\n\t\t}\n\t\tset = rfds->fds_bits[n] | wfds->fds_bits[n] | efds->fds_bits[n];\n\t\twhile(set) {\n\t\t\tif(__FD_ISSET(bit, rfds) || __FD_ISSET(bit, wfds) || __FD_ISSET(bit, efds)) {\n\t\t\t\tCHECK_UFD(bit);\n\t\t\t}\n\t\t\tset >>= 1;\n\t\t\tbit++;\n\t\t}\n\t\tn++;\n\t}\n\n\treturn 0;\n}\n\nstatic int do_check(struct inode *i, struct fd *f, int flag)\n{\n\tif(i->fsop && i->fsop->select) {\n\t\tif(i->fsop->select(i, f, flag)) {\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\treturn 0;\n}\n\nint do_select(int nfds, fd_set *rfds, fd_set *wfds, fd_set *efds, fd_set *res_rfds, fd_set *res_wfds, fd_set *res_efds)\n{\n\tint n, count;\n\tstruct inode *i;\n\n\tcount = 0;\n\tfor(;;) {\n\t\tfor(n = 0; n < nfds; n++) {\n\t\t\tif(!current->fd[n]) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\ti = fd_table[current->fd[n]].inode;\n\t\t\tif(__FD_ISSET(n, rfds)) {\n\t\t\t\tif(do_check(i, &fd_table[current->fd[n]], SEL_R)) {\n\t\t\t\t\t__FD_SET(n, res_rfds);\n\t\t\t\t\tcount++;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(__FD_ISSET(n, wfds)) {\n\t\t\t\tif(do_check(i, &fd_table[current->fd[n]], SEL_W)) {\n\t\t\t\t\t__FD_SET(n, res_wfds);\n\t\t\t\t\tcount++;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(__FD_ISSET(n, efds)) {\n\t\t\t\tif(do_check(i, &fd_table[current->fd[n]], SEL_E)) {\n\t\t\t\t\t__FD_SET(n, res_efds);\n\t\t\t\t\tcount++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif(count || !current->timeout || current->sigpending & ~current->sigblocked) {\n\t\t\tbreak;\n\t\t}\n\t\tif(sleep(&do_select, PROC_INTERRUPTIBLE)) {\n\t\t\treturn -EINTR;\n\t\t}\n\t}\n\n\treturn count;\n}\n\nint sys_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)\n{\n\tunsigned int t;\n\tfd_set rfds, wfds, efds;\n\tfd_set res_rfds, res_wfds, res_efds;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_select(%d, 0x%08x, 0x%08x, 0x%08x, 0x%08x [%d])\\n\", current->pid, nfds, (int)readfds, (int)writefds, (int)exceptfds, (int)timeout, (int)timeout ? tv2ticks(timeout): 0);\n#endif /*__DEBUG__ */\n\n\tif(nfds < 0) {\n\t\treturn -EINVAL;\n\t}\n\tif(nfds > MIN(__FD_SETSIZE, NR_OPENS)) {\n\t\tnfds = MIN(__FD_SETSIZE, NR_OPENS);\n\t}\n\n\tif(readfds) {\n\t\tif((errno = check_user_area(VERIFY_WRITE, readfds, sizeof(fd_set)))) {\n\t\t\treturn errno;\n\t\t}\n\t\tmemcpy_b(&rfds, readfds, sizeof(fd_set));\n\t} else {\n\t\t__FD_ZERO(&rfds);\n\t}\n\tif(writefds) {\n\t\tif((errno = check_user_area(VERIFY_WRITE, writefds, sizeof(fd_set)))) {\n\t\t\treturn errno;\n\t\t}\n\t\tmemcpy_b(&wfds, writefds, sizeof(fd_set));\n\t} else {\n\t\t__FD_ZERO(&wfds);\n\t}\n\tif(exceptfds) {\n\t\tif((errno = check_user_area(VERIFY_WRITE, exceptfds, sizeof(fd_set)))) {\n\t\t\treturn errno;\n\t\t}\n\t\tmemcpy_b(&efds, exceptfds, sizeof(fd_set));\n\t} else {\n\t\t__FD_ZERO(&efds);\n\t}\n\n\t/* check the validity of all fds */\n\tif((errno = check_fds(nfds, &rfds, &wfds, &efds)) < 0) {\n\t\treturn errno;\n\t}\n\n\tif(timeout) {\n\t\tt = tv2ticks(timeout);\n\t} else {\n\t\tt = INFINITE_WAIT;\n\t}\n\n\t__FD_ZERO(&res_rfds);\n\t__FD_ZERO(&res_wfds);\n\t__FD_ZERO(&res_efds);\n\n\tcurrent->timeout = t;\n\tif((errno = do_select(nfds, &rfds, &wfds, &efds, &res_rfds, &res_wfds, &res_efds)) < 0) {\n\t\treturn errno;\n\t}\n\tt = current->timeout;\n\tcurrent->timeout = 0;\n\n\tif(readfds) {\n\t\tmemcpy_b(readfds, &res_rfds, sizeof(fd_set));\n\t}\n\tif(writefds) {\n\t\tmemcpy_b(writefds, &res_wfds, sizeof(fd_set));\n\t}\n\tif(exceptfds) {\n\t\tmemcpy_b(exceptfds, &res_efds, sizeof(fd_set));\n\t}\n\tif(timeout) {\n\t\tticks2tv(t, timeout);\n\t}\n\treturn errno;\n}\n"
  },
  {
    "path": "kernel/syscalls/semctl.c",
    "content": "/*\n * fiwix/kernel/syscalls/semctl.c\n *\n * Copyright 2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/config.h>\n#include <fiwix/kernel.h>\n#include <fiwix/types.h>\n#include <fiwix/string.h>\n#include <fiwix/process.h>\n#include <fiwix/sched.h>\n#include <fiwix/errno.h>\n#include <fiwix/ipc.h>\n#include <fiwix/sem.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\n#ifdef CONFIG_SYSVIPC\nint sys_semctl(int semid, int semnum, int cmd, void *arg)\n{\n\tstruct semid_ds *ss, *tmp;\n\tstruct seminfo *si;\n\tstruct sem_undo *un;\n\tstruct ipc_perm *perm;\n\tstruct sem *s;\n\tunsigned short int *p;\n\tint n, errno, retval, val;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_semctl(%d, %d, %d, 0x%x)\\n\", current->pid, semid, semnum, cmd, (int)arg);\n#endif /*__DEBUG__ */\n\n\tif(semid < 0) {\n\t\treturn -EINVAL;\n\t}\n\n\tswitch(cmd) {\t\n\t\tcase IPC_STAT:\n\t\tcase SEM_STAT:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, arg, sizeof(struct semid_ds)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tif(cmd == IPC_STAT) {\n\t\t\t\tss = semset[semid % SEMMNI];\n\t\t\t} else {\n\t\t\t\tss = semset[semid];\n\t\t\t}\n\t\t\tif(ss == IPC_UNUSED) {\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\tif(!ipc_has_perms(&ss->sem_perm, IPC_R)) {\n\t\t\t\treturn -EACCES;\n\t\t\t}\n\t\t\tif(cmd == IPC_STAT) {\n\t\t\t\tretval = 0;\n\t\t\t} else {\n\t\t\t\tretval = (ss->sem_perm.seq * SEMMNI) + semid;\n\t\t\t}\n\t\t\tmemcpy_b(arg, ss, sizeof(struct semid_ds));\n\t\t\treturn retval;\n\n\t\tcase IPC_SET:\n\t\t\tif((errno = check_user_area(VERIFY_READ, arg, sizeof(struct semid_ds)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tss = semset[semid % SEMMNI];\n\t\t\tif(ss == IPC_UNUSED) {\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\tperm = &ss->sem_perm;\n\t\t\tif(!IS_SUPERUSER && current->euid != perm->uid && current->euid != perm->cuid) {\n\t\t\t\treturn -EPERM;\n\t\t\t}\n\t\t\ttmp = (struct semid_ds *)arg;\n\t\t\tperm->uid = tmp->sem_perm.uid;\n\t\t\tperm->gid = tmp->sem_perm.gid;\n\t\t\tperm->mode = (perm->mode & ~0777) | (tmp->sem_perm.mode & 0777);\n\t\t\tss->sem_ctime = CURRENT_TIME;\n\t\t\treturn 0;\n\n\t\tcase IPC_RMID:\n\t\t\tss = semset[semid % SEMMNI];\n\t\t\tif(ss == IPC_UNUSED) {\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\tperm = &ss->sem_perm;\n\t\t\tif(!IS_SUPERUSER && current->euid != perm->uid && current->euid != perm->cuid) {\n\t\t\t\treturn -EPERM;\n\t\t\t}\n\t\t\tun = ss->undo;\n\t\t\twhile(un) {\n\t\t\t\tif(semnum == un->sem_num) {\n\t\t\t\t\tun->semadj = 0;\n\t\t\t\t}\n\t\t\t\tun = un->id_next;\n\t\t\t}\n\t\t\tfor(n = 0; n < ss->sem_nsems; n++) {\n\t\t\t\ts = ss->sem_base + n;\n\t\t\t\tif(s->semncnt) {\n\t\t\t\t\twakeup(&s->semncnt);\n\t\t\t\t}\n\t\t\t\tif(s->semzcnt) {\n\t\t\t\t\twakeup(&s->semzcnt);\n\t\t\t\t}\n\t\t\t}\n\t\t\tnum_sems -= ss->sem_nsems;\n\t\t\tsem_release_ss(ss);\n\t\t\tsemset[semid % SEMMNI] = (struct semid_ds *)IPC_UNUSED;\n\t\t\tnum_semsets--;\n\t\t\tsem_seq++;\n\t\t\tif((semid % SEMMNI) == max_semid) {\n\t\t\t\twhile(max_semid) {\n\t\t\t\t\tif(semset[max_semid] != IPC_UNUSED) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tmax_semid--;\n\t\t\t\t}\n\t\t\t}\n\t\t\twakeup(ss);\n\t\t\treturn 0;\n\n\t\tcase IPC_INFO:\n\t\tcase SEM_INFO:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, arg, sizeof(struct seminfo)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tsi = (struct seminfo *)arg;\n\t\t\tif(cmd == IPC_INFO) {\n\t\t\t\tsi->semusz = sizeof(struct sem_undo);\n\t\t\t\tsi->semaem = 0;\t/* FIXME: pending to do */\n\t\t\t} else {\n\t\t\t\tsi->semusz = num_semsets;\n\t\t\t\tsi->semaem = num_sems;\n\t\t\t}\n\t\t\tsi->semmap = 0;\t\t/* FIXME: pending to do */\n\t\t\tsi->semmni = SEMMNI;\n\t\t\tsi->semmns = SEMMNS;\n\t\t\tsi->semmnu = 0;\t\t/* FIXME: pending to do */\n\t\t\tsi->semmsl = SEMMSL;\n\t\t\tsi->semopm = SEMOPM;\n\t\t\tsi->semume = 0;\t\t/* FIXME: pending to do */\n\t\t\tsi->semvmx = SEMVMX;\n\t\t\treturn max_semid;\n\n\t\tcase GETPID:\n\t\tcase GETVAL:\n\t\tcase GETALL:\n\t\tcase GETNCNT:\n\t\tcase GETZCNT:\n\t\t\tss = semset[semid % SEMMNI];\n\t\t\tif(ss == IPC_UNUSED) {\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\tif(!ipc_has_perms(&ss->sem_perm, IPC_R)) {\n\t\t\t\treturn -EACCES;\n\t\t\t}\n\t\t\ts = ss->sem_base + semnum;\n\t\t\tswitch(cmd) {\n\t\t\t\tcase GETPID:\n\t\t\t\t\treturn s->sempid;\n\t\t\t\tcase GETVAL:\n\t\t\t\t\treturn s->semval;\n\t\t\t\tcase GETALL:\n\t\t\t\t\tif((errno = check_user_area(VERIFY_WRITE, arg, ss->sem_nsems * sizeof(short int)))) {\n\t\t\t\t\t\treturn errno;\n\t\t\t\t\t}\n\t\t\t\t\tp = (unsigned short int *)arg;\n\t\t\t\t\tfor(n = 0; n < ss->sem_nsems; n++) {\n\t\t\t\t\t\tmemcpy_b(p, &ss->sem_base[n].semval, sizeof(short int));\n\t\t\t\t\t\tp++;\n\t\t\t\t\t}\n\t\t\t\t\treturn 0;\n\t\t\t\tcase GETNCNT:\n\t\t\t\t\treturn s->semncnt;\n\t\t\t\tcase GETZCNT:\n\t\t\t\t\treturn s->semzcnt;\n\t\t\t}\n\n\t\tcase SETVAL:\n\t\t\tss = semset[semid % SEMMNI];\n\t\t\tif(ss == IPC_UNUSED) {\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\tif(!ipc_has_perms(&ss->sem_perm, IPC_W)) {\n\t\t\t\treturn -EACCES;\n\t\t\t}\n\t\t\tval = (int)(int*)arg;\n\t\t\tif(val < 0 || val > SEMVMX) {\n\t\t\t\treturn -ERANGE;\n\t\t\t}\n\t\t\tif(semnum < 0 || semnum > ss->sem_nsems) {\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\ts = ss->sem_base + semnum;\n\t\t\ts->semval = val;\n\t\t\tss->sem_ctime= CURRENT_TIME;\n\t\t\tun = ss->undo;\n\t\t\twhile(un) {\n\t\t\t\tif(semnum == un->sem_num) {\n\t\t\t\t\tun->semadj = 0;\n\t\t\t\t}\n\t\t\t\tun = un->id_next;\n\t\t\t}\n\t\t\tif(s->semncnt) {\n\t\t\t\twakeup(&s->semncnt);\n\t\t\t}\n\t\t\tif(s->semzcnt) {\n\t\t\t\twakeup(&s->semzcnt);\n\t\t\t}\n\t\t\treturn 0;\n\n\t\tcase SETALL:\n\t\t\tss = semset[semid % SEMMNI];\n\t\t\tif(ss == IPC_UNUSED) {\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\tif((errno = check_user_area(VERIFY_READ, arg, ss->sem_nsems * sizeof(short int)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tif(!ipc_has_perms(&ss->sem_perm, IPC_W)) {\n\t\t\t\treturn -EACCES;\n\t\t\t}\n\t\t\tp = (unsigned short int *)arg;\n\t\t\tfor(n = 0; n < ss->sem_nsems; n++) {\n\t\t\t\tss->sem_base[n].semval = *p;\n\t\t\t\tp++;\n\t\t\t\ts = ss->sem_base + n;\n\t\t\t\tif(s->semncnt) {\n\t\t\t\t\twakeup(&s->semncnt);\n\t\t\t\t}\n\t\t\t\tif(s->semzcnt) {\n\t\t\t\t\twakeup(&s->semzcnt);\n\t\t\t\t}\n\t\t\t}\n\t\t\tss->sem_ctime= CURRENT_TIME;\n\t\t\tun = ss->undo;\n\t\t\twhile(un) {\n\t\t\t\tif(semnum == un->sem_num) {\n\t\t\t\t\tun->semadj = 0;\n\t\t\t\t}\n\t\t\t\tun = un->id_next;\n\t\t\t}\n\t\t\treturn 0;\n\t}\n\n\treturn -EINVAL;\n}\n#endif /* CONFIG_SYSVIPC */\n"
  },
  {
    "path": "kernel/syscalls/semget.c",
    "content": "/*\n * fiwix/kernel/syscalls/semget.c\n *\n * Copyright 2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/types.h>\n#include <fiwix/string.h>\n#include <fiwix/errno.h>\n#include <fiwix/process.h>\n#include <fiwix/ipc.h>\n#include <fiwix/sem.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\n#ifdef CONFIG_SYSVIPC\nstatic struct resource ipcsem_resource = { 0, 0 };\n\nstruct semid_ds *semset[SEMMNI];\nunsigned int num_semsets;\nunsigned int num_sems;\nunsigned int max_semid;\nunsigned int sem_seq;\n\n/* FIXME: this should be allocated dynamically */\nstatic struct semid_ds semset_pool[SEMMNI];\nstruct semid_ds *sem_get_new_ss(void)\n{\n\tint n;\n\n\tfor(n = 0; n < SEMMNI; n++) {\n\t\tif(semset_pool[n].sem_ctime == 0) {\n\t\t\tsemset_pool[n].sem_ctime = 1;\n\t\t\treturn &semset_pool[n];\n\t\t}\n\t}\n\treturn NULL;\n}\n\nvoid sem_release_ss(struct semid_ds *ss)\n{\n\tmemset_b(ss, 0, sizeof(struct semid_ds));\n}\n\nstruct sem sma_pool[SEMMNS];\nstruct sem *sem_get_new_sma(void)\n{\n\tunsigned int n;\n\n\tlock_resource(&ipcsem_resource);\n\n\tfor(n = 0; n < SEMMNS; n += SEMMSL) {\n\t\tif(sma_pool[n].sempid < 0) {\n\t\t\tsma_pool[n].sempid = 0;\n\t\t\tunlock_resource(&ipcsem_resource);\n\t\t\treturn &sma_pool[n];\n\t\t}\n\t}\n\n\tunlock_resource(&ipcsem_resource);\n\treturn NULL;\n}\n\nvoid sem_release_sma(struct sem *sma)\n{\n\tlock_resource(&ipcsem_resource);\n\tmemset_b(sma, 0, sizeof(struct sem) * SEMMSL);\n\tsma->sempid = -1;\n\tunlock_resource(&ipcsem_resource);\n}\n\nstruct sem_undo semundo_pool[SEMMSL];\nstruct sem_undo *sem_get_new_su(void)\n{\n\tint n;\n\n\tfor(n = 0; n < SEMMSL; n++) {\n\t\tif(semundo_pool[n].semid < 0) {\n\t\t\tsemundo_pool[n].semid = 0;\n\t\t\treturn &semundo_pool[n];\n\t\t}\n\t}\n\treturn NULL;\n}\n\nvoid sem_release_su(struct sem_undo *su)\n{\n\tmemset_b(su, 0, sizeof(struct sem_undo));\n\tsu->semid = -1;\n}\n\nvoid sem_init(void)\n{\n\tint n;\n\n\tfor(n = 0; n < SEMMNI; n++) {\n\t\tsemset[n] = (struct semid_ds *)IPC_UNUSED;\n\t}\n\tmemset_b(semset_pool, 0, sizeof(semset_pool));\n\tmemset_b(sma_pool, 0, sizeof(sma_pool));\n\tfor(n = 0; n < SEMMNS; n += SEMMSL) {\n\t\tsma_pool[n].sempid = -1;\n\t}\n\tmemset_b(semundo_pool, 0, sizeof(semundo_pool));\n\tfor(n = 0; n < SEMMSL; n++) {\n\t\tsemundo_pool[n].semid = -1;\n\t}\n\tnum_semsets = num_sems = max_semid = sem_seq = 0;\n}\n\nint sys_semget(key_t key, int nsems, int semflg)\n{\n\tstruct semid_ds *ss;\n\tstruct ipc_perm *perm;\n\tint n;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_semget(%d, %d, 0x%x)\\n\", current->pid, (int)key, nsems, semflg);\n#endif /*__DEBUG__ */\n\n\tif(nsems < 0 || nsems > SEMMSL) {\n\t\treturn -EINVAL;\n\t}\n\n\tif(key == IPC_PRIVATE) {\n\t\t/* create a new semaphore set */\n\t\tif(!nsems) {\n\t\t\treturn -EINVAL;\n\t\t}\n\t\tif(num_sems + nsems > SEMMNS) {\n\t\t\treturn -ENOSPC;\n\t\t}\n\t\tif(!(ss = sem_get_new_ss())) {\n\t\t\treturn -ENOMEM;\n\t\t}\n\t\tfor(n = 0; n < SEMMNI; n++) {\n\t\t\tif(semset[n] == (struct semid_ds *)IPC_UNUSED) {\n\t\t\t\tgoto init;\n\t\t\t}\n\t\t}\n\t\tsem_release_ss(ss);\n\t\treturn -ENOSPC;\n\t}\n\n\tss = NULL;\n\n\tfor(n = 0; n < SEMMNI; n++) {\n\t\tif(semset[n] == (struct semid_ds *)IPC_UNUSED) {\n\t\t\tcontinue;\n\t\t}\n\t\tif(key == semset[n]->sem_perm.key) {\n\t\t\tss = semset[n];\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif(!ss) {\n\t\tif(!(semflg & IPC_CREAT)) {\n\t\t\treturn -ENOENT;\n\t\t}\n\n\t\t/* create a new semaphore set */\n\t\tif(!nsems) {\n\t\t\treturn -EINVAL;\n\t\t}\n\t\tif(num_sems + nsems > SEMMNS) {\n\t\t\treturn -ENOSPC;\n\t\t}\n\t\tif(!(ss = sem_get_new_ss())) {\n\t\t\treturn -ENOMEM;\n\t\t}\n\t\tfor(n = 0; n < SEMMNI; n++) {\n\t\t\tif(semset[n] == (struct semid_ds *)IPC_UNUSED) {\n\t\t\t\tgoto init;\n\t\t\t}\n\t\t}\n\t\tsem_release_ss(ss);\n\t\treturn -ENOSPC;\n\t} else {\n\t\tif((semflg & (IPC_CREAT | IPC_EXCL)) == (IPC_CREAT | IPC_EXCL)) {\n\t\t\treturn -EEXIST;\n\t\t}\n\t\tif(!ipc_has_perms(&ss->sem_perm, semflg)) {\n\t\t\treturn -EACCES;\n\t\t}\n\t\tif(nsems > ss->sem_nsems) {\n\t\t\treturn -EINVAL;\n\t\t}\n\t\treturn (ss->sem_perm.seq * SEMMNI) + n;\n\t}\n\ninit:\n\tperm = &ss->sem_perm;\n\tperm->key = key;\n\tperm->uid = perm->cuid = current->euid;\n\tperm->gid = perm->cgid = current->egid;\n\tperm->mode = semflg & 0777;\n\tperm->seq = sem_seq;\n\tss->sem_otime = 0;\n\tss->sem_ctime = CURRENT_TIME;\n\tss->sem_base = sem_get_new_sma();\n\tss->undo = NULL;\n\tss->sem_nsems = nsems;\n\tsemset[n] = ss;\n\tif(n > max_semid) {\n\t\tmax_semid = n;\n\t}\n\tnum_sems += nsems;\n\tnum_semsets++;\n\treturn (ss->sem_perm.seq * SEMMNI) + n;\n}\n#endif /* CONFIG_SYSVIPC */\n"
  },
  {
    "path": "kernel/syscalls/semop.c",
    "content": "/*\n * fiwix/kernel/syscalls/semop.c\n *\n * Copyright 2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/config.h>\n#include <fiwix/kernel.h>\n#include <fiwix/types.h>\n#include <fiwix/string.h>\n#include <fiwix/process.h>\n#include <fiwix/sleep.h>\n#include <fiwix/sched.h>\n#include <fiwix/errno.h>\n#include <fiwix/ipc.h>\n#include <fiwix/sem.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\n#ifdef CONFIG_SYSVIPC\nstatic void semundo_ops(struct semid_ds *ss, struct sembuf *sops, int max)\n{\n\tstruct sem *s;\n\tint n;\n\n\tfor(n = 0; n < max; n++) {\n\t\ts = ss->sem_base + sops[n].sem_num;\n\t\ts->semval -= sops[n].sem_op;\n\t}\n}\n\nvoid semexit(void)\n{\n\tstruct semid_ds *ss;\n\tstruct sem_undo *su, **sup, *ssu, **ssup;\n\tstruct sem *s;\n\n\tsup = &current->semundo;\n\twhile(*sup) {\n\t\tsu = *sup;\n\t\tss = semset[su->semid % SEMMNI];\n\t\tif(ss != IPC_UNUSED) {\n\t\t\tssup = &ss->undo;\n\t\t\twhile(*ssup) {\n\t\t\t\tssu = *ssup;\n\t\t\t\t*ssup = ssu->id_next;\n\t\t\t\tif(su == ssu) {\n\t\t\t\t\ts = ss->sem_base + ssu->sem_num;\n\t\t\t\t\tif((ssu->semadj + s->semval) >= 0) {\n\t\t\t\t\t\ts->semval += ssu->semadj;\n\t\t\t\t\t\ts->sempid = current->pid;\n\t\t\t\t\t\tss->sem_otime = CURRENT_TIME;\n\t\t\t\t\t\tif(s->semncnt) {\n\t\t\t\t\t\t\twakeup(&s->semncnt);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(!s->semval && s->semzcnt) {\n\t\t\t\t\t\t\twakeup(&s->semzcnt);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tssup = &ssu->id_next;\n\t\t\t}\n\t\t}\n\t\t*sup = su->proc_next;\n\t\tsem_release_su(su);\n\t}\n\tcurrent->semundo = NULL;\n}\n\nint sys_semop(int semid, struct sembuf *sops, int nsops)\n{\n\tstruct semid_ds *ss;\n\tstruct sem *s;\n\tstruct sem_undo *su;\n\tint need_alter, need_undo;\n\tint n, errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_semop(%d, 0x%x, %d)\\n\", current->pid, semid, (int)sops, nsops);\n#endif /*__DEBUG__ */\n\n\tif(semid < 0 || nsops <= 0) {\n\t\treturn -EINVAL;\n\t}\n\tif(nsops > SEMOPM) {\n\t\treturn -E2BIG;\n\t}\n\tif((errno = check_user_area(VERIFY_READ, sops, sizeof(struct sembuf)))) {\n\t\treturn errno;\n\t}\n\n\tss = semset[semid % SEMMNI];\n\tif(ss == IPC_UNUSED) {\n\t\treturn -EINVAL;\n\t}\n\n\t/* check permissions and ranges for all semaphore operations */\n\tneed_alter = 0;\n\tfor(n = 0; n < nsops; n++) {\n\t\tif(sops[n].sem_num > ss->sem_nsems) {\n\t\t\treturn -EFBIG;\n\t\t}\n\t\t/* only negative and positive operations ... */\n\t\tif(sops[n].sem_op) {\n\t\t\t/* will alter semaphores */\n\t\t\tneed_alter++;\n\t\t}\n\t}\n\tif(!ipc_has_perms(&ss->sem_perm, need_alter ? IPC_W : IPC_R)) {\n\t\treturn -EACCES;\n\t}\n\n\tneed_undo = 0;\n\nloop:\n\tfor(n = 0; n < nsops; n++) {\n\t\ts = ss->sem_base + sops[n].sem_num;\n\n\t\t/* positive semaphore operation */\n\t\tif(sops[n].sem_op > 0) {\n\t\t\tif((sops[n].sem_op + s->semval) > SEMVMX) {\n\t\t\t\t/* reverse all semaphore ops */\n\t\t\t\tsemundo_ops(ss, sops, n);\n\t\t\t\treturn -ERANGE;\n\t\t\t}\n\t\t\tif(sops[n].sem_flg & SEM_UNDO) {\n\t\t\t\tneed_undo = 1;\n\t\t\t}\n\t\t\ts->semval += sops[n].sem_op;\n\t\t\tif(s->semncnt) {\n\t\t\t\twakeup(&s->semncnt);\n\t\t\t}\n\t\t}\n\n\t\t/* negative semaphore operation */\n\t\tif(sops[n].sem_op < 0) {\n\t\t\tif((sops[n].sem_op + s->semval) >= 0) {\n\t\t\t\tif(sops[n].sem_flg & SEM_UNDO) {\n\t\t\t\t\tneed_undo = 1;\n\t\t\t\t}\n\t\t\t\ts->semval += sops[n].sem_op;\n\t\t\t\tif(!s->semval && s->semzcnt) {\n\t\t\t\t\twakeup(&s->semzcnt);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t/* reverse all semaphore ops */\n\t\t\t\tsemundo_ops(ss, sops, n);\n\t\t\t\tif(sops[n].sem_flg & IPC_NOWAIT) {\n\t\t\t\t\treturn -EAGAIN;\n\t\t\t\t}\n\t\t\t\ts->semncnt++;\n\t\t\t\terrno = sleep(&s->semncnt, PROC_INTERRUPTIBLE);\n\t\t\t\tss = semset[semid % SEMMNI];\n\t\t\t\tif(ss == IPC_UNUSED) {\n\t\t\t\t\treturn -EIDRM;\n\t\t\t\t}\n\t\t\t\ts->semncnt--;\n\t\t\t\tif(errno) {\n\t\t\t\t\treturn -EINTR;\n\t\t\t\t}\n\t\t\t\tgoto loop;\t/* start loop from beginning */\n\t\t\t}\n\t\t}\n\n\t\t/* semaphore operation is zero */\n\t\tif(!sops[n].sem_op) {\n\t\t\tif(s->semval) {\n\t\t\t\t/* reverse all semaphore ops */\n\t\t\t\tsemundo_ops(ss, sops, n);\n\t\t\t\tif(sops[n].sem_flg & IPC_NOWAIT) {\n\t\t\t\t\treturn -EAGAIN;\n\t\t\t\t}\n\t\t\t\ts->semzcnt++;\n\t\t\t\terrno = sleep(&s->semzcnt, PROC_INTERRUPTIBLE);\n\t\t\t\tss = semset[semid % SEMMNI];\n\t\t\t\tif(ss == IPC_UNUSED) {\n\t\t\t\t\treturn -EIDRM;\n\t\t\t\t}\n\t\t\t\ts->semzcnt--;\n\t\t\t\tif(errno) {\n\t\t\t\t\treturn -EINTR;\n\t\t\t\t}\n\t\t\t\tgoto loop;\t/* start loop from beginning */\n\t\t\t}\n\t\t}\n\t}\n\n\tif(need_undo) {\n\t\tfor(n = 0; n < nsops; n++) {\n\t\t\tif(sops[n].sem_flg & SEM_UNDO) {\n\t\t\t\tsu = current->semundo;\n\t\t\t\twhile(su) {\n\t\t\t\t\tif(su->semid == semid && su->sem_num == sops[n].sem_num) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tsu = su->proc_next;\n\t\t\t\t}\n\t\t\t\tif(!su) {\n\t\t\t\t\tif(!(su = sem_get_new_su())) {\n\t\t\t\t\t\tsemundo_ops(ss, sops, n);\n\t\t\t\t\t\treturn -ENOMEM;\n\t\t\t\t\t}\n\t\t\t\t\tsu->proc_next = current->semundo;\n\t\t\t\t\tsu->id_next = ss->undo;\n\t\t\t\t\tsu->semid = semid;\n\t\t\t\t\tsu->semadj = 0;\n\t\t\t\t\tsu->sem_num = sops[n].sem_num;\n\t\t\t\t\tcurrent->semundo = su;\n\t\t\t\t\tss->undo = su;\n\t\t\t\t}\n\t\t\t\tsu->semadj -= sops[n].sem_op;\n\t\t\t}\n\t\t}\n\t}\n\n\tfor(n = 0; n < nsops; n++) {\n\t\ts = ss->sem_base + sops[n].sem_num;\n\t\ts->sempid = current->pid;\n\t}\n\tss->sem_otime = CURRENT_TIME;\n\treturn 0;\n}\n#endif /* CONFIG_SYSVIPC */\n"
  },
  {
    "path": "kernel/syscalls/setdomainname.c",
    "content": "/*\n * fiwix/kernel/syscalls/setdomainname.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/utsname.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_setdomainname(const char *name, int length)\n{\n\tint errno;\n\tchar *tmp_name;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_setdomainname('%s', %d)\\n\", current->pid, name, length);\n#endif /*__DEBUG__ */\n\n\tif((errno = malloc_name(name, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\tif(!IS_SUPERUSER) {\n\t\tfree_name(tmp_name);\n\t\treturn -EPERM;\n\t}\n\tif(length < 0 || length > _UTSNAME_LENGTH) {\n\t\tfree_name(tmp_name);\n\t\treturn -EINVAL;\n\t}\n\tmemcpy_b(&sys_utsname.domainname, tmp_name, length);\n\tsys_utsname.domainname[length] = 0;\n\tfree_name(tmp_name);\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/setfsgid.c",
    "content": "/*\n * fiwix/kernel/syscalls/setfsgid.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_setfsgid(__gid_t fsgid)\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_setfsgid(%d) -> %d\\n\", current->pid, fsgid);\n#endif /*__DEBUG__ */\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/setfsuid.c",
    "content": "/*\n * fiwix/kernel/syscalls/setfsuid.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_setfsuid(__uid_t fsuid)\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_setfsuid(%d) -> %d\\n\", current->pid, fsuid);\n#endif /*__DEBUG__ */\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/setgid.c",
    "content": "/*\n * fiwix/kernel/syscalls/setgid.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_setgid(__gid_t gid)\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_setgid(%d)\\n\", current->pid, gid);\n#endif /*__DEBUG__ */\n\n\tif(IS_SUPERUSER) {\n\t\tcurrent->gid = current->egid = current->sgid = gid;\n\t} else {\n\t\tif((current->gid == gid) || (current->sgid == gid)) {\n\t\t\tcurrent->egid = gid;\n\t\t} else {\n\t\t\treturn -EPERM;\n\t\t}\n\t}\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/setgroups.c",
    "content": "/*\n * fiwix/kernel/syscalls/setgroups.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_setgroups(__ssize_t size, const __gid_t *list)\n{\n\tint n, errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_setgroups(%d, 0x%08x)\\n\", current->pid, size, (unsigned int)list);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_user_area(VERIFY_READ, list, sizeof(__gid_t)))) {\n\t\treturn errno;\n\t}\n\tif(!IS_SUPERUSER) {\n\t\treturn -EPERM;\n\t}\n\tif(size > NGROUPS_MAX) {\n\t\treturn -EINVAL;\n\t}\n\tfor(n = 0; n < NGROUPS_MAX; n++) {\n\t\tcurrent->groups[n] = -1;\n\t\tif(n < size) {\n\t\t\tcurrent->groups[n] = list[n];\n\t\t}\n\t}\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/sethostname.c",
    "content": "/*\n * fiwix/kernel/syscalls/sethostname.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/utsname.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_sethostname(const char *name, int length)\n{\n\tint errno;\n\tchar *tmp_name;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_sethostname('%s', %d)\\n\", current->pid, name, length);\n#endif /*__DEBUG__ */\n\n\tif((errno = malloc_name(name, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\tif(!IS_SUPERUSER) {\n\t\tfree_name(tmp_name);\n\t\treturn -EPERM;\n\t}\n\tif(length < 0 || length > _UTSNAME_LENGTH) {\n\t\tfree_name(tmp_name);\n\t\treturn -EINVAL;\n\t}\n\tmemcpy_b(&sys_utsname.nodename, tmp_name, length);\n\tsys_utsname.nodename[length] = 0;\n\tfree_name(tmp_name);\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/setitimer.c",
    "content": "/*\n * fiwix/kernel/syscalls/setitimer.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/time.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value)\n{\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_setitimer(%d, 0x%08x, 0x%08x) -> \\n\", current->pid, which, (unsigned int)new_value, (unsigned int)old_value);\n#endif /*__DEBUG__ */\n\n\tif((unsigned int)old_value) {\n\t\tif((errno = check_user_area(VERIFY_WRITE, old_value, sizeof(struct itimerval)))) {\n\t\t\treturn errno;\n\t\t}\n\t}\n\n\treturn setitimer(which, new_value, old_value);\n}\n"
  },
  {
    "path": "kernel/syscalls/setpgid.c",
    "content": "/*\n * fiwix/kernel/syscalls/setpgid.c\n *\n * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/process.h>\n#include <fiwix/sched.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_setpgid(__pid_t pid, __pid_t pgid)\n{\n\tstruct proc *p;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_setpgid(%d, %d)\", current->pid, pid, pgid);\n#endif /*__DEBUG__ */\n\n\tif(pid < 0 || pgid < 0) {\n\t\treturn -EINVAL;\n\t}\n\tif(!pid) {\n\t\tpid = current->pid;\n\t}\n\n\tif(!(p = get_proc_by_pid(pid))) {\n\t\treturn -EINVAL;\n\t}\n\tif(!pgid) {\n\t\tpgid = p->pid;\n\t}\n\n\tif(p != current && p->ppid != current) {\n\t\treturn -ESRCH;\n\t}\n\tif(p->sid == p->pid || p->sid != current->sid) {\n\t\treturn -EPERM;\n\t}\n\n\t{\n\t\tstruct proc *p;\n\n\t\tFOR_EACH_PROCESS(p) {\n\t\t\tif(p->pgid == pgid && p->sid != current->sid) {\n\t\t\t\treturn -EPERM;\n\t\t\t}\n\t\t\tp = p->next;\n\t\t}\n\t}\n\n\tif(p != current && p->flags & PF_PEXEC) {\n\t\treturn -EACCES;\n\t}\n\n\tp->pgid = pgid;\n\n#ifdef __DEBUG__\n\tprintk(\" -> 0\\n\");\n#endif /*__DEBUG__ */\n\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/setregid.c",
    "content": "/*\n * fiwix/kernel/syscalls/setregid.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_setregid(__gid_t gid, __gid_t egid)\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_setregid(%d, %d) -> \", current->pid, gid, egid);\n#endif /*__DEBUG__ */\n\n\tif(IS_SUPERUSER) {\n\t\tif(egid != (__uid_t)-1) {\n\t\t\tif(gid != (__uid_t)-1 || (current->egid >= 0 && current->gid != egid)) {\n\t\t\t\tcurrent->sgid = egid;\n\t\t\t}\n\t\t\tcurrent->egid = egid;\n\t\t}\n\t\tif(gid != (__uid_t)-1) {\n\t\t\tcurrent->gid = gid;\n\t\t}\n\t} else {\n\t\tif(egid != (__uid_t)-1 && (current->gid == egid || current->egid == egid || current->sgid == egid)) {\n\t\t\tif(gid != (__uid_t)-1 || (current->egid >= 0 && current->gid != egid)) {\n\t\t\t\tcurrent->sgid = egid;\n\t\t\t}\n\t\t\tcurrent->egid = egid;\n\t\t} else {\n\t\t\treturn -EPERM;\n\t\t}\n\t\tif(gid != (__uid_t)-1 && (current->gid == gid || current->egid == gid)) {\n\t\t\tcurrent->gid = gid;\n\t\t} else {\n\t\t\treturn -EPERM;\n\t\t}\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/setreuid.c",
    "content": "/*\n * fiwix/kernel/syscalls/setreuid.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_setreuid(__uid_t uid, __uid_t euid)\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_setreuid(%d, %d) -> \", current->pid, uid, euid);\n#endif /*__DEBUG__ */\n\n\tif(IS_SUPERUSER) {\n\t\tif(euid != (__uid_t)-1) {\n\t\t\tif(uid != (__uid_t)-1 || (current->euid >= 0 && current->uid != euid)) {\n\t\t\t\tcurrent->suid = euid;\n\t\t\t}\n\t\t\tcurrent->euid = euid;\n\t\t}\n\t\tif(uid != (__uid_t)-1) {\n\t\t\tcurrent->uid = uid;\n\t\t}\n\t} else {\n\t\tif(euid != (__uid_t)-1 && (current->uid == euid || current->euid == euid || current->suid == euid)) {\n\t\t\tif(uid != (__uid_t)-1 || (current->euid >= 0 && current->uid != euid)) {\n\t\t\t\tcurrent->suid = euid;\n\t\t\t}\n\t\t\tcurrent->euid = euid;\n\t\t} else {\n\t\t\treturn -EPERM;\n\t\t}\n\t\tif(uid != (__uid_t)-1 && (current->uid == uid || current->euid == uid)) {\n\t\t\tcurrent->uid = uid;\n\t\t} else {\n\t\t\treturn -EPERM;\n\t\t}\n\t}\n\n#ifdef __DEBUG__\n\tprintk(\" 0\\n\");\n#endif /*__DEBUG__ */\n\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/setrlimit.c",
    "content": "/*\n * fiwix/kernel/syscalls/setrlimit.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/resource.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_setrlimit(int resource, const struct rlimit *rlim)\n{\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_setrlimit(%d, 0x%08x)\\n\", current->pid, resource, (unsigned int)rlim);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_user_area(VERIFY_READ, rlim, sizeof(struct rlimit)))) {\n\t\treturn errno;\n\t}\n\tif(resource < 0 || resource >= RLIM_NLIMITS) {\n\t\treturn -EINVAL;\n\t}\n\tif(rlim->rlim_cur > rlim->rlim_max) {\n\t\treturn -EINVAL;\n\t}\n\tif(!IS_SUPERUSER) {\n\t\tif(rlim->rlim_max > current->rlim[resource].rlim_max) {\n\t\t\treturn -EPERM;\n\t\t}\n\t}\n\tmemcpy_b(&current->rlim[resource], rlim, sizeof(struct rlimit));\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/setsid.c",
    "content": "/*\n * fiwix/kernel/syscalls/setsid.c\n *\n * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_setsid(void)\n{\n\tstruct proc *p;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_setsid()\\n\", current->pid);\n#endif /*__DEBUG__ */\n\n\tif(PG_LEADER(current)) {\n\t\treturn -EPERM;\n\t}\n\tFOR_EACH_PROCESS(p) {\t/* POSIX ANSI/IEEE Std 1003.1-1996 4.3.2 */\n\t\tif(p != current && p->pgid == current->pid) {\n\t\t\treturn -EPERM;\n\t\t}\n\t\tp = p->next;\n\t}\n\n\tcurrent->sid = current->pgid = current->pid;\n\tcurrent->ctty = NULL;\n\treturn current->sid;\n}\n"
  },
  {
    "path": "kernel/syscalls/settimeofday.c",
    "content": "/*\n * fiwix/kernel/syscalls/settimeofday.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/fs.h>\n#include <fiwix/time.h>\n#include <fiwix/timer.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_settimeofday(const struct timeval *tv, const struct timezone *tz)\n{\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_settimeofday()\\n\", current->pid);\n#endif /*__DEBUG__ */\n\n\tif(!IS_SUPERUSER) {\n\t\treturn -EPERM;\n\t}\n\n\tif(tv) {\n\t\tif((errno = check_user_area(VERIFY_READ, tv, sizeof(struct timeval)))) {\n\t\t\treturn errno;\n\t\t}\n\t\tCURRENT_TIME = tv->tv_sec;\n\t\tset_system_time(CURRENT_TIME);\n\t}\n\tif(tz) {\n\t\tif((errno = check_user_area(VERIFY_READ, tz, sizeof(struct timezone)))) {\n\t\t\treturn errno;\n\t\t}\n\t\tkstat.tz_minuteswest = tz->tz_minuteswest;\n\t\tkstat.tz_dsttime = tz->tz_dsttime;\n\t}\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/setuid.c",
    "content": "/*\n * fiwix/kernel/syscalls/setuid.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_setuid(__uid_t uid)\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_setuid(%d)\\n\", current->pid, uid);\n#endif /*__DEBUG__ */\n\n\tif(IS_SUPERUSER) {\n\t\tcurrent->uid = current->suid = uid;\n\t} else {\n\t\tif((current->uid != uid) && (current->suid != uid)) {\n\t\t\treturn -EPERM;\n\t\t}\n\t}\n\tcurrent->euid = uid;\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/sgetmask.c",
    "content": "/*\n * fiwix/kernel/syscalls/sgetmask.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/process.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_sgetmask(void)\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_sgetmask() -> \\n\", current->pid);\n#endif /*__DEBUG__ */\n\treturn current->sigblocked;\n}\n"
  },
  {
    "path": "kernel/syscalls/shmat.c",
    "content": "/*\n * fiwix/kernel/syscalls/shmat.c\n *\n * Copyright 2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/config.h>\n#include <fiwix/kernel.h>\n#include <fiwix/types.h>\n#include <fiwix/string.h>\n#include <fiwix/process.h>\n#include <fiwix/sched.h>\n#include <fiwix/errno.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/mm.h>\n#include <fiwix/mman.h>\n#include <fiwix/ipc.h>\n#include <fiwix/shm.h>\n#include <fiwix/stdio.h>\n\n#ifdef CONFIG_SYSVIPC\nint shm_map_page(struct vma *vma, unsigned int cr2)\n{\n\tstruct shmid_ds *seg;\n\tstruct page *pg;\n\tunsigned int addr, index;\n\n\tseg = (struct shmid_ds *)vma->object;\n\tindex = (cr2 - vma->start) / PAGE_SIZE;\n\taddr = seg->shm_pages[index];\n\n\tif(!addr) {\n\t\tif(!(addr = map_page(current, cr2, 0, vma->prot))) {\n\t\t\tprintk(\"%s(): Oops, map_page() returned 0!\\n\", __FUNCTION__);\n\t\t\treturn 1;\n\t\t}\n\t\tseg->shm_pages[index] = addr;\n\t\tshm_rss++;\n\t} else {\n\t\tif(!(addr = map_page(current, cr2, V2P(addr), vma->prot))) {\n\t\t\tprintk(\"%s(): Oops, map_page() returned 0!\\n\", __FUNCTION__);\n\t\t\treturn 1;\n\t\t}\n\t}\n\tpg = &page_table[V2P(addr) >> PAGE_SHIFT];\n\tpg->count++;\n\n\treturn 0;\n}\n\nint sys_shmat(int shmid, char *shmaddr, int shmflg, unsigned int *raddr)\n{\n\tstruct shmid_ds *seg;\n\tstruct vma *sega;\n\tunsigned int addr;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_shmat(%d, 0x%x, %d, 0x%x)\\n\", current->pid, shmid, (int)shmaddr, shmflg, (int)raddr);\n#endif /*__DEBUG__ */\n\n\tif(shmid < 0) {\n\t\treturn -EINVAL;\n\t}\n\n\tseg = shmseg[shmid % SHMMNI];\n\tif(seg == IPC_UNUSED) {\n\t\treturn -EINVAL;\n\t}\n\n\taddr = (unsigned int)shmaddr;\n\tif(addr) {\n\t\tif(shmflg & SHM_RND) {\n\t\t\taddr &= ~(SHMLBA - 1);\n\t\t} else {\n\t\t\tif(addr & (SHMLBA - 1)) {\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t}\n\t\tif(find_vma_intersection(addr, addr + seg->shm_segsz)) {\n\t\t\treturn -EINVAL;\n\t\t}\n\t} else {\n\t\tif(!(addr = get_unmapped_vma_region(seg->shm_segsz))) {\n\t\t\treturn -ENOMEM;\n\t\t}\n\t}\n\n\tif(!ipc_has_perms(&seg->shm_perm, shmflg & SHM_RDONLY ? IPC_R : IPC_R | IPC_W)) {\n\t\treturn -EACCES;\n\t}\n\n\tif(!(sega = shm_get_new_attach(seg))) {\n\t\treturn -ENOMEM;\n\t}\n\n\tsega->start = addr;\n\tsega->end = addr + seg->shm_segsz;\n\tsega->prot = PROT_READ | PROT_WRITE | PROT_EXEC;\n\tsega->flags = MAP_PRIVATE | MAP_FIXED;\n\tsega->offset = 0;\n\tsega->s_type = P_SHM;\n\tsega->inode = NULL;\n\tsega->o_mode = shmflg & SHM_RDONLY ? O_RDONLY : O_RDWR;\n\tseg->shm_nattch++;\n\n\terrno = do_mmap(NULL, addr, seg->shm_segsz, sega->prot, sega->flags, sega->offset, sega->s_type, sega->o_mode, seg);\n\tif(errno < 0 && errno > -PAGE_SIZE) {\n\t\treturn errno;\n\t}\n\n\tseg->shm_atime = CURRENT_TIME;\n\tseg->shm_lpid = current->pid;\n\t*raddr = addr;\n\n\treturn 0;\n}\n#endif /* CONFIG_SYSVIPC */\n"
  },
  {
    "path": "kernel/syscalls/shmctl.c",
    "content": "/*\n * fiwix/kernel/syscalls/shmctl.c\n *\n * Copyright 2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/config.h>\n#include <fiwix/kernel.h>\n#include <fiwix/types.h>\n#include <fiwix/string.h>\n#include <fiwix/process.h>\n#include <fiwix/sched.h>\n#include <fiwix/errno.h>\n#include <fiwix/ipc.h>\n#include <fiwix/shm.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\n#ifdef CONFIG_SYSVIPC\nint sys_shmctl(int shmid, int cmd, struct shmid_ds *buf)\n{\n\tstruct shmid_ds *seg;\n\tstruct shminfo *si;\n\tstruct shm_info *s_i;\n\tstruct ipc_perm *perm;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_shmctl(%d, %d, 0x%x)\\n\", current->pid, shmid, cmd, (int)buf);\n#endif /*__DEBUG__ */\n\n\tif(shmid < 0) {\n\t\treturn -EINVAL;\n\t}\n\n\tswitch(cmd) {\t\n\t\tcase IPC_STAT:\n\t\tcase SHM_STAT:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, buf, sizeof(struct shmid_ds)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tif(cmd == SHM_STAT) {\n\t\t\t\tif(shmid > max_segid) {\n\t\t\t\t\treturn -EINVAL;\n\t\t\t\t}\n\t\t\t\tseg = shmseg[shmid];\n\t\t\t} else {\n\t\t\t\tseg = shmseg[shmid % SHMMNI];\n\t\t\t}\n\t\t\tif(seg == IPC_UNUSED) {\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\tif(!ipc_has_perms(&seg->shm_perm, IPC_R)) {\n\t\t\t\treturn -EACCES;\n\t\t\t}\n\t\t\tmemcpy_b(buf, seg, sizeof(struct shmid_ds));\n\t\t\t/* private kernel information zeroed */\n\t\t\tbuf->shm_npages = 0;\n\t\t\tbuf->shm_pages = 0;\n\t\t\tbuf->shm_attaches = 0;\n\t\t\tif(cmd == SHM_STAT) {\n\t\t\t\treturn (seg->shm_perm.seq * SHMMNI) + shmid;\n\t\t\t}\n\t\t\treturn 0;\n\n\t\tcase IPC_SET:\n\t\t\tif((errno = check_user_area(VERIFY_READ, buf, sizeof(struct shmid_ds)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tseg = shmseg[shmid % SHMMNI];\n\t\t\tif(seg == IPC_UNUSED) {\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\tperm = &seg->shm_perm;\n\t\t\tif(!IS_SUPERUSER && current->euid != perm->uid && current->euid != perm->cuid) {\n\t\t\t\treturn -EPERM;\n\t\t\t}\n\t\t\tperm->uid = buf->shm_perm.uid;\n\t\t\tperm->gid = buf->shm_perm.gid;\n\t\t\tperm->mode = (perm->mode & ~0777) | (buf->shm_perm.mode & 0777);\n\t\t\tseg->shm_ctime = CURRENT_TIME;\n\t\t\treturn 0;\n\n\t\tcase IPC_RMID:\n\t\t\tseg = shmseg[shmid % SHMMNI];\n\t\t\tif(seg == IPC_UNUSED) {\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\tperm = &seg->shm_perm;\n\t\t\tif(!IS_SUPERUSER && current->euid != perm->uid && current->euid != perm->cuid) {\n\t\t\t\treturn -EPERM;\n\t\t\t}\n\t\t\tperm->mode |= SHM_DEST;\n\t\t\tif(!seg->shm_nattch) {\n\t\t\t\tfree_seg(shmid);\n\t\t\t}\n\t\t\treturn 0;\n\n\t\tcase IPC_INFO:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, buf, sizeof(struct shminfo)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tsi = (struct shminfo *)buf;\n\t\t\tsi->shmmax = SHMMAX;\n\t\t\tsi->shmmin = SHMMIN;\n\t\t\tsi->shmmni = SHMMNI;\n\t\t\tsi->shmseg = SHMSEG;\n\t\t\tsi->shmall = SHMALL;\n\t\t\treturn max_segid;\n\n\t\tcase SHM_INFO:\n\t\t\tif((errno = check_user_area(VERIFY_WRITE, buf, sizeof(struct shm_info)))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\ts_i = (struct shm_info *)buf;\n\t\t\ts_i->used_ids = num_segs;\n\t\t\ts_i->shm_tot = shm_tot;\n\t\t\ts_i->shm_rss = shm_rss;\n\t\t\ts_i->shm_swp = 0;\t\t/* FIXME: pending to do */\n\t\t\ts_i->swap_attempts = 0;\t\t/* FIXME: pending to do */\n\t\t\ts_i->swap_successes = 0;\t/* FIXME: pending to do */\n\t\t\treturn max_segid;\n\t}\n\n\treturn -EINVAL;\n}\n#endif /* CONFIG_SYSVIPC */\n"
  },
  {
    "path": "kernel/syscalls/shmdt.c",
    "content": "/*\n * fiwix/kernel/syscalls/shmdt.c\n *\n * Copyright 2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/config.h>\n#include <fiwix/kernel.h>\n#include <fiwix/types.h>\n#include <fiwix/string.h>\n#include <fiwix/process.h>\n#include <fiwix/sched.h>\n#include <fiwix/errno.h>\n#include <fiwix/mm.h>\n#include <fiwix/mman.h>\n#include <fiwix/ipc.h>\n#include <fiwix/shm.h>\n#include <fiwix/stdio.h>\n\n#ifdef CONFIG_SYSVIPC\nint sys_shmdt(char *shmaddr)\n{\n\tstruct vma *vma;\n\tstruct shmid_ds *seg;\n\tunsigned int addr;\n\tint n;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_shmdt(0x%x)\\n\", current->pid, (int)shmaddr);\n#endif /*__DEBUG__ */\n\n\taddr = (unsigned int)shmaddr;\n\n\tif(!(vma = find_vma_region(addr))) {\n\t\tprintk(\"WARNING: %s(): no vma region found!\\n\", __FUNCTION__);\n\t\treturn 0;\n\t}\n\tif(vma->s_type != P_SHM) {\n\t\tprintk(\"WARNING: %s(): vma region is not a shared memory!\\n\", __FUNCTION__);\n\t\treturn 0;\n\t}\n\tif(!(seg = (struct shmid_ds *)vma->object)) {\n\t\tprintk(\"WARNING: %s(): object is NULL!\\n\", __FUNCTION__);\n\t\treturn 0;\n\t}\n\n\tfor(n = 0; n < NUM_ATTACHES_PER_SEG; n++) {\n\t\tif(seg->shm_attaches[n].start == addr) {\n\t\t\tdo_munmap(addr, seg->shm_attaches[n].end - seg->shm_attaches[n].start);\n\t\t\tshm_release_attach(&seg->shm_attaches[n]);\n\t\t\tseg->shm_nattch--;\n\t\t}\n\t}\n\n\treturn 0;\n}\n#endif /* CONFIG_SYSVIPC */\n"
  },
  {
    "path": "kernel/syscalls/shmget.c",
    "content": "/*\n * fiwix/kernel/syscalls/shmget.c\n *\n * Copyright 2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/types.h>\n#include <fiwix/string.h>\n#include <fiwix/errno.h>\n#include <fiwix/process.h>\n#include <fiwix/mm.h>\n#include <fiwix/ipc.h>\n#include <fiwix/shm.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\n#ifdef CONFIG_SYSVIPC\nstruct shmid_ds *shmseg[SHMMNI];\nunsigned int num_segs;\nunsigned int max_segid;\nunsigned int shm_seq;\nunsigned int shm_tot;\nunsigned int shm_rss;\n\n/* FIXME: this should be allocated dynamically */\nstatic struct shmid_ds shmseg_pool[SHMMNI];\nstruct shmid_ds *shm_get_new_seg(void)\n{\n\tint n;\n\n\tfor(n = 0; n < SHMMNI; n++) {\n\t\tif(shmseg_pool[n].shm_ctime == 0) {\n\t\t\tshmseg_pool[n].shm_ctime = 1;\n\t\t\tif(!(shmseg_pool[n].shm_pages = (unsigned int *)kmalloc(PAGE_SIZE))) {\n\t\t\t\treturn NULL;\n\t\t\t}\n\t\t\tmemset_b(shmseg_pool[n].shm_pages, 0, PAGE_SIZE);\n\t\t\treturn &shmseg_pool[n];\n\t\t}\n\t}\n\treturn NULL;\n}\n\nvoid shm_release_seg(struct shmid_ds *seg)\n{\n\tkfree((unsigned int)seg->shm_pages);\n\tif(seg->shm_attaches) {\n\t\tkfree((unsigned int)seg->shm_attaches);\n\t}\n\tmemset_b(seg, 0, sizeof(struct shmid_ds));\n}\n\nvoid free_seg(int shmid)\n{\n\tstruct shmid_ds *seg;\n\tint npages;\n\n\tseg = shmseg[shmid % SHMMNI];\n\tnpages = (seg->shm_segsz + (PAGE_SIZE - 1)) >> PAGE_SHIFT;\n\tnum_segs--;\n\tshm_tot -= npages;\n\tshm_seq++;\n\tshmseg[shmid % SHMMNI] = (struct shmid_ds *)IPC_UNUSED;\n\tif((shmid % SHMMNI) == max_segid) {\n\t\twhile(max_segid) {\n\t\t\tif(shmseg[max_segid] != IPC_UNUSED) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tmax_segid--;\n\t\t}\n\t}\n\tshm_release_seg(seg);\n}\n\nstruct vma *shm_get_new_attach(struct shmid_ds *seg)\n{\n\tint n;\n\n\tif(!seg->shm_attaches) {\n\t\tif(!(seg->shm_attaches = (void *)kmalloc(PAGE_SIZE))) {\n\t\t\treturn NULL;\n\t\t}\n\t\tmemset_b(seg->shm_attaches, 0, PAGE_SIZE);\n\t}\n\tfor(n = 0; n < NUM_ATTACHES_PER_SEG; n++) {\n\t\tif(!seg->shm_attaches[n].start && !seg->shm_attaches[n].end) {\n\t\t\treturn &seg->shm_attaches[n];\n\t\t}\n\t}\n\treturn NULL;\n}\n\nvoid shm_release_attach(struct vma *attach)\n{\n\tmemset_b(attach, 0, sizeof(struct vma));\n}\n\nvoid shm_init(void)\n{\n\tint n;\n\n\tfor(n = 0; n < SHMMNI; n++) {\n\t\tshmseg[n] = (struct shmid_ds *)IPC_UNUSED;\n\t}\n\tmemset_b(shmseg_pool, 0, sizeof(shmseg_pool));\n\tnum_segs = max_segid = shm_seq = shm_tot = shm_rss = 0;\n}\n\nint sys_shmget(key_t key, __size_t size, int shmflg)\n{\n\tstruct shmid_ds *seg;\n\tstruct ipc_perm *perm;\n\tint n, npages;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_shmget(%d, %d, 0x%x)\\n\", current->pid, (int)key, size, shmflg);\n#endif /*__DEBUG__ */\n\n\tif(size < 0 || size > SHMMAX) {\n\t\treturn -EINVAL;\n\t}\n\n\tif(key == IPC_PRIVATE) {\n\t\t/* create a new segment */\n\t\tif(size < SHMMIN) {\n\t\t\treturn -EINVAL;\n\t\t}\n\t\tnpages = (size + (PAGE_SIZE - 1)) >> PAGE_SHIFT;\n\t\tif(shm_tot + npages >= SHMALL) {\n\t\t\treturn -ENOSPC;\n\t\t}\n\t\tif(!(seg = shm_get_new_seg())) {\n\t\t\treturn -ENOMEM;\n\t\t}\n\t\tfor(n = 0; n < SHMMNI; n++) {\n\t\t\tif(shmseg[n] == (struct shmid_ds *)IPC_UNUSED) {\n\t\t\t\tgoto init;\n\t\t\t}\n\t\t}\n\t\tshm_release_seg(seg);\n\t\treturn -ENOSPC;\n\t}\n\n\tseg = NULL;\n\n\tfor(n = 0; n < SHMMNI; n++) {\n\t\tif(shmseg[n] == (struct shmid_ds *)IPC_UNUSED) {\n\t\t\tcontinue;\n\t\t}\n\t\tif(key == shmseg[n]->shm_perm.key) {\n\t\t\tseg = shmseg[n];\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif(!seg) {\n\t\tif(!(shmflg & IPC_CREAT)) {\n\t\t\treturn -ENOENT;\n\t\t}\n\n\t\t/* create a new segment */\n\t\tif(size < SHMMIN) {\n\t\t\treturn -EINVAL;\n\t\t}\n\t\tnpages = (size + (PAGE_SIZE - 1)) >> PAGE_SHIFT;\n\t\tif(shm_tot + npages >= SHMALL) {\n\t\t\treturn -ENOSPC;\n\t\t}\n\t\tif(!(seg = shm_get_new_seg())) {\n\t\t\treturn -ENOMEM;\n\t\t}\n\t\tfor(n = 0; n < SHMMNI; n++) {\n\t\t\tif(shmseg[n] == (struct shmid_ds *)IPC_UNUSED) {\n\t\t\t\tgoto init;\n\t\t\t}\n\t\t}\n\t\tshm_release_seg(seg);\n\t\treturn -ENOSPC;\n\t} else {\n\t\tif((shmflg & (IPC_CREAT | IPC_EXCL)) == (IPC_CREAT | IPC_EXCL)) {\n\t\t\treturn -EEXIST;\n\t\t}\n\t\tif(!ipc_has_perms(&seg->shm_perm, shmflg)) {\n\t\t\treturn -EACCES;\n\t\t}\n\t\tif(size > seg->shm_segsz) {\n\t\t\treturn -EINVAL;\n\t\t}\n\t\treturn (seg->shm_perm.seq * SHMMNI) + n;\n\t}\n\ninit:\n\tperm = &seg->shm_perm;\n\tperm->key = key;\n\tperm->uid = perm->cuid = current->euid;\n\tperm->gid = perm->cgid = current->egid;\n\tperm->mode = shmflg & 0777;\n\tperm->seq = shm_seq;\n\tseg->shm_segsz = size;\n\tseg->shm_atime = seg->shm_dtime = 0;\n\tseg->shm_ctime = CURRENT_TIME;\n\tseg->shm_cpid = current->pid;\n\tseg->shm_lpid = 0;\n\tseg->shm_nattch = 0;\n\tseg->shm_npages = 0;\n\tseg->shm_attaches = 0;\n\tshmseg[n] = seg;\n\tif(n > max_segid) {\n\t\tmax_segid = n;\n\t}\n\tnum_segs++;\n\tshm_tot += npages;\n\treturn (seg->shm_perm.seq * SHMMNI) + n;\n}\n#endif /* CONFIG_SYSVIPC */\n"
  },
  {
    "path": "kernel/syscalls/sigaction.c",
    "content": "/*\n * fiwix/kernel/syscalls/sigaction.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/signal.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_sigaction(__sigset_t signum, const struct sigaction *newaction, struct sigaction *oldaction)\n{\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_sigaction(%d, 0x%08x, 0x%08x)\\n\", current->pid, signum, (unsigned int)newaction, (unsigned int)oldaction);\n#endif /*__DEBUG__ */\n\n\tif(signum < 1 || signum > NSIG) {\n\t\treturn -EINVAL;\n\t}\n\tif(signum == SIGKILL || signum == SIGSTOP) {\n\t\treturn -EINVAL;\n\t}\n\tif(oldaction) {\n\t\tif((errno = check_user_area(VERIFY_WRITE, oldaction, sizeof(struct sigaction)))) {\n\t\t\treturn errno;\n\t\t}\n\t\t*oldaction = current->sigaction[signum - 1];\n\t}\n\tif(newaction) {\n\t\tif((errno = check_user_area(VERIFY_READ, newaction, sizeof(struct sigaction)))) {\n\t\t\treturn errno;\n\t\t}\n\t\tcurrent->sigaction[signum - 1] = *newaction;\n\t\tif(current->sigaction[signum - 1].sa_handler == SIG_IGN) {\n\t\t\tif(signum != SIGCHLD) {\n\t\t\t\tcurrent->sigpending &= SIG_MASK(signum);\n\t\t\t}\n\t\t}\n\t\tif(current->sigaction[signum - 1].sa_handler == SIG_DFL) {\n\t\t\tif(signum != SIGCHLD) {\n\t\t\t\tcurrent->sigpending &= SIG_MASK(signum);\n\t\t\t}\n\t\t}\n\t}\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/signal.c",
    "content": "/*\n * fiwix/kernel/syscalls/signal.c\n *\n * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/syscalls.h>\n#include <fiwix/signal.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nunsigned int sys_signal(__sigset_t signum, void(* sighandler)(int))\n{\n\tstruct sigaction s;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_signal()\\n\", current->pid);\n#endif /*__DEBUG__ */\n\n\tif(signum < 1 || signum > NSIG) {\n\t\treturn -EINVAL;\n\t}\n\tif(signum == SIGKILL || signum == SIGSTOP) {\n\t\treturn -EINVAL;\n\t}\n\tif(sighandler != SIG_DFL && sighandler != SIG_IGN) {\n\t\tif((errno = check_user_area(VERIFY_READ, sighandler, sizeof(unsigned int)))) {\n\t\t\treturn errno;\n\t\t}\n\t}\n\n\tmemset_b(&s, 0, sizeof(struct sigaction));\n\ts.sa_handler = sighandler;\n\ts.sa_mask = 0;\n\ts.sa_flags = SA_RESETHAND;\n\tsighandler = current->sigaction[signum - 1].sa_handler;\n\tcurrent->sigaction[signum - 1] = s;\n\tif(current->sigaction[signum - 1].sa_handler == SIG_IGN) {\n\t\tif(signum != SIGCHLD) {\n\t\t\tcurrent->sigpending &= SIG_MASK(signum);\n\t\t}\n\t}\n\tif(current->sigaction[signum - 1].sa_handler == SIG_DFL) {\n\t\tif(signum != SIGCHLD) {\n\t\t\tcurrent->sigpending &= SIG_MASK(signum);\n\t\t}\n\t}\n\treturn (unsigned int)sighandler;\n}\n"
  },
  {
    "path": "kernel/syscalls/sigpending.c",
    "content": "/*\n * fiwix/kernel/syscalls/sigpending.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/signal.h>\n#include <fiwix/process.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_sigpending(__sigset_t *set)\n{\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_sigpending(0x%08x) -> \", current->pid, set);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_user_area(VERIFY_WRITE, set, sizeof(__sigset_t)))) {\n\t\treturn errno;\n\t}\n\tmemcpy_b(set, &current->sigpending, sizeof(__sigset_t));\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/sigprocmask.c",
    "content": "/*\n * fiwix/kernel/syscalls/sigprocmask.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/signal.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_sigprocmask(int how, const __sigset_t *set, __sigset_t *oldset)\n{\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_sigprocmask(%d, 0x%08x, 0x%08x)\\n\", current->pid, how, set, oldset);\n#endif /*__DEBUG__ */\n\n\tif(oldset) {\n\t\tif((errno = check_user_area(VERIFY_WRITE, oldset, sizeof(__sigset_t)))) {\n\t\t\treturn errno;\n\t\t}\n\t\t*oldset = current->sigblocked;\n\t}\n\n\tif(set) {\n\t\tif((errno = check_user_area(VERIFY_READ, set, sizeof(__sigset_t)))) {\n\t\t\treturn errno;\n\t\t}\n\t\tswitch(how) {\n\t\t\tcase SIG_BLOCK:\n\t\t\t\tcurrent->sigblocked |= (*set & SIG_BLOCKABLE);\n\t\t\t\tbreak;\n\t\t\tcase SIG_UNBLOCK:\n\t\t\t\tcurrent->sigblocked &= ~(*set & SIG_BLOCKABLE);\n\t\t\t\tbreak;\n\t\t\tcase SIG_SETMASK:\n\t\t\t\tcurrent->sigblocked = (*set & SIG_BLOCKABLE);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\treturn -EINVAL;\n\t\t}\n\t}\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/sigreturn.c",
    "content": "/*\n * fiwix/kernel/syscalls/sigreturn.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/process.h>\n#include <fiwix/sigcontext.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\n#ifdef CONFIG_SYSCALL_6TH_ARG\nint sys_sigreturn(unsigned int signum, int arg2, int arg3, int arg4, int arg5, int arg6, struct sigcontext *sc)\n#else\nint sys_sigreturn(unsigned int signum, int arg2, int arg3, int arg4, int arg5, struct sigcontext *sc)\n#endif /* CONFIG_SYSCALL_6TH_ARG */\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_sigreturn(0x%08x)\\n\", current->pid, signum);\n#endif /*__DEBUG__ */\n\n\tcurrent->sigblocked &= ~current->sigexecuting;\n\tcurrent->sigexecuting = 0;\n\tmemcpy_b(sc, &current->sc[signum - 1], sizeof(struct sigcontext));\n\n\t/*\n\t * We return here the value that the syscall was returning when it was\n\t * interrupted by a signal.\n\t */\n\treturn current->sc[signum - 1].eax;\n}\n"
  },
  {
    "path": "kernel/syscalls/sigsuspend.c",
    "content": "/*\n * fiwix/kernel/syscalls/sigsuspend.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/syscalls.h>\n#include <fiwix/signal.h>\n#include <fiwix/process.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_sigsuspend(__sigset_t *mask)\n{\n\t__sigset_t old_mask;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_sigsuspend(0x%08x) -> \", current->pid, mask);\n#endif /*__DEBUG__ */\n\n\told_mask = current->sigblocked;\n\tif(mask) {\n\t\tif((errno = check_user_area(VERIFY_READ, mask, sizeof(__sigset_t)))) {\n\t\t\treturn errno;\n\t\t}\n\t\tcurrent->sigblocked = (int)*mask & SIG_BLOCKABLE;\n\t} else {\n\t\tcurrent->sigblocked = 0 & SIG_BLOCKABLE;\n\t}\n\tsys_pause();\n\tcurrent->sigblocked = old_mask;\n\n#ifdef __DEBUG__\n\tprintk(\"-EINTR\\n\");\n#endif /*__DEBUG__ */\n\n\treturn -EINTR;\n}\n"
  },
  {
    "path": "kernel/syscalls/socketcall.c",
    "content": "/*\n * fiwix/kernel/syscalls/socketcall.c\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/config.h>\n#include <fiwix/net.h>\n#include <fiwix/errno.h>\n#include <fiwix/process.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_socketcall(int call, unsigned int *args)\n{\n#ifdef CONFIG_NET\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_socketcall(%d, 0x%08x)\\n\", current->pid, call, args);\n#endif /*__DEBUG__ */\n\n\tswitch(call) {\n\t\tcase SYS_SOCKET:\n\t\t\tif((errno = check_user_area(VERIFY_READ, args, sizeof(unsigned int) * 3))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\treturn socket(args[0], args[1], args[2]);\n\t\tcase SYS_BIND:\n\t\t\tif((errno = check_user_area(VERIFY_READ, args, sizeof(unsigned int) * 3))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\treturn bind(args[0], (struct sockaddr *)args[1], args[2]);\n\t\tcase SYS_CONNECT:\n\t\t\tif((errno = check_user_area(VERIFY_READ, args, sizeof(unsigned int) * 3))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\treturn connect(args[0], (struct sockaddr *)args[1], args[2]);\n\t\tcase SYS_LISTEN:\n\t\t\tif((errno = check_user_area(VERIFY_READ, args, sizeof(unsigned int) * 2))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\treturn listen(args[0], args[1]);\n\t\tcase SYS_ACCEPT:\n\t\t\tif((errno = check_user_area(VERIFY_READ, args, sizeof(unsigned int) * 3))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\treturn accept(args[0], (struct sockaddr *)args[1], (unsigned int *)args[2]);\n\t\tcase SYS_GETSOCKNAME:\n\t\t\tif((errno = check_user_area(VERIFY_READ, args, sizeof(unsigned int) * 3))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\treturn getname(args[0], (struct sockaddr *)args[1], (unsigned int *)args[2], SYS_GETSOCKNAME);\n\t\tcase SYS_GETPEERNAME:\n\t\t\tif((errno = check_user_area(VERIFY_READ, args, sizeof(unsigned int) * 3))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\treturn getname(args[0], (struct sockaddr *)args[1], (unsigned int *)args[2], SYS_GETPEERNAME);\n\t\tcase SYS_SOCKETPAIR:\n\t\t\tif((errno = check_user_area(VERIFY_READ, args, sizeof(unsigned int) * 4))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\treturn socketpair(args[0], args[1], args[2], (int *)args[3]);\n\t\tcase SYS_SEND:\n\t\t\tif((errno = check_user_area(VERIFY_READ, args, sizeof(unsigned int) * 4))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\treturn send(args[0], (void *)args[1], args[2], args[3]);\n\t\tcase SYS_RECV:\n\t\t\tif((errno = check_user_area(VERIFY_READ, args, sizeof(unsigned int) * 4))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\treturn recv(args[0], (void *)args[1], args[2], args[3]);\n\t\tcase SYS_SENDTO:\n\t\t\tif((errno = check_user_area(VERIFY_READ, args, sizeof(unsigned int) * 6))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\treturn sendto(args[0], (void *)args[1], args[2], args[3], (struct sockaddr *)args[4], args[5]);\n\t\tcase SYS_RECVFROM:\n\t\t\tif((errno = check_user_area(VERIFY_READ, args, sizeof(unsigned int) * 6))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\treturn recvfrom(args[0], (void *)args[1], args[2], args[3], (struct sockaddr *)args[4], (int *)args[5]);\n\t\tcase SYS_SHUTDOWN:\n\t\t\tif((errno = check_user_area(VERIFY_READ, args, sizeof(unsigned int) * 2))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\treturn shutdown(args[0], args[1]);\n\t\tcase SYS_SETSOCKOPT:\n\t\t\tif((errno = check_user_area(VERIFY_READ, args, sizeof(unsigned int) * 5))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\treturn setsockopt(args[0], args[1], args[2], (void *)args[3], args[4]);\n\t\tcase SYS_GETSOCKOPT:\n\t\t\tif((errno = check_user_area(VERIFY_READ, args, sizeof(unsigned int) * 5))) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\treturn getsockopt(args[0], args[1], args[2], (void *)args[3], (socklen_t *)args[4]);\n\t}\n\n\treturn -EINVAL;\n#else\n\treturn -ENOSYS;\n#endif /* CONFIG_NET */\n}\n"
  },
  {
    "path": "kernel/syscalls/ssetmask.c",
    "content": "/*\n * fiwix/kernel/syscalls/ssetmask.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/process.h>\n#include <fiwix/signal.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_ssetmask(int newmask)\n{\n\tint oldmask;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_ssetmask(0x%08x) -> \\n\", current->pid, newmask);\n#endif /*__DEBUG__ */\n\n\toldmask = current->sigblocked;\n\tcurrent->sigblocked = newmask & SIG_BLOCKABLE;\n\treturn oldmask;\n}\n"
  },
  {
    "path": "kernel/syscalls/stat.c",
    "content": "/*\n * fiwix/kernel/syscalls/stat.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/statbuf.h>\n#include <fiwix/fs.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_stat(const char *filename, struct old_stat *statbuf)\n{\n\tstruct inode *i;\n\tchar *tmp_name;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_stat(%s, 0x%08x) -> returning structure\\n\", current->pid, filename, (unsigned int )statbuf);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_user_area(VERIFY_WRITE, statbuf, sizeof(struct old_stat)))) {\n\t\treturn errno;\n\t}\n\tif((errno = malloc_name(filename, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = namei(tmp_name, &i, NULL, FOLLOW_LINKS))) {\n\t\tfree_name(tmp_name);\n\t\treturn errno;\n\t}\n\tstatbuf->st_dev = i->dev;\n\tstatbuf->st_ino = i->inode;\n\tstatbuf->st_mode = i->i_mode;\n\tstatbuf->st_nlink = i->i_nlink;\n\tstatbuf->st_uid = i->i_uid;\n\tstatbuf->st_gid = i->i_gid;\n\tstatbuf->st_rdev = i->rdev;\n\tstatbuf->st_size = i->i_size;\n\tstatbuf->st_atime = i->i_atime;\n\tstatbuf->st_mtime = i->i_mtime;\n\tstatbuf->st_ctime = i->i_ctime;\n\tiput(i);\n\tfree_name(tmp_name);\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/stat64.c",
    "content": "/*\n * fiwix/kernel/syscalls/stat64.c\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Copyright 2023, Richard R. Masters.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/statbuf.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_stat64(const char *filename, struct stat64 *statbuf)\n{\n\tstruct inode *i;\n\tchar *tmp_name;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_stat64('%s', 0x%08x) -> returning structure\\n\", current->pid, filename, (unsigned int)statbuf);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_user_area(VERIFY_WRITE, statbuf, sizeof(struct stat64)))) {\n\t\treturn errno;\n\t}\n\tif((errno = malloc_name(filename, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = namei(tmp_name, &i, NULL, FOLLOW_LINKS))) {\n\t\tfree_name(tmp_name);\n\t\treturn errno;\n\t}\n\tstatbuf->st_dev = i->dev;\n\tstatbuf->__st_dev_padding = 0;\n\tstatbuf->st_ino = i->inode;\n\tstatbuf->st_mode = i->i_mode;\n\tstatbuf->st_nlink = i->i_nlink;\n\tstatbuf->st_uid = i->i_uid;\n\tstatbuf->st_gid = i->i_gid;\n\tstatbuf->st_rdev = i->rdev;\n\tstatbuf->__st_rdev_padding = 0;\n\tstatbuf->st_size = i->i_size;\n\tstatbuf->st_blksize = i->sb->s_blocksize;\n\tstatbuf->st_blocks = i->i_blocks;\n\tif(!i->i_blocks) {\n\t\tstatbuf->st_blocks = (i->i_size / i->sb->s_blocksize) * 2;\n\t\tstatbuf->st_blocks++;\n\t}\n\tstatbuf->st_atime = i->i_atime;\n\tstatbuf->st_atime_nsec = 0;\n\tstatbuf->st_mtime = i->i_mtime;\n\tstatbuf->st_mtime_nsec = 0;\n\tstatbuf->st_ctime = i->i_ctime;\n\tstatbuf->st_ctime_nsec = 0;\n\tiput(i);\n\tfree_name(tmp_name);\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/statfs.c",
    "content": "/*\n * fiwix/kernel/syscalls/statfs.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/statfs.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_statfs(const char *filename, struct statfs *statfsbuf)\n{\n\tstruct inode *i;\n\tchar *tmp_name;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_statfs('%s', 0x%08x)\\n\", current->pid, filename, (unsigned int)statfsbuf);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_user_area(VERIFY_WRITE, statfsbuf, sizeof(struct statfs)))) {\n\t\treturn errno;\n\t}\n\tif((errno = malloc_name(filename, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = namei(tmp_name, &i, NULL, FOLLOW_LINKS))) {\n\t\tfree_name(tmp_name);\n\t\treturn errno;\n\t}\n\tfree_name(tmp_name);\n\n\tif(i->sb && i->sb->fsop && i->sb->fsop->statfs) {\n\t\ti->sb->fsop->statfs(i->sb, statfsbuf);\n\t\tiput(i);\n\t\treturn 0;\n\t}\n\tiput(i);\n\treturn -ENOSYS;\n}\n"
  },
  {
    "path": "kernel/syscalls/stime.c",
    "content": "/*\n * fiwix/kernel/syscalls/stime.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/timer.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_stime(__time_t *t)\n{\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_stime(0x%08x)\\n\", current->pid, (unsigned int)t);\n#endif /*__DEBUG__ */\n\n\tif(!IS_SUPERUSER) {\n\t\treturn -EPERM;\n\t}\n\tif((errno = check_user_area(VERIFY_READ, t, sizeof(__time_t)))) {\n\t\treturn errno;\n\t}\n\n\tset_system_time(*t);\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/symlink.c",
    "content": "/*\n * fiwix/kernel/syscalls/symlink.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_symlink(const char *oldpath, const char *newpath)\n{\n\tstruct inode *i, *dir;\n\tchar *tmp_oldpath, *tmp_newpath, *basename;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_symlink('%s', '%s')\\n\", current->pid, oldpath, newpath);\n#endif /*__DEBUG__ */\n\n\tif((errno = malloc_name(oldpath, &tmp_oldpath)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = malloc_name(newpath, &tmp_newpath)) < 0) {\n\t\tfree_name(tmp_oldpath);\n\t\treturn errno;\n\t}\n\tbasename = get_basename(tmp_newpath);\n\tif((errno = namei(tmp_newpath, &i, &dir, !FOLLOW_LINKS))) {\n\t\tif(!dir) {\n\t\t\tfree_name(tmp_oldpath);\n\t\t\tfree_name(tmp_newpath);\n\t\t\treturn errno;\n\t\t}\n\t}\n\tif(!errno) {\n\t\tiput(i);\n\t\tiput(dir);\n\t\tfree_name(tmp_oldpath);\n\t\tfree_name(tmp_newpath);\n\t\treturn -EEXIST;\n\t}\n\tif(IS_RDONLY_FS(dir)) {\n\t\tiput(dir);\n\t\tfree_name(tmp_oldpath);\n\t\tfree_name(tmp_newpath);\n\t\treturn -EROFS;\n\t}\n\n\tif(check_permission(TO_EXEC | TO_WRITE, dir) < 0) {\n\t\tiput(dir);\n\t\tfree_name(tmp_oldpath);\n\t\tfree_name(tmp_newpath);\n\t\treturn -EACCES;\n\t}\n\n\tif(dir->fsop && dir->fsop->symlink) {\n\t\terrno = dir->fsop->symlink(dir, basename, tmp_oldpath);\n\t} else {\n\t\terrno = -EPERM;\n\t}\n\tiput(dir);\n\tfree_name(tmp_oldpath);\n\tfree_name(tmp_newpath);\n\treturn errno;\n}\n"
  },
  {
    "path": "kernel/syscalls/sync.c",
    "content": "/*\n * fiwix/kernel/syscalls/sync.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/buffer.h>\n#include <fiwix/filesystems.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nvoid sys_sync(void)\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_sync()\\n\", current->pid);\n#endif /*__DEBUG__ */\n\n\tsync_superblocks(0);\t/* in all devices */\n\tsync_inodes(0);\t\t/* in all devices */\n\tsync_buffers(0);\t/* in all devices */\n\treturn;\n}\n"
  },
  {
    "path": "kernel/syscalls/sysinfo.c",
    "content": "/*\n * fiwix/kernel/syscalls/sysinfo.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/fs.h>\n#include <fiwix/system.h>\n#include <fiwix/sched.h>\n#include <fiwix/mm.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_sysinfo(struct sysinfo *info)\n{\n\tstruct sysinfo tmp_info;\n\tstruct proc *p;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_sysinfo(0x%08x)\\n \", current->pid, (unsigned int)info);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_user_area(VERIFY_WRITE, info, sizeof(struct sysinfo)))) {\n\t\treturn errno;\n\t}\n\tmemset_b(&tmp_info, 0, sizeof(struct sysinfo));\n\ttmp_info.loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT);\n\ttmp_info.loads[1] = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT);\n\ttmp_info.loads[2] = avenrun[2] << (SI_LOAD_SHIFT - FSHIFT);\n\ttmp_info.uptime = kstat.uptime;\n\ttmp_info.totalram = kstat.total_mem_pages << PAGE_SHIFT;\n\ttmp_info.freeram = kstat.free_pages << PAGE_SHIFT;\n\ttmp_info.sharedram = 0;\n\ttmp_info.bufferram = kstat.buffers_size * 1024;\n\ttmp_info.totalswap = 0;\n\ttmp_info.freeswap = 0;\n\tFOR_EACH_PROCESS(p) {\n\t\ttmp_info.procs++;\n\t\tp = p->next;\n\t}\n\n\tmemcpy_b(info, &tmp_info, sizeof(struct sysinfo));\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/syslog.c",
    "content": "/*\n * fiwix/kernel/syscalls/syslog.c\n *\n * Copyright 2025, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/syslog.h>\n#include <fiwix/sched.h>\n#include <fiwix/sleep.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_syslog(int type, char *buffer, int len)\n{\n\tchar c;\n\tint errno, n, count;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_syslog(%d, 0x%x, %d)\\n\", current->pid, type, buffer, len);\n#endif /*__DEBUG__ */\n\n\tif(type != SYSLOG_READ_ALL && !IS_SUPERUSER) {\n\t\treturn -EPERM;\n\t}\n\tif(type == SYSLOG_CLOSE || type == SYSLOG_OPEN) {\n\t\treturn 0;\n\t}\n\tif(type == SYSLOG_READ ||\n\t   type == SYSLOG_READ_ALL ||\n\t   type == SYSLOG_READ_CLEAR) {\n\t\tif(!buffer || len < 0) {\n\t\t\treturn -EINVAL;\n\t\t}\n\t\tif(!len) {\n\t\t\treturn 0;\n\t\t}\n\t\tif((errno = check_user_area(VERIFY_WRITE, buffer, len))) {\n\t\t\treturn errno;\n\t\t}\n\t\tcount = 0;\n\t\tif(type == SYSLOG_READ || type == SYSLOG_READ_CLEAR) {\n\t\t\twhile(!log_new_chars) {\n\t\t\t\tsleep(&sys_syslog, PROC_INTERRUPTIBLE);\n\t\t\t\tif(current->sigpending & ~current->sigblocked) {\n\t\t\t\t\treturn -ERESTART;\n\t\t\t\t}\n\t\t\t}\n\t\t\tn = (log_write - log_new_chars) & (LOG_BUF_LEN - 1);\n\t\t\twhile(log_new_chars && count < len) {\n\t\t\t\tif(!log_buf[n]) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tc = log_buf[n];\n\t\t\t\tlog_new_chars--;\n\t\t\t\tn++;\n\t\t\t\tn &= LOG_BUF_LEN - 1;\n\t\t\t\t*buffer = c;\n\t\t\t\tbuffer++;\n\t\t\t\tcount++;\n\t\t\t}\n\t\t\tif(type == SYSLOG_READ_CLEAR) {\n\t\t\t\tlog_new_chars = 0;\n\t\t\t}\n\t\t} else {\n\t\t\tlen = MIN(LOG_BUF_LEN, len);\n\t\t\tlen = MIN(log_size, len);\n\t\t\tn = log_read;\n\t\t\twhile(len) {\n\t\t\t\tif(!log_buf[n]) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tc = log_buf[n];\n\t\t\t\tn++;\n\t\t\t\tn &= LOG_BUF_LEN - 1;\n\t\t\t\t*buffer = c;\n\t\t\t\tbuffer++;\n\t\t\t\tlen--;\n\t\t\t\tcount++;\n\t\t\t}\n\t\t}\n\t\treturn count;\n\t}\n\tif(type == SYSLOG_CLEAR) {\n\t\tlog_new_chars = 0;\n\t\treturn 0;\n\t}\n\tif(type == SYSLOG_CONSOLE_OFF) {\n\t\tconsole_loglevel = 1;\n\t\treturn 0;\n\t}\n\tif(type == SYSLOG_CONSOLE_ON) {\n\t\tconsole_loglevel = DEFAULT_CONSOLE_LOGLEVEL;\n\t\treturn 0;\n\t}\n\tif(type == SYSLOG_CONSOLE_LEVEL) {\n\t\tif(len < 1 || len > 8) {\n\t\t\treturn -EINVAL;\n\t\t}\n\t\tconsole_loglevel = len;\n\t\treturn 0;\n\t}\n\tif(type == SYSLOG_SIZE_BUFFER) {\n\t\treturn LOG_BUF_LEN;\n\t}\n\n\treturn -EINVAL;\n}\n"
  },
  {
    "path": "kernel/syscalls/time.c",
    "content": "/*\n * fiwix/kernel/syscalls/time.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/kernel.h>\n#include <fiwix/fs.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_time(__time_t *tloc)\n{\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_time() -> \", current->pid);\n#endif /*__DEBUG__ */\n\n\tif(tloc) {\n\t\tif((errno = check_user_area(VERIFY_WRITE, tloc, sizeof(__time_t)))) {\n\t\t\treturn errno;\n\t\t}\n\t\t*tloc = CURRENT_TIME;\n\t}\n\n#ifdef __DEBUG__\n\tprintk(\"%d\\n\", CURRENT_TIME);\n#endif /*__DEBUG__ */\n\n\treturn CURRENT_TIME;\n}\n"
  },
  {
    "path": "kernel/syscalls/times.c",
    "content": "/*\n * fiwix/kernel/syscalls/times.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/types.h>\n#include <fiwix/syscalls.h>\n#include <fiwix/times.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_times(struct tms *buf)\n{\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_times(0x%08x) -> \", (unsigned int )buf);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_user_area(VERIFY_WRITE, buf, sizeof(struct tms)))) {\n\t\treturn errno;\n\t}\n\tif(buf) {\n\t\tbuf->tms_utime = tv2ticks(&current->usage.ru_utime);\n\t\tbuf->tms_stime = tv2ticks(&current->usage.ru_stime);\n\t\tbuf->tms_cutime = tv2ticks(&current->cusage.ru_utime);\n\t\tbuf->tms_cstime = tv2ticks(&current->cusage.ru_stime);\n\t}\n\n\treturn CURRENT_TICKS;\n}\n"
  },
  {
    "path": "kernel/syscalls/truncate.c",
    "content": "/*\n * fiwix/kernel/syscalls/truncate.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_truncate(const char *path, __off_t length)\n{\n\tstruct inode *i;\n\tchar *tmp_name;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_truncate(%s, %d)\\n\", current->pid, path, length);\n#endif /*__DEBUG__ */\n\n\tif((errno = malloc_name(path, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = namei(tmp_name, &i, NULL, FOLLOW_LINKS))) {\n\t\tfree_name(tmp_name);\n\t\treturn errno;\n\t}\n\tfree_name(tmp_name);\n\n\tif(S_ISDIR(i->i_mode)) {\n\t\tiput(i);\n\t\treturn -EISDIR;\n\t}\n\tif(IS_RDONLY_FS(i)) {\n\t\tiput(i);\n\t\treturn -EROFS;\n\t}\n\tif(check_permission(TO_WRITE, i) < 0) {\n\t\tiput(i);\n\t\treturn -EACCES;\n\t}\n\tif(length == i->i_size) {\n\t\tiput(i);\n\t\treturn 0;\n\t}\n\n\tif(i->fsop && i->fsop->truncate) {\n\t\tinode_lock(i);\n\t\terrno = i->fsop->truncate(i, length);\n\t\tinode_unlock(i);\n\t\tiput(i);\n\t\treturn errno;\n\t}\n\tiput(i);\n\treturn -EINVAL;\n}\n"
  },
  {
    "path": "kernel/syscalls/truncate64.c",
    "content": "/*\n * fiwix/kernel/syscalls/truncate64.c\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_truncate64(const char *path, __loff_t length)\n{\n\tstruct inode *i;\n\tchar *tmp_name;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_truncate64(%s, %llu)\\n\", current->pid, path, length);\n#endif /*__DEBUG__ */\n\n\tif((errno = malloc_name(path, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = namei(tmp_name, &i, NULL, FOLLOW_LINKS))) {\n\t\tfree_name(tmp_name);\n\t\treturn errno;\n\t}\n\tfree_name(tmp_name);\n\n\tif(S_ISDIR(i->i_mode)) {\n\t\tiput(i);\n\t\treturn -EISDIR;\n\t}\n\tif(IS_RDONLY_FS(i)) {\n\t\tiput(i);\n\t\treturn -EROFS;\n\t}\n\tif(check_permission(TO_WRITE, i) < 0) {\n\t\tiput(i);\n\t\treturn -EACCES;\n\t}\n\tif((__off_t)length == i->i_size) {\n\t\tiput(i);\n\t\treturn 0;\n\t}\n\n\tif(i->fsop && i->fsop->truncate) {\n\t\tinode_lock(i);\n\t\terrno = i->fsop->truncate(i, (__off_t)length);\n\t\tinode_unlock(i);\n\t\tiput(i);\n\t\treturn errno;\n\t}\n\tiput(i);\n\treturn -EINVAL;\n}\n"
  },
  {
    "path": "kernel/syscalls/umask.c",
    "content": "/*\n * fiwix/kernel/syscalls/umask.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/process.h>\n#include <fiwix/stat.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_umask(__mode_t mask)\n{\n\t__mode_t old_umask;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_umask(%d)\\n\", current->pid, mask);\n#endif /*__DEBUG__ */\n\n\told_umask = current->umask;\n\tcurrent->umask = mask & (S_IRWXU | S_IRWXG | S_IRWXO);\n\treturn old_umask;\n}\n"
  },
  {
    "path": "kernel/syscalls/umount.c",
    "content": "/*\n * fiwix/kernel/syscalls/umount.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/syscalls.h>\n#include <fiwix/process.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nint sys_umount(const char *target)\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_umount(%s)\\n\", current->pid, target);\n#endif /*__DEBUG__ */\n\n\treturn sys_umount2(target, 0);\n}\n"
  },
  {
    "path": "kernel/syscalls/umount2.c",
    "content": "/*\n * fiwix/kernel/syscalls/umount2.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/stat.h>\n#include <fiwix/sleep.h>\n#include <fiwix/devices.h>\n#include <fiwix/buffer.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstatic struct resource umount_resource = { 0, 0 };\n\nint sys_umount2(const char *target, int flags)\n{\n\tstruct inode *i_target;\n\tstruct mount *mp = NULL;\n\tstruct filesystems *fs;\n\tstruct device *d;\n\tstruct inode dummy_i;\n\tstruct superblock *sb;\n\tchar *tmp_target;\n\t__dev_t dev;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_umount2(%s, 0x%08x)\\n\", current->pid, target, flags);\n#endif /*__DEBUG__ */\n\n\tif(!IS_SUPERUSER) {\n\t\treturn -EPERM;\n\t}\n\tif((errno = malloc_name(target, &tmp_target)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = namei(tmp_target, &i_target, NULL, FOLLOW_LINKS))) {\n\t\tfree_name(tmp_target);\n\t\treturn errno;\n\t}\n\tif(!S_ISBLK(i_target->i_mode) && !S_ISDIR(i_target->i_mode)) {\n\t\tiput(i_target);\n\t\tfree_name(tmp_target);\n\t\treturn -EINVAL;\n\t}\n\n\tif(!(mp = get_mount_point(i_target))) {\n\t\tiput(i_target);\n\t\tfree_name(tmp_target);\n\t\treturn -EINVAL;\n\t}\n\tif(S_ISBLK(i_target->i_mode)) {\n\t\tdev = i_target->rdev;\n\t} else {\n\t\tdev = i_target->sb->dev;\n\t}\n\n\tif(!(sb = get_superblock(dev))) {\n\t\tprintk(\"WARNING: %s(): unable to get superblock from device %d,%d\\n\", __FUNCTION__, MAJOR(dev), MINOR(dev));\n\t\tiput(i_target);\n\t\tfree_name(tmp_target);\n\t\treturn -EINVAL;\n\t}\n\n\t/*\n\t * We must free now the inode in order to avoid having its 'count' to 2\n\t * when calling check_fs_busy(), specially if sys_umount() was called\n\t * using the mount-point instead of the device.\n\t */\n\tiput(i_target);\n\tfree_name(tmp_target);\n\n\tif(check_fs_busy(dev, sb->root)) {\n\t\treturn -EBUSY;\n\t}\n\n\tlock_resource(&umount_resource);\n\n\tfs = mp->fs;\n\tif(fs->fsop && fs->fsop->release_superblock) {\n\t\tfs->fsop->release_superblock(sb);\n\t}\n\tif(sb->fsop->flags & FSOP_REQUIRES_DEV) {\n\t\tif(!(d = get_device(BLK_DEV, dev))) {\n\t\t\tprintk(\"WARNING: %s(): block device %d,%d not registered!\\n\", __FUNCTION__, MAJOR(dev), MINOR(dev));\n\t\t\tunlock_resource(&umount_resource);\n\t\t\treturn -EINVAL;\n\t\t}\n\t\tmemset_b(&dummy_i, 0, sizeof(struct inode));\n\t\tdummy_i.dev = dummy_i.rdev = dev;\n\t\tif(d && d->fsop && d->fsop->close) {\n\t\t\td->fsop->close(&dummy_i, NULL);\n\t\t}\n\t}\n\n\tsb->dir->mount_point = NULL;\n\tiput(sb->root);\n\tiput(sb->dir);\n\n\tsync_superblocks(dev);\n\tsync_inodes(dev);\n\tsync_buffers(dev);\n\tinvalidate_buffers(dev);\n\tinvalidate_inodes(dev);\n\n\tdel_mount_point(mp);\n\tunlock_resource(&umount_resource);\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/uname.c",
    "content": "/*\n * fiwix/kernel/syscalls/uname.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/utsname.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_uname(struct old_utsname *uname)\n{\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_uname(0x%08x) -> returning \", current->pid, (unsigned int)uname);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_user_area(VERIFY_WRITE, uname, sizeof(struct old_utsname)))) {\n\t\treturn errno;\n\t}\n\tmemcpy_b(&uname->sysname, &sys_utsname.sysname, sizeof(sys_utsname.sysname));\n\tmemcpy_b(&uname->nodename, &sys_utsname.nodename, sizeof(sys_utsname.nodename));\n\tmemcpy_b(&uname->release, &sys_utsname.release, sizeof(sys_utsname.release));\n\tmemcpy_b(&uname->version, &sys_utsname.version, sizeof(sys_utsname.version));\n\tmemcpy_b(&uname->machine, &sys_utsname.machine, sizeof(sys_utsname.machine));\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/unlink.c",
    "content": "/*\n * fiwix/kernel/syscalls/unlink.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/syscalls.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_unlink(const char *filename)\n{\n\tstruct inode *i, *dir;\n\tchar *tmp_name, *basename;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_unlink('%s')\\n\", current->pid, filename);\n#endif /*__DEBUG__ */\n\n\tif((errno = malloc_name(filename, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = namei(tmp_name, &i, &dir, !FOLLOW_LINKS))) {\n\t\tif(dir) {\n\t\t\tiput(dir);\n\t\t}\n\t\tfree_name(tmp_name);\n\t\treturn errno;\n\t}\n\tif(S_ISDIR(i->i_mode)) {\n\t\tiput(i);\n\t\tiput(dir);\n\t\tfree_name(tmp_name);\n\t\treturn -EPERM;\t/* Linux returns -EISDIR */\n\t}\n\tif(IS_RDONLY_FS(i)) {\n\t\tiput(i);\n\t\tiput(dir);\n\t\tfree_name(tmp_name);\n\t\treturn -EROFS;\n\t}\n\tif(check_permission(TO_EXEC | TO_WRITE, dir) < 0) {\n\t\tiput(i);\n\t\tiput(dir);\n\t\tfree_name(tmp_name);\n\t\treturn -EACCES;\n\t}\n\n\t/* check sticky permission bit */\n\tif(dir->i_mode & S_ISVTX) {\n\t\tif(check_user_permission(i)) {\n\t\t\tiput(i);\n\t\t\tiput(dir);\n\t\t\tfree_name(tmp_name);\n\t\t\treturn -EPERM;\n\t\t}\n\t}\n\n\tbasename = get_basename(filename);\n\tif(dir->fsop && dir->fsop->unlink) {\n\t\terrno = dir->fsop->unlink(dir, i, basename);\n\t} else {\n\t\terrno = -EPERM;\n\t}\n\tiput(i);\n\tiput(dir);\n\tfree_name(tmp_name);\n\treturn errno;\n}\n"
  },
  {
    "path": "kernel/syscalls/ustat.c",
    "content": "/*\n * fiwix/kernel/syscalls/ustat.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/ustat.h>\n#include <fiwix/statfs.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_ustat(__dev_t dev, struct ustat *ubuf)\n{\n\tstruct superblock *sb;\n\tstruct statfs statfsbuf;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_ustat(%d, 0x%08x)\\n\", current->pid, dev, (int)ubuf);\n#endif /*__DEBUG__ */\n\tif((errno = check_user_area(VERIFY_WRITE, ubuf, sizeof(struct ustat)))) {\n\t\treturn errno;\n\t}\n\tif(!(sb = get_superblock(dev))) {\n\t\treturn -EINVAL;\n\t}\n\tif(sb->fsop && sb->fsop->statfs) {\n\t\tsb->fsop->statfs(sb, &statfsbuf);\n\t\tmemset_b(ubuf, 0, sizeof(struct ustat));\n\t\tubuf->f_tfree = statfsbuf.f_bfree;\n\t\tubuf->f_tinode = statfsbuf.f_ffree;\n\t\treturn 0;\n\t}\n\treturn -ENOSYS;\n}\n"
  },
  {
    "path": "kernel/syscalls/utime.c",
    "content": "/*\n * fiwix/kernel/syscalls/utime.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/fs.h>\n#include <fiwix/utime.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_utime(const char *filename, struct utimbuf *times)\n{\n\tstruct inode *i;\n\tchar *tmp_name;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_utime('%s', 0x%08x)\\n\", current->pid, filename, (int)times);\n#endif /*__DEBUG__ */\n\n\tif((errno = malloc_name(filename, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = namei(tmp_name, &i, NULL, FOLLOW_LINKS))) {\n\t\tfree_name(tmp_name);\n\t\treturn errno;\n\t}\n\n\tif(IS_RDONLY_FS(i)) {\n\t\tiput(i);\n\t\tfree_name(tmp_name);\n\t\treturn -EROFS;\n\t}\n\n\tif(!times) {\n\t\tif(check_user_permission(i) || check_permission(TO_WRITE, i)) {\n\t\t\tiput(i);\n\t\t\tfree_name(tmp_name);\n\t\t\treturn -EACCES;\n\t\t}\n\t\ti->i_atime = CURRENT_TIME;\n\t\ti->i_mtime = CURRENT_TIME;\n\t} else {\n\t\tif((errno = check_user_area(VERIFY_READ, times, sizeof(struct utimbuf)))) {\n\t\t\tiput(i);\n\t\t\tfree_name(tmp_name);\n\t\t\treturn errno;\n\t\t}\n\t\tif(check_user_permission(i)) {\n\t\t\tiput(i);\n\t\t\tfree_name(tmp_name);\n\t\t\treturn -EPERM;\n\t\t}\n\t\ti->i_atime = times->actime;\n\t\ti->i_mtime = times->modtime;\n\t}\n\n\ti->i_ctime = CURRENT_TIME;\n\ti->state |= INODE_DIRTY;\n\tiput(i);\n\tfree_name(tmp_name);\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/utimes.c",
    "content": "/*\n * fiwix/kernel/syscalls/utimes.c\n *\n * Copyright 2018-2023, Jordi Sanfeliu. All rights reserved.\n * Copyright 2023, Richard R. Masters. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/fs.h>\n#include <fiwix/utime.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_utimes(const char *filename, struct timeval times[2])\n{\n\tstruct inode *i;\n\tchar *tmp_name;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_utimes('%s', 0x%08x)\\n\", current->pid, filename, (int)times);\n#endif /*__DEBUG__ */\n\n\tif((errno = malloc_name(filename, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = namei(tmp_name, &i, NULL, FOLLOW_LINKS))) {\n\t\tfree_name(tmp_name);\n\t\treturn errno;\n\t}\n\n\tif(IS_RDONLY_FS(i)) {\n\t\tiput(i);\n\t\tfree_name(tmp_name);\n\t\treturn -EROFS;\n\t}\n\n\tif(!times) {\n\t\tif(check_user_permission(i) || check_permission(TO_WRITE, i)) {\n\t\t\tiput(i);\n\t\t\tfree_name(tmp_name);\n\t\t\treturn -EACCES;\n\t\t}\n\t\ti->i_atime = CURRENT_TIME;\n\t\ti->i_mtime = CURRENT_TIME;\n\t} else {\n\t\tif((errno = check_user_area(VERIFY_READ, times, sizeof(struct timeval) * 2))) {\n\t\t\tiput(i);\n\t\t\tfree_name(tmp_name);\n\t\t\treturn errno;\n\t\t}\n\t\tif(check_user_permission(i)) {\n\t\t\tiput(i);\n\t\t\tfree_name(tmp_name);\n\t\t\treturn -EPERM;\n\t\t}\n\t\ti->i_atime = times[0].tv_sec;\n\t\ti->i_mtime = times[1].tv_sec;\n\t}\n\n\ti->i_ctime = CURRENT_TIME;\n\ti->state |= INODE_DIRTY;\n\tiput(i);\n\tfree_name(tmp_name);\n\treturn 0;\n}\n"
  },
  {
    "path": "kernel/syscalls/wait4.c",
    "content": "/*\n * fiwix/kernel/syscalls/wait4.c\n *\n * Copyright 2018-2021, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/fs.h>\n#include <fiwix/resource.h>\n#include <fiwix/signal.h>\n#include <fiwix/sched.h>\n#include <fiwix/sleep.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_wait4(__pid_t pid, int *status, int options, struct rusage *ru)\n{\n\tstruct proc *p;\n\tint flag, signum, errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_wait4(%d, status, %d)\\n\", current->pid, pid, options);\n#endif /*__DEBUG__ */\n\n\tif(ru) {\n\t\tif((errno = check_user_area(VERIFY_WRITE, ru, sizeof(struct rusage)))) {\n\t\t\treturn errno;\n\t\t}\n\t}\n\twhile(current->children) {\n\t\tflag = 0;\n\t\tFOR_EACH_PROCESS(p) {\n\t\t\tif(p->ppid != current) {\n\t\t\t\tp = p->next;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif(pid > 0) {\n\t\t\t\tif(p->pid == pid) {\n\t\t\t\t\tflag = 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(!pid) {\n\t\t\t\tif(p->pgid == current->pgid) {\n\t\t\t\t\tflag = 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(pid < -1) {\n\t\t\t\tif(p->pgid == -pid) {\n\t\t\t\t\tflag = 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(pid == -1) {\n\t\t\t\tflag = 1;\n\t\t\t}\n\t\t\tif(flag) {\n\t\t\t\tif(p->state == PROC_STOPPED) {\n\t\t\t\t\tif(!p->exit_code) {\n\t\t\t\t\t\tp = p->next;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif(status) {\n\t\t\t\t\t\t*status = (p->exit_code << 8) | 0x7F;\n\t\t\t\t\t}\n\t\t\t\t\tp->exit_code = 0;\n\t\t\t\t\tif(ru) {\n\t\t\t\t\t\tget_rusage(p, ru);\n\t\t\t\t\t}\n\t\t\t\t\treturn p->pid;\n\t\t\t\t}\n\t\t\t\tif(p->state == PROC_ZOMBIE) {\n\t\t\t\t\tadd_rusage(p);\n\t\t\t\t\tif(status) {\n\t\t\t\t\t\t*status = p->exit_code;\n\t\t\t\t\t}\n\t\t\t\t\tif(ru) {\n\t\t\t\t\t\tget_rusage(p, ru);\n\t\t\t\t\t}\n\t\t\t\t\treturn remove_zombie(p);\n\t\t\t\t}\n\t\t\t}\n\t\t\tp = p->next;\n\t\t\tflag = 0;\n\t\t}\n\t\tif(options & WNOHANG) {\n\t\t\tif(flag) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tif((signum = sleep(&sys_wait4, PROC_INTERRUPTIBLE))) {\n\t\t\treturn signum;\n\t\t}\n\t\tcurrent->sigpending &= SIG_MASK(SIGCHLD);\n\t}\n\treturn -ECHILD;\n}\n"
  },
  {
    "path": "kernel/syscalls/waitpid.c",
    "content": "/*\n * fiwix/kernel/syscalls/waitpid.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/syscalls.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_waitpid(__pid_t pid, int *status, int options)\n{\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_waitpid(%d, 0x%08x, %d)\\n\", current->pid, pid,  status ? *status : 0, options);\n#endif /*__DEBUG__ */\n\treturn sys_wait4(pid, status, options, NULL);\n}\n"
  },
  {
    "path": "kernel/syscalls/write.c",
    "content": "/*\n * fiwix/kernel/syscalls/write.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_write(unsigned int ufd, const char *buf, int count)\n{\n\tstruct inode *i;\n\tint errno;\n\n#ifdef __DEBUG__\n/*\tprintk(\"(pid %d) sys_write(%d, '%s', %d)\\n\", current->pid, ufd, buf, count);*/\n\tprintk(\"(pid %d) sys_write(%d, 0x%08x, %d) -> \", current->pid, ufd, buf, count);\n#endif /*__DEBUG__ */\n\n\tCHECK_UFD(ufd);\n\tif((errno = check_user_area(VERIFY_READ, buf, count))) {\n\t\treturn errno;\n\t}\n\tif(!(fd_table[current->fd[ufd]].flags & (O_RDWR | O_WRONLY))) {\n\t\treturn -EBADF;\n\t}\n\tif(!count) {\n\t\treturn 0;\n\t}\n\tif(count < 0) {\n\t\treturn -EINVAL;\n\t}\n\ti = fd_table[current->fd[ufd]].inode;\n\tif(i->fsop && i->fsop->write) {\n\t\terrno = i->fsop->write(i, &fd_table[current->fd[ufd]], buf, count);\n#ifdef __DEBUG__\n\t\tprintk(\"%d\\n\", errno);\n#endif /*__DEBUG__ */\n\t\treturn errno;\n\t}\n\treturn -EINVAL;\n}\n"
  },
  {
    "path": "kernel/syscalls/writev.c",
    "content": "/*\n * fiwix/kernel/syscalls/writev.c\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Copyright 2023, Richard R. Masters.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/fs.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/errno.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\nint sys_writev(int ufd, const struct iovec *iov, int iovcnt)\n{\n\tstruct inode *i;\n\tint errno;\n\tint bytes_written = 0;\n\tint vi;\t/* vector index */\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sys_writev(%d, 0x%08x, %d) -> \", current->pid, ufd, iov, iovcnt);\n#endif /*__DEBUG__ */\n\n\tCHECK_UFD(ufd);\n\tif(iovcnt < 0 || iovcnt > UIO_MAXIOV) {\n\t\treturn -EINVAL;\n\t}\n\tfor (vi = 0; vi < iovcnt; vi++) {\n\t\tconst struct iovec *io_write = &iov[vi];\n\t\tif(!io_write->iov_len) {\n\t\t\tcontinue;\n\t\t}\n\t\tif((errno = check_user_area(VERIFY_READ, io_write->iov_base, io_write->iov_len))) {\n\t\t\treturn errno;\n\t\t}\n\t\tif(fd_table[current->fd[ufd]].flags & O_RDONLY) {\n\t\t\treturn -EBADF;\n\t\t}\n\t\tif(io_write->iov_len < 0) {\n\t\t\treturn -EINVAL;\n\t\t}\n\t\ti = fd_table[current->fd[ufd]].inode;\n\t\tif(i->fsop && i->fsop->write) {\n\t\t\terrno = i->fsop->write(i, &fd_table[current->fd[ufd]], io_write->iov_base, io_write->iov_len);\n\t\t\tif (errno < 0) {\n\t\t\t\treturn errno;\n\t\t\t}\n\t\t\tbytes_written += errno;\n\t\t} else {\n\t\t\treturn -EINVAL;\n\t\t}\n\t}\n#ifdef __DEBUG__\n\tprintk(\"%d\\n\", bytes_written);\n#endif /*__DEBUG__ */\n\treturn bytes_written;\n}\n"
  },
  {
    "path": "kernel/syscalls.c",
    "content": "/*\n * fiwix/kernel/syscalls.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/types.h>\n#include <fiwix/syscalls.h>\n#include <fiwix/mm.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/stdio.h>\n#endif /*__DEBUG__ */\n\nstatic int verify_address(int type, const void *addr, unsigned int size)\n{\n\tstruct vma *vma;\n\tunsigned int start, gs;\n\n\t/* no need to verify anything if the caller is the kernel */\n\tGET_GS(gs);\n\tif(gs == KERNEL_DS) {\n\t\treturn 0;\n\t}\n\n\t/*\n\t * The vma_table of the INIT process is not setup yet when it\n\t * calls sys_open() and sys_execve() from init_trampoline(),\n\t * but these calls are trusted.\n\t */\n\tif(!current->vma_table) {\n\t\treturn 0;\n\t}\n\n\tstart = (unsigned int)addr;\n\tif(!(vma = find_vma_region(start))) {\n\t\t/*\n\t\t * We need to check here if addr looks like a possible\n\t\t * non-existent user stack address. If so, just return 0\n\t\t * and let 'do_page_fault()' to handle the imminent page\n\t\t * fault as soon as the kernel will try to access it.\n\t\t */\n\t\tvma = current->vma_table->prev;\n\t\tif(vma) {\n\t\t\tif(vma->s_type == P_STACK) {\n\t\t\t\tif(start < vma->start && start > vma->prev->end) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn -EFAULT;\n\t}\n\n\tfor(;;) {\n\t\tif(type == VERIFY_WRITE) {\n\t\t\tif(!(vma->prot & PROT_WRITE)) {\n\t\t\t\treturn -EFAULT;\n\t\t\t}\n\t\t} else {\n\t\t\tif(!(vma->prot & PROT_READ)) {\n\t\t\t\treturn -EFAULT;\n\t\t\t}\n\t\t}\n\t\tif(start + size <= vma->end) {\n\t\t\tbreak;\n\t\t}\n\t\tif(!(vma = find_vma_region(vma->end))) {\n\t\t\treturn -EFAULT;\n\t\t}\n\t}\n\treturn 0;\n}\n\nvoid free_name(const char *name)\n{\n\tkfree((unsigned int)name);\n}\n\n/*\n * This function has two objectives:\n *\n * 1. verifies the memory address validity of the char pointer supplied by the\n *    user and, at the same time, limits its length to PAGE_SIZE (4096) bytes.\n * 2. creates a copy of 'string' in the kernel data space.\n */\nint malloc_name(const char *string, char **name)\n{\n\tchar *b;\n\tint n, errno;\n\n\tif((errno = verify_address(PROT_READ, string, 0))) {\n\t\treturn errno;\n\t}\n\n\tif(!(b = (char *)kmalloc(PAGE_SIZE))) {\n\t\treturn -ENOMEM;\n\t}\n\t*name = b;\n\tfor(n = 0; n < PAGE_SIZE; n++) {\n\t\tif(!(*b = *string)) {\n\t\t\treturn 0;\n\t\t}\n\t\tb++;\n\t\tstring++;\n\t}\n\n\tfree_name(*name);\n\treturn -ENAMETOOLONG;\n}\n\nint check_user_permission(struct inode *i)\n{\n\tif(!IS_SUPERUSER) {\n\t\tif(current->euid != i->i_uid) {\n\t\t\treturn 1;\n\t\t}\n\t}\n\treturn 0;\n}\n\nint check_group(struct inode *i)\n{\n\tint n;\n\t__gid_t gid;\n\n\tif(current->flags & PF_USEREAL) {\n\t\tgid = current->gid;\n\t} else {\n\t\tgid = current->egid;\n\t}\n\n\tif(i->i_gid == gid) {\n\t\treturn 0;\n\t}\n\n\tfor(n = 0; n < NGROUPS_MAX; n++) {\n\t\tif(current->groups[n] == -1) {\n\t\t\tbreak;\n\t\t}\n\t\tif(current->groups[n] == i->i_gid) {\n\t\t\treturn 0;\n\t\t}\n\t}\n\treturn 1;\n}\n\nint check_user_area(int type, const void *addr, unsigned int size)\n{\n\treturn verify_address(type, addr, size);\n}\n\nint check_permission(int mask, struct inode *i)\n{\n\t__uid_t uid;\n\n\tif(current->flags & PF_USEREAL) {\n\t\tuid = current->uid;\n\t} else {\n\t\tuid = current->euid;\n\t}\n\n\tif(mask & TO_EXEC) {\n\t\tif(!(i->i_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {\n\t\t\treturn -EACCES;\n\t\t}\n\t}\n\tif(uid == 0) {\n\t\treturn 0;\n\t}\n\tif(i->i_uid == uid) {\n\t\tif((((i->i_mode >> 6) & 7) & mask) == mask) {\n\t\t\treturn 0;\n\t\t}\n\t}\n\tif(!check_group(i)) {\n\t\tif((((i->i_mode >> 3) & 7) & mask) == mask) {\n\t\t\treturn 0;\n\t\t}\n\t}\n\tif(((i->i_mode & 7) & mask) == mask) {\n\t\treturn 0;\n\t}\n\n\treturn -EACCES;\n}\n\n\n/* Linux 2.0 i386 ABI system call (plus some from Linux 2.2 and Linux 2.4) */\nvoid *syscall_table[] = {\n\tNULL,\t\t\t\t/* 0 */\t/* sys_setup (-ENOSYS) */\n\tsys_exit,\n\tsys_fork,\n\tsys_read,\n\tsys_write,\n\tsys_open,\t\t\t/* 5 */\n\tsys_close,\n\tsys_waitpid,\n\tsys_creat,\n\tsys_link,\n\tsys_unlink,\t\t\t/* 10 */\n\tsys_execve,\n\tsys_chdir,\n\tsys_time,\n\tsys_mknod,\n\tsys_chmod,\t\t\t/* 15 */\n\tsys_lchown,\n\tNULL,\t\t\t\t\t/* sys_break (-ENOSYS) */\n\tsys_stat,\n\tsys_lseek,\n\tsys_getpid,\t\t\t/* 20 */\n\tsys_mount,\n\tsys_umount,\n\tsys_setuid,\n\tsys_getuid,\n\tsys_stime, \t\t\t/* 25 */\n\tNULL,\t/* sys_ptrace */\n\tsys_alarm,\n\tsys_fstat,\n\tsys_pause,\n\tsys_utime,\t\t\t/* 30 */\n\tNULL,\t\t\t\t\t/* sys_stty (-ENOSYS) */\n\tNULL,\t\t\t\t\t/* sys_gtty (-ENOSYS) */\n\tsys_access,\n\tNULL,\t/* sys_nice */\n\tsys_ftime,\t\t\t/* 35 */\n\tsys_sync,\n\tsys_kill,\n\tsys_rename,\n\tsys_mkdir,\n\tsys_rmdir,\t\t\t/* 40 */\n\tsys_dup,\n\tsys_pipe,\n\tsys_times,\n\tNULL,\t/* sys_prof */\n\tsys_brk,\t\t\t/* 45 */\n\tsys_setgid,\n\tsys_getgid,\n\tsys_signal,\n\tsys_geteuid,\n\tsys_getegid,\t\t\t/* 50 */\n\tNULL,\t/* sys_acct */\n\tsys_umount2,\n\tNULL,\t\t\t\t\t/* sys_lock (-ENOSYS) */\n\tsys_ioctl,\n\tsys_fcntl,\t\t\t/* 55 */\n\tNULL,\t\t\t\t\t/* sys_mpx (-ENOSYS) */\n\tsys_setpgid,\n\tNULL,\t\t\t\t\t/* sys_ulimit (-ENOSYS) */\n\tsys_olduname,\n\tsys_umask,\t\t\t/* 60 */\n\tsys_chroot,\n\tsys_ustat,\n\tsys_dup2,\n\tsys_getppid,\n\tsys_getpgrp,\t\t\t/* 65 */\n\tsys_setsid,\n\tsys_sigaction,\n\tsys_sgetmask,\n\tsys_ssetmask,\n\tsys_setreuid,\t\t\t/* 70 */\n\tsys_setregid,\n\tsys_sigsuspend,\n\tsys_sigpending,\n\tsys_sethostname,\n\tsys_setrlimit,\t\t\t/* 75 */\n\tsys_getrlimit,\n\tsys_getrusage,\n\tsys_gettimeofday,\n\tsys_settimeofday,\n\tsys_getgroups,\t\t\t/* 80 */\n\tsys_setgroups,\n\told_select,\n\tsys_symlink,\n\tsys_lstat,\n\tsys_readlink,\t\t\t/* 85 */\n\tNULL,\t/* sys_uselib */\n\tNULL,\t/* sys_swapon */\n\tsys_reboot,\n\tNULL,\t/* old_readdir */\n\told_mmap,\t\t\t/* 90 */\n\tsys_munmap,\n\tsys_truncate,\n\tsys_ftruncate,\n\tsys_fchmod,\n\tsys_fchown,\t\t\t/* 95 */\n\tNULL,\t/* sys_getpriority */\n\tNULL,\t/* sys_setpriority */\n\tNULL,\t\t\t\t\t/* sys_profil (-ENOSYS) */\n\tsys_statfs,\n\tsys_fstatfs,\t\t\t/* 100 */\n\tsys_ioperm,\n\tsys_socketcall,\n\tsys_syslog,\n\tsys_setitimer,\n\tsys_getitimer,\t\t\t/* 105 */\n\tsys_newstat,\n\tsys_newlstat,\n\tsys_newfstat,\n\tsys_uname,\n\tsys_iopl,\t\t\t/* 110 */\n\tNULL,\t/* sys_vhangup */\n\tNULL,\t\t\t\t\t/* sys_idle (-ENOSYS) */\n\tNULL,\t/* sys_vm86old */\n\tsys_wait4,\n\tNULL,\t/* sys_swapoff */\t/* 115 */\n\tsys_sysinfo,\n#ifdef CONFIG_SYSVIPC\n\tsys_ipc,\n#else\n\tNULL,\t/* sys_ipc */\n#endif /* CONFIG_SYSVIPC */\n\tsys_fsync,\n\tsys_sigreturn,\n\tNULL,\t/* sys_clone */\t\t/* 120 */\n\tsys_setdomainname,\n\tsys_newuname,\n\tNULL,\t/* sys_modify_ldt */\n\tNULL,\t/* sys_adjtimex */\n\tsys_mprotect,\t\t\t/* 125 */\n\tsys_sigprocmask,\n\tNULL,\t/* sys_create_module */\n\tNULL,\t/* sys_init_module */\n\tNULL,\t/* sys_delete_module */\n\tNULL,\t/* sys_get_kernel_syms */\t/* 130 */\n\tNULL,\t/* sys_quotactl */\n\tsys_getpgid,\n\tsys_fchdir,\n\tNULL,\t/* sys_bdflush */\n\tNULL,\t/* sys_sysfs */\t\t/* 135 */\n\tsys_personality,\n\tNULL,\t\t\t\t\t/* afs_syscall (-ENOSYS) */\n\tsys_setfsuid,\n\tsys_setfsgid,\n\tsys_llseek,\t\t\t/* 140 */\n\tsys_getdents,\n\tsys_select,\n\tsys_flock,\n\tNULL,\t/* sys_msync */\n\tsys_readv,\t\t\t/* 145 */\n\tsys_writev,\n\tsys_getsid,\n\tsys_fdatasync,\n\tNULL,\t/* sys_sysctl */\n\tNULL,\t/* sys_mlock */\t\t/* 150 */\n\tNULL,\t/* sys_munlock */\n\tNULL,\t/* sys_mlockall */\n\tNULL,\t/* sys_munlockall */\n\tNULL,\t/* sys_sched_setparam */\n\tNULL,\t/* sys_sched_getparam */\t/* 155 */\n\tNULL,\t/* sys_sched_setscheduler */\n\tNULL,\t/* sys_sched_getscheduler */\n\tNULL,\t/* sys_sched_yield */\n\tNULL,\t/* sys_sched_get_priority_max */\n\tNULL,\t/* sys_sched_get_priority_min */\t/* 160 */\n\tNULL,\t/* sys_sched_rr_get_interval */\n\tsys_nanosleep,\n\tNULL,\t/* sys_mremap */\n\tNULL,\n\tNULL,\t\t\t\t/* 165 */\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\t\t\t\t/* 170 */\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\t\t\t\t/* 175 */\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\t\t\t\t/* 180 */\n\tNULL,\n\tsys_chown,\n\tsys_getcwd,\n\tNULL,\n\tNULL,\t\t\t\t/* 185 */\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\n\tsys_fork,\t\t\t/* 190 (sys_vfork) */\n\tNULL,\n#ifdef CONFIG_MMAP2\n\tsys_mmap2,\n#else\n\tNULL,\n#endif\n\tsys_truncate64,\n\tsys_ftruncate64,\n\tsys_stat64,\t\t\t/* 195 */\n\tsys_lstat64,\n\tsys_fstat64,\n\tNULL,\n\tNULL,\n\tNULL,\t\t\t\t/* 200 */\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\t\t\t\t/* 205 */\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\t\t\t\t/* 210 */\n\tNULL,\n\tsys_chown32,\n\tNULL,\n\tNULL,\n\tNULL,\t\t\t\t/* 215 */\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\n\tsys_getdents64,\t\t\t/* 220 */\n\tsys_fcntl64,\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\t\t\t\t/* 225 */\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\t\t\t\t/* 230 */\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\t\t\t\t/* 235 */\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\t\t\t\t/* 240 */\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\t\t\t\t/* 245 */\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\t\t\t\t/* 250 */\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\t\t\t\t/* 255 */\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\t\t\t\t/* 260 */\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\t\t\t\t/* 265 */\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\n\tNULL,\t\t\t\t/* 270 */\n\tsys_utimes,\n};\n\nstatic void do_bad_syscall(unsigned int num)\n{\n#ifdef __DEBUG__\n\tprintk(\"***** (pid %d) system call %d not supported yet *****\\n\", current->pid, num);\n#endif /*__DEBUG__ */\n}\n\n/*\n * The argument 'struct sigcontext' is needed because there are some system\n * calls (such as sys_iopl and sys_fork) that need to get information from\n * certain registers (EFLAGS and ESP). The rest of system calls will ignore\n * such extra argument.\n */\n#ifdef CONFIG_SYSCALL_6TH_ARG\nint do_syscall(unsigned int num, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, struct sigcontext sc)\n#else\nint do_syscall(unsigned int num, int arg1, int arg2, int arg3, int arg4, int arg5, struct sigcontext sc)\n#endif /* CONFIG_SYSCALL_6TH_ARG */\n{\n\tint (*sys_func)(int, ...);\n\n\tif(num > NR_SYSCALLS) {\n\t\tdo_bad_syscall(num);\n\t\treturn -ENOSYS;\n\t}\n\tsys_func = syscall_table[num];\n\tif(!sys_func) {\n\t\tdo_bad_syscall(num);\n\t\treturn -ENOSYS;\n\t}\n\tcurrent->sp = (unsigned int)&sc;\n#ifdef CONFIG_SYSCALL_6TH_ARG\n\treturn sys_func(arg1, arg2, arg3, arg4, arg5, arg6, &sc);\n#else\n\treturn sys_func(arg1, arg2, arg3, arg4, arg5, &sc);\n#endif /* CONFIG_SYSCALL_6TH_ARG */\n}\n"
  },
  {
    "path": "kernel/timer.c",
    "content": "/*\n * fiwix/kernel/timer.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/segments.h>\n#include <fiwix/cmos.h>\n#include <fiwix/pit.h>\n#include <fiwix/timer.h>\n#include <fiwix/time.h>\n#include <fiwix/irq.h>\n#include <fiwix/sched.h>\n#include <fiwix/pic.h>\n#include <fiwix/cmos.h>\n#include <fiwix/signal.h>\n#include <fiwix/process.h>\n#include <fiwix/sleep.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n/*\n * timer.c implements a callout table using a singly linked list.\n *\n *  head\n * +---------+  ----------+  ...  ----------+\n * |data|next|  |data|next|  ...  |data|next|\n * |    |  -->  |    |  -->  ...  |    |  / |\n * +---------+  ----------+  ...  ----------+\n *  (callout)    (callout)         (callout)\n */\n\n#define LATCH\t(OSCIL / HZ)\n\nstruct callout callout_pool[NR_CALLOUTS];\nstruct callout *callout_pool_head;\nstruct callout *callout_head;\n\nstatic char month[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };\nunsigned int avenrun[3] = { 0, 0, 0 };\n\nstatic struct bh timer_bh = { 0, &irq_timer_bh, NULL };\nstatic struct bh callouts_bh = { 0, &do_callouts_bh, NULL };\nstatic struct interrupt irq_config_timer = { 0, \"timer\", &irq_timer, NULL };\n\nstatic unsigned int count_active_procs(void)\n{\n\tint counter;\n\tstruct proc *p;\n\n\tcounter = 0;\n\tFOR_EACH_PROCESS(p) {\n\t\tif(p->state == PROC_RUNNING ||\n\t\t  (p->state == PROC_SLEEPING && p->flags & PF_NOTINTERRUPT)) {\n\t\t\tcounter += FIXED_1;\n\t\t}\n\t\tp = p->next;\n\t}\n\treturn counter;\n}\n\nstatic void calc_load(void)\n{\n\tunsigned int active_procs;\n\tstatic int count = LOAD_FREQ;\n\n\tif(count-- >= 0) {\n\t\treturn;\n\t}\n\n\tcount = LOAD_FREQ;\n\tactive_procs = count_active_procs();\n\tCALC_LOAD(avenrun[0], EXP_1, active_procs);\n\tCALC_LOAD(avenrun[1], EXP_5, active_procs);\n\tCALC_LOAD(avenrun[2], EXP_15, active_procs);\n}\n\nstatic struct callout *get_free_callout(void)\n{\n\tstruct callout *new;\n\n\tnew = NULL;\n\tif(callout_pool_head) {\n\t\tnew = callout_pool_head;\n\t\tcallout_pool_head = callout_pool_head->next;\n\t\tnew->next = NULL;\n\t}\n\treturn new;\n}\n\nstatic void put_free_callout(struct callout *old)\n{\n\told->next = callout_pool_head;\n\tcallout_pool_head = old;\n}\n\nstatic void do_del_callout(struct callout *c)\n{\n\tstruct callout **tmp;\n\n\tif(callout_head) {\n\t\ttmp = &callout_head;\n\t\twhile(*tmp) {\n\t\t\tif((*tmp) == c) {\n\t\t\t\tif((*tmp)->next != NULL) {\n\t\t\t\t\t*tmp = (*tmp)->next;\n\t\t\t\t\t(*tmp)->expires += c->expires;\n\t\t\t\t} else {\n\t\t\t\t\t*tmp = NULL;\n\t\t\t\t}\n\t\t\t\tput_free_callout(c);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\ttmp = &(*tmp)->next;\n\t\t}\n\t}\n}\n\nvoid add_callout(struct callout_req *creq, unsigned int ticks)\n{\n\tunsigned int flags;\n\tstruct callout *c, **tmp;\n\n\tdel_callout(creq);\n\tSAVE_FLAGS(flags); CLI();\n\n\tif(!(c = get_free_callout())) {\n\t\tprintk(\"WARNING: %s(): no more callout slots!\\n\", __FUNCTION__);\n\t\tRESTORE_FLAGS(flags);\n\t\treturn;\n\t}\n\n\t/* setup the new callout */\n\tmemset_b(c, 0, sizeof(struct callout));\n\tc->expires = ticks;\n\tc->fn = creq->fn;\n\tc->arg = creq->arg;\n\n\tif(!callout_head) {\n\t\tcallout_head = c;\n\t} else {\n\t\ttmp = &callout_head;\n\t\twhile(*tmp) {\n\t\t\tif((*tmp)->expires > c->expires) {\n\t\t\t\t(*tmp)->expires -= c->expires;\n\t\t\t\tc->next = *tmp;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tc->expires -= (*tmp)->expires;\n\t\t\ttmp = &(*tmp)->next;\n\t\t}\n\t\t*tmp = c;\n\t}\n\tRESTORE_FLAGS(flags);\n}\n\nvoid del_callout(struct callout_req *creq)\n{\n\tunsigned int flags;\n\tstruct callout *c;\n\n\tSAVE_FLAGS(flags); CLI();\n\tc = callout_head;\n\twhile(c) {\n\t\tif(c->fn == creq->fn && c->arg == creq->arg) {\n\t\t\tdo_del_callout(c);\n\t\t\tbreak;\n\t\t}\n\t\tc = c->next;\n\t}\n\tRESTORE_FLAGS(flags);\n}\n\nvoid irq_timer(int num, struct sigcontext *sc)\n{\n\tif((++CURRENT_TICKS % HZ) == 0) {\n\t\tCURRENT_TIME++;\n\t\tkstat.uptime++;\n\t}\n\n\ttimer_bh.flags |= BH_ACTIVE;\n}\n\nunsigned int tv2ticks(const struct timeval *tv)\n{\n\treturn((tv->tv_sec * HZ) + tv->tv_usec * HZ / 1000000);\n}\n\nvoid ticks2tv(int ticks, struct timeval *tv)\n{\n\ttv->tv_sec = ticks / HZ;\n\ttv->tv_usec = (ticks % HZ) * 1000000 / HZ;\n}\n\nint setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value)\n{\n\tswitch(which) {\n\t\tcase ITIMER_REAL:\n\t\t\tif((unsigned int)old_value) {\n\t\t\t\tticks2tv(current->it_real_interval, &old_value->it_interval);\n\t\t\t\tticks2tv(current->it_real_value, &old_value->it_value);\n\t\t\t}\n\t\t\tcurrent->it_real_interval = tv2ticks(&new_value->it_interval);\n\t\t\tcurrent->it_real_value = tv2ticks(&new_value->it_value);\n\t\t\tbreak;\n\t\tcase ITIMER_VIRTUAL:\n\t\t\tif((unsigned int)old_value) {\n\t\t\t\tticks2tv(current->it_virt_interval, &old_value->it_interval);\n\t\t\t\tticks2tv(current->it_virt_value, &old_value->it_value);\n\t\t\t}\n\t\t\tcurrent->it_virt_interval = tv2ticks(&new_value->it_interval);\n\t\t\tcurrent->it_virt_value = tv2ticks(&new_value->it_value);\n\t\t\tbreak;\n\t\tcase ITIMER_PROF:\n\t\t\tif((unsigned int)old_value) {\n\t\t\t\tticks2tv(current->it_prof_interval, &old_value->it_interval);\n\t\t\t\tticks2tv(current->it_prof_value, &old_value->it_value);\n\t\t\t}\n\t\t\tcurrent->it_prof_interval = tv2ticks(&new_value->it_interval);\n\t\t\tcurrent->it_prof_value = tv2ticks(&new_value->it_value);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\treturn -EINVAL;\n\t}\n\n\treturn 0;\n}\n\nunsigned int mktime(struct tm *tm)\n{\n\tint n, total_days;\n\tunsigned int seconds;\n\n\ttotal_days = 0;\n\n\tfor(n = UNIX_EPOCH; n < tm->tm_year; n++) {\n\t\ttotal_days += DAYS_PER_YEAR(n);\n\t}\n\tfor(n = 0; n < (tm->tm_month - 1); n++) {\n\t\ttotal_days += month[n];\n\t\tif(n == 1) {\n\t\t\ttotal_days += LEAP_YEAR(tm->tm_year) ? 1 : 0;\n\t\t}\n\t}\n\n\ttotal_days += (tm->tm_mday - 1);\n\tseconds = total_days * SECS_PER_DAY;\n\tseconds += tm->tm_hour * SECS_PER_HOUR;\n\tseconds += tm->tm_min * SECS_PER_MIN;\n\tseconds += tm->tm_sec;\n\treturn seconds;\n}\n\nvoid irq_timer_bh(struct sigcontext *sc)\n{\n\tstruct proc *p;\n\n\tif(sc->cs == KERNEL_CS) {\n\t\tcurrent->usage.ru_stime.tv_usec += TICK;\n\t\tif(current->usage.ru_stime.tv_usec >= 1000000) {\n\t\t\tcurrent->usage.ru_stime.tv_sec++;\n\t\t\tcurrent->usage.ru_stime.tv_usec -= 1000000;\n\t\t}\n\t\tif(current->pid != IDLE) {\n\t\t\tkstat.cpu_system++;\n\t\t}\n\t} else {\n\t\tcurrent->usage.ru_utime.tv_usec += TICK;\n\t\tif(current->usage.ru_utime.tv_usec >= 1000000) {\n\t\t\tcurrent->usage.ru_utime.tv_sec++;\n\t\t\tcurrent->usage.ru_utime.tv_usec -= 1000000;\n\t\t}\n\t\tif(current->pid != IDLE) {\n\t\t\tkstat.cpu_user++;\n\t\t}\n\t\tif(current->it_virt_value > 0) {\n\t\t\tcurrent->it_virt_value--;\n\t\t\tif(!current->it_virt_value) {\n\t\t\t\tcurrent->it_virt_value = current->it_virt_interval;\n\t\t\t\tsend_sig(current, SIGVTALRM);\n\t\t\t}\n\t\t}\n\t}\n\n\tif(current->usage.ru_utime.tv_sec + current->usage.ru_stime.tv_sec > current->rlim[RLIMIT_CPU].rlim_cur) {\n\t\tsend_sig(current, SIGXCPU);\n\t}\n\n\tif(current->it_prof_value > 0) {\n\t\tcurrent->it_prof_value--;\n\t\tif(!current->it_prof_value) {\n\t\t\tcurrent->it_prof_value = current->it_prof_interval;\n\t\t\tsend_sig(current, SIGPROF);\n\t\t}\n\t}\n\n\tcalc_load();\n\tFOR_EACH_PROCESS(p) {\n\t\tif(p->timeout > 0 && p->timeout < INFINITE_WAIT) {\n\t\t\tp->timeout--;\n\t\t\tif(!p->timeout) {\n\t\t\t\twakeup_proc(p);\n\t\t\t}\n\t\t}\n\t\tif(p->it_real_value > 0) {\n\t\t\tp->it_real_value--;\n\t\t\tif(!p->it_real_value) {\n\t\t\t\tp->it_real_value = p->it_real_interval;\n\t\t\t\tsend_sig(p, SIGALRM);\n\t\t\t}\n\t\t}\n\t\tp = p->next;\n\t}\n\n\t/* callouts */\n\tif(callout_head) {\n\t\tif(callout_head->expires > 0) {\n\t\t\tcallout_head->expires--;\n\t\t\tif(!callout_head->expires) {\n\t\t\t\tcallouts_bh.flags |= BH_ACTIVE;\n\t\t\t}\n\t\t} else {\n\t\t\tprintk(\"%s(): callout losing ticks.\\n\", __FUNCTION__);\n\t\t\tcallouts_bh.flags |= BH_ACTIVE;\n\t\t}\n\t}\n\n\tif(current->pid > IDLE && --current->cpu_count <= 0) {\n\t\tcurrent->cpu_count = 0;\n\t\tneed_resched = 1;\n\t}\n}\n\nvoid do_callouts_bh(struct sigcontext *sc)\n{\n\tstruct callout *c;\n\tvoid (*fn)(unsigned int);\n\tunsigned int arg;\n\n\twhile(callout_head) {\n\t\tif(callout_head->expires) {\n\t\t\tbreak;\n\t\t}\n\t\tif(!can_lock_area(AREA_CALLOUT)) {\n\t\t\tbreak;\n\t\t}\n\t\tfn = callout_head->fn;\n\t\targ = callout_head->arg;\n\t\tc = callout_head;\n\t\tcallout_head = callout_head->next;\n\t\tput_free_callout(c);\n\t\tunlock_area(AREA_CALLOUT);\n\t\tfn(arg);\n\t}\n}\n\nvoid get_system_time(void)\n{\n\tshort int cmos_century;\n\tstruct tm tm;\n\t\t  \n\t/* read date and time from CMOS */\n\ttm.tm_sec = cmos_read_date(CMOS_SEC);\n\ttm.tm_min = cmos_read_date(CMOS_MIN);\n\ttm.tm_hour = cmos_read_date(CMOS_HOUR);\n\ttm.tm_mday = cmos_read_date(CMOS_DAY);\n\ttm.tm_month = cmos_read_date(CMOS_MONTH);\n\ttm.tm_year = cmos_read_date(CMOS_YEAR);\n\tcmos_century = cmos_read_date(CMOS_CENTURY);\n\ttm.tm_year += cmos_century * 100;\n\n\tkstat.boot_time = CURRENT_TIME = mktime(&tm);\n}\n\nvoid set_system_time(__time_t t)\n{\n\tint sec, spm, min, hour, d, m, y;\n\n\tsec = t;\n\ty = 1970;\n\twhile(sec >= (DAYS_PER_YEAR(y) * SECS_PER_DAY)) {\n\t\tsec -= (DAYS_PER_YEAR(y) * SECS_PER_DAY);\n\t\ty++;\n\t}\n\n\tm = 0;\n\twhile(sec > month[m] * SECS_PER_DAY) {\n\t\tspm = month[m] * SECS_PER_DAY;\n\t\tif(m == 1) {\n\t\t\tspm = LEAP_YEAR(y) ? spm + SECS_PER_DAY : spm;\n\t\t}\n\t\tsec -= spm;\n\t\tm++;\n\t}\n\tm++;\n\n\td = 1;\n\twhile(sec >= SECS_PER_DAY) {\n\t\tsec -= SECS_PER_DAY;\n\t\td++;\n\t}\n\n\thour = 0;\n\twhile(sec >= SECS_PER_HOUR) {\n\t\tsec -= SECS_PER_HOUR;\n\t\thour++;\n\t}\n\n\tmin = 0;\n\twhile(sec >= SECS_PER_MIN) {\n\t\tsec -= SECS_PER_MIN;\n\t\tmin++;\n\t}\n\n\t/* write date and time to CMOS */\n\tcmos_write_date(CMOS_SEC, sec);\n\tcmos_write_date(CMOS_MIN, min);\n\tcmos_write_date(CMOS_HOUR, hour);\n\tcmos_write_date(CMOS_DAY, d);\n\tcmos_write_date(CMOS_MONTH, m);\n\tcmos_write_date(CMOS_YEAR, y % 100);\n\tcmos_write_date(CMOS_CENTURY, (y - (y % 100)) / 100);\n\n\tCURRENT_TIME = t;\n}\n\nint gettimeoffset(void)\n{\n\tint count;\n\n\tcount = pit_getcounter0();\n\tcount = (LATCH - count) * TICK;\n\tcount /= LATCH;\n\n\treturn count;\n}\n\nvoid timer_init(void)\n{\n\tint n;\n\tstruct callout *c;\n\n\tadd_bh(&timer_bh);\n\tadd_bh(&callouts_bh);\n\n\tpit_init(HZ);\n\n\tmemset_b(callout_pool, 0, sizeof(callout_pool));\n\n\t/* callout free list initialization */\n\tcallout_pool_head = NULL;\n\tn = NR_CALLOUTS;\n\twhile(n--) {\n\t\tc = &callout_pool[n];\n\t\tput_free_callout(c);\n\t}\n\tcallout_head = NULL;\n\n\tprintk(\"clock     -                 %d\\ttype=PIT Hz=%d\\n\", TIMER_IRQ, HZ);\n\tif(!register_irq(TIMER_IRQ, &irq_config_timer)) {\n\t\tenable_irq(TIMER_IRQ);\n\t}\n}\n"
  },
  {
    "path": "kernel/traps.c",
    "content": "/*\n * fiwix/kernel/traps.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/traps.h>\n#include <fiwix/cpu.h>\n#include <fiwix/pit.h>\n#include <fiwix/mm.h>\n#include <fiwix/process.h>\n#include <fiwix/signal.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n#include <fiwix/sched.h>\n\nstruct traps traps_table[NR_EXCEPTIONS] = {\n\t{ \"Divide Error\", do_divide_error, 0 },\n\t{ \"Debug\", do_debug, 0 },\n\t{ \"NMI Interrupt\", do_nmi_interrupt, 0 },\n\t{ \"Breakpoint\", do_breakpoint, 0 },\n\t{ \"Overflow\" , do_overflow, 0 },\n\t{ \"BOUND Range Exceeded\", do_bound, 0 },\n\t{ \"Invalid Opcode\", do_invalid_opcode, 0 },\n\t{ \"Device Not Available (No Math Coprocessor)\", do_no_math_coprocessor, 0 },\n\t{ \"Double Fault\", do_double_fault, 1 },\n\t{ \"Coprocessor Segment Overrun\", do_coprocessor_segment_overrun, 0 },\n\t{ \"Invalid TSS\", do_invalid_tss, 1 },\n\t{ \"Segment Not Present\", do_segment_not_present, 1 },\n\t{ \"Stack-Segment Fault\", do_stack_segment_fault, 1 },\n\t{ \"General Protection\", do_general_protection, 1 },\n\t{ \"Page Fault\", do_page_fault, 1 },\n\t{ \"Intel reserved\", do_reserved, 0 },\n\t{ \"x87 FPU Floating-Point Error\", do_floating_point_error, 0 },\n\t{ \"Alignment Check\", do_alignment_check, 1 },\n\t{ \"Machine Check\", do_machine_check, 0 },\n\t{ \"SIMD Floating-Point Exception\", do_simd_fault, 0 },\n\t{ \"Intel reserved\", do_reserved, 0 },\n\t{ \"Intel reserved\", do_reserved, 0 },\n\t{ \"Intel reserved\", do_reserved, 0 },\n\t{ \"Intel reserved\", do_reserved, 0 },\n\t{ \"Intel reserved\", do_reserved, 0 },\n\t{ \"Intel reserved\", do_reserved, 0 },\n\t{ \"Intel reserved\", do_reserved, 0 },\n\t{ \"Intel reserved\", do_reserved, 0 },\n\t{ \"Intel reserved\", do_reserved, 0 },\n\t{ \"Intel reserved\", do_reserved, 0 },\n\t{ \"Intel reserved\", do_reserved, 0 },\n\t{ \"Intel reserved\", do_reserved, 0 }\n};\n\nvoid do_divide_error(unsigned int trap, struct sigcontext *sc)\n{\n\tif(dump_registers(trap, sc)) {\n\t\tPANIC(\"\");\n\t}\n\tsend_sig(current, SIGFPE);\n\treturn;\n}\n\nvoid do_debug(unsigned int trap, struct sigcontext *sc)\n{\n\tif(dump_registers(trap, sc)) {\n\t\tPANIC(\"\");\n\t}\n\tsend_sig(current, SIGTRAP);\n\treturn;\n}\n\nvoid do_nmi_interrupt(unsigned int trap, struct sigcontext *sc)\n{\n\tunsigned char error;\n\n\terror = inport_b(PS2_SYSCTRL_B);\n\n\tprintk(\"NMI received: \", error);\n\tswitch(error) {\n\t\tcase 0x80:\n\t\t\tprintk(\"parity check occurred. Defective RAM chips?\\n\");\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tprintk(\"unknown error 0x%x\\n\", error);\n\t\t\tbreak;\n\t}\n\n\tif(dump_registers(trap, sc)) {\n\t\tPANIC(\"\");\n\t}\n\tsend_sig(current, SIGSEGV);\n\treturn;\n}\n\nvoid do_breakpoint(unsigned int trap, struct sigcontext *sc)\n{\n\tif(dump_registers(trap, sc)) {\n\t\tPANIC(\"\");\n\t}\n\tsend_sig(current, SIGTRAP);\n\treturn;\n}\n\nvoid do_overflow(unsigned int trap, struct sigcontext *sc)\n{\n\tif(dump_registers(trap, sc)) {\n\t\tPANIC(\"\");\n\t}\n\tsend_sig(current, SIGSEGV);\n\treturn;\n}\n\nvoid do_bound(unsigned int trap, struct sigcontext *sc)\n{\n\tif(dump_registers(trap, sc)) {\n\t\tPANIC(\"\");\n\t}\n\tsend_sig(current, SIGSEGV);\n\treturn;\n}\n\nvoid do_invalid_opcode(unsigned int trap, struct sigcontext *sc)\n{\n\tif(dump_registers(trap, sc)) {\n\t\tPANIC(\"\");\n\t}\n\tsend_sig(current, SIGILL);\n\treturn;\n}\n\nvoid do_no_math_coprocessor(unsigned int trap, struct sigcontext *sc)\n{\n\t/* floating-point emulation would go here */\n\n\tif(dump_registers(trap, sc)) {\n\t\tPANIC(\"No coprocessor/emulation found.\\n\");\n\t}\n\tsend_sig(current, SIGILL);\n\treturn;\n}\n\nvoid do_double_fault(unsigned int trap, struct sigcontext *sc)\n{\n\tif(dump_registers(trap, sc)) {\n\t\tPANIC(\"\");\n\t}\n\tsend_sig(current, SIGSEGV);\n\treturn;\n}\n\nvoid do_coprocessor_segment_overrun(unsigned int trap, struct sigcontext *sc)\n{\n\tif(dump_registers(trap, sc)) {\n\t\tPANIC(\"\");\n\t}\n\tsend_sig(current, SIGFPE);\n\treturn;\n}\n\nvoid do_invalid_tss(unsigned int trap, struct sigcontext *sc)\n{\n\tif(dump_registers(trap, sc)) {\n\t\tPANIC(\"\");\n\t}\n\tsend_sig(current, SIGSEGV);\n\treturn;\n}\n\nvoid do_segment_not_present(unsigned int trap, struct sigcontext *sc)\n{\n\tif(dump_registers(trap, sc)) {\n\t\tPANIC(\"\");\n\t}\n\tsend_sig(current, SIGBUS);\n\treturn;\n}\n\nvoid do_stack_segment_fault(unsigned int trap, struct sigcontext *sc)\n{\n\tif(dump_registers(trap, sc)) {\n\t\tPANIC(\"\");\n\t}\n\tsend_sig(current, SIGBUS);\n\treturn;\n}\n\nvoid do_general_protection(unsigned int trap, struct sigcontext *sc)\n{\n\tif(dump_registers(trap, sc)) {\n\t\tPANIC(\"\");\n\t}\n\tsend_sig(current, SIGSEGV);\n\treturn;\n}\n\n/* do_page_fault() resides in mm/fault.c */\n\nvoid do_reserved(unsigned int trap, struct sigcontext *sc)\n{\n\tif(dump_registers(trap, sc)) {\n\t\tPANIC(\"\");\n\t}\n\tsend_sig(current, SIGSEGV);\n\treturn;\n}\n\nvoid do_floating_point_error(unsigned int trap, struct sigcontext *sc)\n{\n\tif(dump_registers(trap, sc)) {\n\t\tPANIC(\"\");\n\t}\n\tsend_sig(current, SIGFPE);\n\treturn;\n}\n\nvoid do_alignment_check(unsigned int trap, struct sigcontext *sc)\n{\n\tif(dump_registers(trap, sc)) {\n\t\tPANIC(\"\");\n\t}\n\tsend_sig(current, SIGSEGV);\n\treturn;\n}\n\nvoid do_machine_check(unsigned int trap, struct sigcontext *sc)\n{\n\tif(dump_registers(trap, sc)) {\n\t\tPANIC(\"\");\n\t}\n\tsend_sig(current, SIGSEGV);\n\treturn;\n}\n\nvoid do_simd_fault(unsigned int trap, struct sigcontext *sc)\n{\n\tif(dump_registers(trap, sc)) {\n\t\tPANIC(\"\");\n\t}\n\tsend_sig(current, SIGSEGV);\n\treturn;\n}\n\nvoid trap_handler(unsigned int trap, struct sigcontext sc)\n{\n\ttraps_table[trap].handler(trap, &sc);\n\n\t/* avoids confusion with -RESTART return value */\n\tsc.err = -sc.err;\n}\n\nconst char *elf_lookup_symbol(unsigned int addr)\n{\n\tElf32_Shdr *vsymtab, *vstrtab;\n\tElf32_Sym *sym;\n\tunsigned int n;\n\n\tvsymtab = (Elf32_Shdr *)P2V((unsigned int)symtab);\n\tvstrtab = (Elf32_Shdr *)P2V((unsigned int)strtab);\n\tsym = (Elf32_Sym *)P2V(vsymtab->sh_addr);\n\tfor(n = 0; n < vsymtab->sh_size / sizeof(Elf32_Sym); n++, sym++) {\n\t\tif(ELF32_ST_TYPE(sym->st_info) != STT_FUNC) {\n\t\t\tcontinue;\n\t\t}\n\t\tif(addr >= sym->st_value && addr < (sym->st_value + sym->st_size)) {\n\t\t\treturn (const char *)P2V(vstrtab->sh_addr) + sym->st_name;\n\t\t}\n\t}\n\treturn NULL;\n}\n\nvoid stack_backtrace(void)\n{\n\tint n;\n\tunsigned int addr, *sp;\n\tconst char *str;\n\n\tprintk(\"Stack:\\n\");\n\tGET_ESP(sp);\n\t/* eip, cs, eflags, oldesp and oldss cannot be counted here */\n\tsp += (sizeof(struct sigcontext) / sizeof(unsigned int)) - 5;\n\tsp = (unsigned int *)P2V((unsigned int)sp);\n\tfor(n = 1; n <= 32; n++) {\n\t\tprintk(\" %08x\", *sp);\n\t\tsp++;\n\t\tif(!(n % 8)) {\n\t\t\tprintk(\"\\n\");\n\t\t}\n\t}\n\tprintk(\"Kernel backtrace:\\n\");\n\tGET_ESP(sp);\n\t/* eip, cs, eflags, oldesp and oldss cannot be counted here */\n\tsp += (sizeof(struct sigcontext) / sizeof(unsigned int)) - 5;\n\tsp = (unsigned int *)P2V((unsigned int)sp);\n\tfor(n = 0; n < 256; n++) {\n\t\taddr = *sp;\n\t\tstr = elf_lookup_symbol(addr);\n\t\tif(str) {\n\t\t\tprintk(\"<0x%08x> %s()\\n\", addr, str);\n\t\t}\n\t\tsp++;\n\t}\n}\n\nint dump_registers(unsigned int trap, struct sigcontext *sc)\n{\n\tunsigned int cr2;\n\tint errno;\n\n\tprintk(\"\\n\");\n\tif(trap == 14) {\t/* Page Fault */\n\t\tGET_CR2(cr2);\n\t\tprintk(\"%s at 0x%08x (%s) with error code 0x%02x%s\", traps_table[trap].name, cr2, sc->err & PFAULT_W ? \"writing\" : \"reading\", sc->err, sc->err & PAGE_USER ? \"\\n\" : \" in kernel mode.\\n\");\n\t} else {\n\t\tprintk(\"EXCEPTION: %s\", traps_table[trap].name);\n\t\tif(traps_table[trap].errcode) {\n\t\t\tprintk(\": error code 0x%08x (0b%b)\", sc->err, sc->err);\n\t\t}\n\t\tprintk(\"\\n\");\n\t}\n\n\terrno = 0;\n\tif(current) {\n\t\tprintk(\"Process '%s' with pid %d\", current->argv0, current->pid);\n\t\t/* panic if the exception has been in kernel mode */\n\t\tif(current->flags & PF_KPROC || sc->cs == KERNEL_CS) {\n\t\t\terrno = 1;\n\t\t}\n\t} else {\n\t\tprintk(\"['current' is NULL!]\");\n\t\terrno = 1;\n\t}\n\tif(sc->cs == KERNEL_CS) {\n\t\tprintk(\" in '%s()'\", elf_lookup_symbol(sc->eip));\n\t}\n\tprintk(\".\\n\");\n\n\tprintk(\" cs: 0x%04x\\teip: 0x%08x\\tefl: 0x%08x\\t ss: 0x%08x\\tesp: 0x%08x\\n\", sc->cs, sc->eip, sc->eflags, sc->oldss, sc->oldesp);\n\tprintk(\"eax: 0x%08x\\tebx: 0x%08x\\tecx: 0x%08x\\tedx: 0x%08x\\n\", sc->eax, sc->ebx, sc->ecx, sc->edx);\n\tprintk(\"esi: 0x%08x\\tedi: 0x%08x\\tesp: 0x%08x\\tebp: 0x%08x\\n\", sc->esi, sc->edi, sc->esp, sc->ebp);\n\tprintk(\" ds: 0x%04x\\t es: 0x%04x\\t fs: 0x%04x\\t gs: 0x%04x\\n\", sc->ds, sc->es, sc->fs, sc->gs);\n\n\tif(sc->cs == KERNEL_CS) {\n\t\tstack_backtrace();\n\t}\n\n\treturn errno;\n}\n"
  },
  {
    "path": "lib/Makefile",
    "content": "# fiwix/lib/Makefile\n#\n# Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n# Distributed under the terms of the Fiwix License.\n#\n\n.c.o:\n\t$(CC) $(CFLAGS) -c -o $@ $<\n\nOBJS = ctype.o string.o printk.o sysconsole.o\n\nall:\t$(OBJS)\n\nclean:\n\trm -f *.o\n\n"
  },
  {
    "path": "lib/ctype.c",
    "content": "/*\n * fiwix/lib/ctype.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/ctype.h>\n\nunsigned char _ctype[] = {\n\t0,\n\t_C,\t\t/* ^@   0x00 (NUL '\\0') */\n\t_C,\t\t/* ^A   0x01 (SOH) */\n\t_C,\t\t/* ^B   0x02 (STX) */\n\t_C,\t\t/* ^C   0x03 (ETX) */\n\t_C,\t\t/* ^D   0x04 (EOT) */\n\t_C,\t\t/* ^E   0x05 (ENQ) */\n\t_C,\t\t/* ^F   0x06 (ACK) */\n\t_C,\t\t/* ^G   0x07 (BEL '\\a') */\n\t_C,\t\t/* ^H   0x08 (BS  '\\b') */\n\t_C | _S,\t/* ^I   0x09 (HT  '\\t') */\n\t_C | _S,\t/* ^J   0x0A (LF  '\\n') */\n\t_C | _S,\t/* ^K   0x0B (VT  '\\v') */\n\t_C | _S,\t/* ^L   0x0C (FF  '\\f') */\n\t_C | _S,\t/* ^M   0x0D (CR  '\\r') */\n\t_C,\t\t/* ^N   0x0E (SO) */\n\t_C,\t\t/* ^O   0x0F (SI) */\n\t_C,\t\t/* ^P   0x10 (DLE) */\n\t_C,\t\t/* ^Q   0x11 (DC1) */\n\t_C,\t\t/* ^R   0x12 (DC2) */\n\t_C,\t\t/* ^S   0x13 (DC3) */\n\t_C,\t\t/* ^T   0x14 (DC4) */\n\t_C,\t\t/* ^U   0x15 (NAK) */\n\t_C,\t\t/* ^V   0x16 (SYN) */\n\t_C,\t\t/* ^W   0x17 (ETB) */\n\t_C,\t\t/* ^X   0x18 (CAN) */\n\t_C,\t\t/* ^Y   0x19 (EM) */\n\t_C,\t\t/* ^Z   0x1A (SUB) */\n\t_C,\t\t/* ^[   0x1B (ESC) */\n\t_C,\t\t/* ^\\   0x1C (FS) */\n\t_C,\t\t/* ^]   0x1D (GS) */\n\t_C,\t\t/* ^^   0x1E (RS) */\n\t_C,\t\t/* ^_   0x1F (US) */\n\t_S,\t\t/* ' '  0x20 */\n\t_P,\t\t/* '!'  0x21 */\n\t_P,\t\t/* '\"'  0x22 */\n\t_P,\t\t/* '#'  0x23 */\n\t_P,\t\t/* '$'  0x24 */\n\t_P,\t\t/* '%'  0x25 */\n\t_P,\t\t/* '&'  0x26 */\n\t_P,\t\t/* '''  0x27 */\n\t_P,\t\t/* '('  0x28 */\n\t_P,\t\t/* ')'  0x29 */\n\t_P,\t\t/* '*'  0x2A */\n\t_P,\t\t/* '+'  0x2B */\n\t_P,\t\t/* ','  0x2C */\n\t_P,\t\t/* '-'  0x2D */\n\t_P,\t\t/* '.'  0x2E */\n\t_P,\t\t/* '/'  0x2F */\n\t_N,\t\t/* '0'  0x30 */\n\t_N,\t\t/* '1'  0x31 */\n\t_N,\t\t/* '2'  0x32 */\n\t_N,\t\t/* '3'  0x33 */\n\t_N,\t\t/* '4'  0x34 */\n\t_N,\t\t/* '5'  0x35 */\n\t_N,\t\t/* '6'  0x36 */\n\t_N,\t\t/* '7'  0x37 */\n\t_N,\t\t/* '8'  0x38 */\n\t_N,\t\t/* '9'  0x39 */\n\t_P,\t\t/* ':'  0x3A */\n\t_P,\t\t/* ';'  0x3B */\n\t_P,\t\t/* '<'  0x3C */\n\t_P,\t\t/* '='  0x3D */\n\t_P,\t\t/* '>'  0x3E */\n\t_P,\t\t/* '?'  0x3F */\n\t_P,\t\t/* '@'  0x40 */\n\t_U | _X,\t/* 'A'  0x41 */\n\t_U | _X,\t/* 'B'  0x42 */\n\t_U | _X,\t/* 'C'  0x43 */\n\t_U | _X,\t/* 'D'  0x44 */\n\t_U | _X,\t/* 'E'  0x45 */\n\t_U | _X,\t/* 'F'  0x46 */\n\t_U,\t\t/* 'G'  0x47 */\n\t_U,\t\t/* 'H'  0x48 */\n\t_U,\t\t/* 'I'  0x49 */\n\t_U,\t\t/* 'J'  0x4A */\n\t_U,\t\t/* 'K'  0x4B */\n\t_U,\t\t/* 'L'  0x4C */\n\t_U,\t\t/* 'M'  0x4D */\n\t_U,\t\t/* 'N'  0x4E */\n\t_U,\t\t/* 'O'  0x4F */\n\t_U,\t\t/* 'P'  0x50 */\n\t_U,\t\t/* 'Q'  0x51 */\n\t_U,\t\t/* 'R'  0x52 */\n\t_U,\t\t/* 'S'  0x53 */\n\t_U,\t\t/* 'T'  0x54 */\n\t_U,\t\t/* 'U'  0x55 */\n\t_U,\t\t/* 'V'  0x56 */\n\t_U,\t\t/* 'W'  0x57 */\n\t_U,\t\t/* 'X'  0x58 */\n\t_U,\t\t/* 'Y'  0x59 */\n\t_U,\t\t/* 'Z'  0x5A */\n\t_P,\t\t/* '['  0x5B */\n\t_P,\t\t/* '\\'  0x5C */\n\t_P,\t\t/* ']'  0x5D */\n\t_P,\t\t/* '^'  0x5E */\n\t_P,\t\t/* '_'  0x5F */\n\t_P,\t\t/* '`'  0x60 */\n\t_L | _X,\t/* 'a'  0x61 */\n\t_L | _X,\t/* 'b'  0x62 */\n\t_L | _X,\t/* 'c'  0x63 */\n\t_L | _X,\t/* 'd'  0x64 */\n\t_L | _X,\t/* 'e'  0x65 */\n\t_L | _X,\t/* 'f'  0x66 */\n\t_L,\t\t/* 'g'  0x67 */\n\t_L,\t\t/* 'h'  0x68 */\n\t_L,\t\t/* 'i'  0x69 */\n\t_L,\t\t/* 'j'  0x6A */\n\t_L,\t\t/* 'k'  0x6B */\n\t_L,\t\t/* 'l'  0x6C */\n\t_L,\t\t/* 'm'  0x6D */\n\t_L,\t\t/* 'n'  0x6E */\n\t_L,\t\t/* 'o'  0x6F */\n\t_L,\t\t/* 'p'  0x70 */\n\t_L,\t\t/* 'q'  0x71 */\n\t_L,\t\t/* 'r'  0x72 */\n\t_L,\t\t/* 's'  0x73 */\n\t_L,\t\t/* 't'  0x74 */\n\t_L,\t\t/* 'u'  0x75 */\n\t_L,\t\t/* 'v'  0x76 */\n\t_L,\t\t/* 'w'  0x77 */\n\t_L,\t\t/* 'x'  0x78 */\n\t_L,\t\t/* 'y'  0x79 */\n\t_L,\t\t/* 'z'  0x7A */\n\t_P,\t\t/* '{'  0x7B */\n\t_P,\t\t/* '|'  0x7C */\n\t_P,\t\t/* '}'  0x7D */\n\t_P,\t\t/* '~'  0x7E */\n\t_C,\t\t/* DEL  0x7F */\n};\n"
  },
  {
    "path": "lib/printk.c",
    "content": "/*\n * fiwix/lib/printk.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/syslog.h>\n#include <fiwix/tty.h>\n#include <fiwix/sysconsole.h>\n#include <fiwix/syscalls.h>\n#include <fiwix/sleep.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n#include <fiwix/stdarg.h>\n#include <fiwix/mm.h>\n\n#define MAX_BUF\t\t1024\t/* printk() and sprintk() size limit */\n\nstatic char buf[MAX_BUF];\nstatic char newline = 1;\nchar log_buf[LOG_BUF_LEN];\t/* circular buffer */\nunsigned int log_read, log_write, log_size, log_new_chars;\nint console_loglevel = DEFAULT_CONSOLE_LOGLEVEL;\n\nstatic void puts(char *buffer, int msg_level)\n{\n\tstruct tty *tty;\n\tint n;\n\tchar *p, *l;\n\n#ifdef CONFIG_QEMU_DEBUGCON\n\tif(kstat.flags & KF_HAS_DEBUGCON) {\n\t\tp = buffer;\n\t\twhile(*p) {\n\t\t\tif(p == buffer && strlen(buffer) > 3) {\n\t\t\t\tif(p[0] == '<' &&\n\t\t\t\t   p[1] >= '0' && p[1] <= '7' &&\n\t\t\t\t   p[2] == '>') {\n\t\t\t\t\tp = p + 3;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(msg_level < console_loglevel) {\n\t\t\t\toutport_b(QEMU_DEBUG_PORT, *(p++));\n\t\t\t}\n\t\t}\n\t}\n#endif /* CONFIG_QEMU_DEBUGCON */\n\n\ttty = NULL;\n\tfor(n = 0; n < NR_SYSCONSOLES; n++) {\n\t\tif(!sysconsole_table[n].dev) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif(sysconsole_table[n].dev == MKDEV(VCONSOLES_MAJOR, 0)) {\n\t\t\ttty = get_tty(MKDEV(VCONSOLES_MAJOR, 0));\n\t\t} else {\n\t\t\ttty = sysconsole_table[n].tty;\n\t\t}\n\t}\n\n\tl = p = buffer;\n\twhile(*l) {\n\t\tif(tty && *p) {\n\t\t\tif(p == buffer && strlen(buffer) > 3) {\n\t\t\t\tif(p[0] == '<' &&\n\t\t\t\t   p[1] >= '0' && p[1] <= '7' &&\n\t\t\t\t   p[2] == '>') {\n\t\t\t\t\tp = p + 3;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(msg_level < console_loglevel) {\n\t\t\t\tcharq_putchar(&tty->write_q, *p);\n\t\t\t}\n\t\t\ttty->output(tty);\n\t\t\tp++;\n\t\t}\n\t\tlog_write &= LOG_BUF_LEN - 1;\n\t\tlog_buf[log_write++] = *l;\n\t\tif(log_size < LOG_BUF_LEN) {\n\t\t\tlog_size++;\n\t\t} else {\n\t\t\tlog_read++;\n\t\t\tlog_read &= LOG_BUF_LEN - 1;\n\t\t}\n\t\tlog_new_chars = log_new_chars < LOG_BUF_LEN ? log_new_chars + 1 : log_new_chars;\n\t\tl++;\n\t}\n\twakeup(&sys_syslog);\n\twakeup(&do_select);\n}\n\n/*\n * format identifiers\n * --------------------------------------------------------\n *\t%d\tdecimal conversion\n *\t%u\tunsigned decimal conversion\n *\t%x\thexadecimal conversion (lower case)\n *\t%X\thexadecimal conversion (upper case)\n *\t%b\tbinary conversion\n *\t%o\toctal conversion\n *\t%c\tcharacter\n *\t%s\tstring\n *\n * length modifiers (e.g: %ld or %lu)\n * --------------------------------------------------------\n *  \tl\tlong long int arguments\n *\n * flags (e.g: %05d or %-6s)\n * --------------------------------------------------------\n *\t0\tresult is padded with zeros (e.g.: '%06d')\n *\t\t(maximum value is 32)\n *\tblank\tresult is padded with spaces (e.g.: '% 6d')\n *\t\t(maximum value is 32)\n *\t-\tthe numeric result is left-justified\n *\t\t(default is right-justified)\n *\t\tthe string is right-justified\n *\t\t(default is left-justified)\n */\nstatic int do_printk(char *buffer, const char *format, va_list args)\n{\n\tchar sw_neg, in_identifier, n_pad, lf, sw_l;\n\tchar str[32 + 1], ch_pad, basecase, c;\n\tchar nullstr[7] = { '<', 'N', 'U', 'L', 'L', '>', '\\0' };\n\tchar *ptr_s, *p;\n\tint num, count, level_found;\n\tchar simplechar;\n\tunsigned int unum, digit;\n\tlong long int lnum;\n\tunsigned long long int lunum;\n\tstatic char msg_level = -1;\n\n\tsw_neg = in_identifier = n_pad = lf = sw_l = 0;\n\tcount = 0;\n\tbasecase = 'A';\n\tch_pad = ' ';\n\tp = NULL;\n\n\t/*\n\t * Checks the log level (e.g: <4>) on every new line and adds the\n\t * level mark (if needed), but only if the caller function was printk().\n\t */\n\tif(newline == 1) {\n\t\tif(msg_level < 0 && buffer == buf) {\n\t\t\tlevel_found = 0;\n\t\t\tif(strlen(format) > 3) {\n\t\t\t\tif(format[0] == '<' &&\n\t\t\t\t   format[1] >= '0' && format[1] <= '7' &&\n\t\t\t\t   format[2] == '>') {\n\t\t\t\t\tmsg_level = format[1] - '0';\n\t\t\t\t\tlevel_found = 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(!level_found) {\n\t\t\t\tmsg_level = DEFAULT_MESSAGE_LOGLEVEL;\n\t\t\t\t*(buffer++) = '<';\n\t\t\t\t*(buffer++) = msg_level + '0';\n\t\t\t\t*(buffer++) = '>';\n\t\t\t}\n\t\t}\n\t\tnewline = 0;\n\t}\n\n\t/* assumes buffer has a maximum size of MAX_BUF */\n\twhile((c = *(format++)) && count < MAX_BUF) {\n\t\tif(!in_identifier) {\n\t\t\tmemset_b(str, 0, sizeof(str));\n\t\t}\n\t\tif((c != '%') && !in_identifier) {\n\t\t\tif(c == '\\n') {\n\t\t\t\tnewline = 1;\n\t\t\t\tmsg_level = -1;\n\t\t\t}\n\t\t\t*(buffer++) = c;\n\t\t} else {\n\t\t\tin_identifier = 1;\n\t\t\tswitch(c = *(format)) {\n\t\t\t\tcase 'd':\n#ifdef CONFIG_PRINTK64\n\t\t\t\t\tif(sw_l) {\n\t\t\t\t\t\tlnum = va_arg(args, long long int);\n\t\t\t\t\t\tif(lnum < 0) {\n\t\t\t\t\t\t\tlnum *= -1;\n\t\t\t\t\t\t\tsw_neg = 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tptr_s = str;\n\t\t\t\t\t\tdo {\n\t\t\t\t\t\t\t*(ptr_s++) = '0' + (lnum % 10);\n\t\t\t\t\t\t} while(lnum /= 10);\n\t\t\t\t\t} else {\n#endif /* CONFIG_PRINTK64 */\n\t\t\t\t\t\tnum = va_arg(args, int);\n\t\t\t\t\t\tif(num < 0) {\n\t\t\t\t\t\t\tnum *= -1;\n\t\t\t\t\t\t\tsw_neg = 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tptr_s = str;\n\t\t\t\t\t\tdo {\n\t\t\t\t\t\t\t*(ptr_s++) = '0' + (num % 10);\n\t\t\t\t\t\t} while(num /= 10);\n#ifdef CONFIG_PRINTK64\n\t\t\t\t\t}\n#endif /* CONFIG_PRINTK64 */\n\n\t\t\t\t\tif(lf) {\n\t\t\t\t\t\tp = ptr_s;\n\t\t\t\t\t} else {\n\t\t\t\t\t\twhile(*ptr_s) {\n\t\t\t\t\t\t\tptr_s++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif(sw_neg) {\n\t\t\t\t\t\tsw_neg = 0;\n\t\t\t\t\t\t*(ptr_s++) = '-';\n\t\t\t\t\t}\n\t\t\t\t\tdo {\n\t\t\t\t\t\t*(buffer++) = *(--ptr_s);\n\t\t\t\t\t\tcount++;\n\t\t\t\t\t} while(ptr_s != str && count < MAX_BUF);\n\t\t\t\t\tif(lf) {\n\t\t\t\t\t\twhile(*p && count < MAX_BUF) {\n\t\t\t\t\t\t\t*(buffer++) = *(p++);\n\t\t\t\t\t\t\tcount++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tformat++;\n\t\t\t\t\tch_pad = ' ';\n\t\t\t\t\tn_pad = 0;\n\t\t\t\t\tin_identifier = 0;\n\t\t\t\t\tlf = 0;\n\t\t\t\t\tsw_l = 0;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'u':\n#ifdef CONFIG_PRINTK64\n\t\t\t\t\tif(sw_l) {\n\t\t\t\t\t\tlunum = va_arg(args, unsigned long long int);\n\t\t\t\t\t\tptr_s = str;\n\t\t\t\t\t\tdo {\n\t\t\t\t\t\t\t*(ptr_s++) = '0' + (lunum % 10);\n\t\t\t\t\t\t} while(lunum /= 10);\n\t\t\t\t\t} else {\n#endif /* CONFIG_PRINTK64 */\n\t\t\t\t\t\tunum = va_arg(args, unsigned int);\n\t\t\t\t\t\tptr_s = str;\n\t\t\t\t\t\tdo {\n\t\t\t\t\t\t\t*(ptr_s++) = '0' + (unum % 10);\n\t\t\t\t\t\t} while(unum /= 10);\n#ifdef CONFIG_PRINTK64\n\t\t\t\t\t}\n#endif /* CONFIG_PRINTK64 */\n\n\t\t\t\t\tif(lf) {\n\t\t\t\t\t\tp = ptr_s;\n\t\t\t\t\t} else {\n\t\t\t\t\t\twhile(*ptr_s) {\n\t\t\t\t\t\t\tptr_s++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdo {\n\t\t\t\t\t\t*(buffer++) = *(--ptr_s);\n\t\t\t\t\t\tcount++;\n\t\t\t\t\t} while(ptr_s != str && count < MAX_BUF);\n\t\t\t\t\tif(lf) {\n\t\t\t\t\t\twhile(*p && count < MAX_BUF) {\n\t\t\t\t\t\t\t*(buffer++) = *(p++);\n\t\t\t\t\t\t\tcount++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tformat++;\n\t\t\t\t\tch_pad = ' ';\n\t\t\t\t\tn_pad = 0;\n\t\t\t\t\tin_identifier = 0;\n\t\t\t\t\tlf = 0;\n\t\t\t\t\tsw_l = 0;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'x':\n\t\t\t\t\tbasecase = 'a';\n\t\t\t\tcase 'X':\n\t\t\t\t\tunum = va_arg(args, unsigned int);\n\t\t\t\t\tptr_s = str;\n\t\t\t\t\tdo {\n\t\t\t\t\t\t*(ptr_s++) = (digit = (unum & 0x0F)) > 9 ? basecase + digit - 10 : '0' + digit;\n\t\t\t\t\t} while(unum /= 16);\n\t\t\t\t\tif(lf) {\n\t\t\t\t\t\tp = ptr_s;\n\t\t\t\t\t} else {\n\t\t\t\t\t\twhile(*ptr_s) {\n\t\t\t\t\t\t\tptr_s++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdo {\n\t\t\t\t\t\t*(buffer++) = *(--ptr_s);\n\t\t\t\t\t\tcount++;\n\t\t\t\t\t} while(ptr_s != str && count < MAX_BUF);\n\t\t\t\t\tif(lf) {\n\t\t\t\t\t\twhile(*p && count < MAX_BUF) {\n\t\t\t\t\t\t\t*(buffer++) = *(p++);\n\t\t\t\t\t\t\tcount++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tformat++;\n\t\t\t\t\tch_pad = ' ';\n\t\t\t\t\tn_pad = 0;\n\t\t\t\t\tin_identifier = 0;\n\t\t\t\t\tlf = 0;\n\t\t\t\t\tsw_l = 0;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'b':\n\t\t\t\t\tnum = va_arg(args, unsigned int);\n\t\t\t\t\tif(num < 0) {\n\t\t\t\t\t\tnum *= -1;\n\t\t\t\t\t}\n\t\t\t\t\tptr_s = str;\n\t\t\t\t\tdo {\n\t\t\t\t\t\t*(ptr_s++) = '0' + (num % 2);\n\t\t\t\t\t} while(num /= 2);\n\t\t\t\t\tif(lf) {\n\t\t\t\t\t\tp = ptr_s;\n\t\t\t\t\t} else {\n\t\t\t\t\t\twhile(*ptr_s) {\n\t\t\t\t\t\t\tptr_s++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdo {\n\t\t\t\t\t\t*(buffer++) = *(--ptr_s);\n\t\t\t\t\t\tcount++;\n\t\t\t\t\t} while(ptr_s != str && count < MAX_BUF);\n\t\t\t\t\tif(lf) {\n\t\t\t\t\t\twhile(*p && count < MAX_BUF) {\n\t\t\t\t\t\t\t*(buffer++) = *(p++);\n\t\t\t\t\t\t\tcount++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tformat++;\n\t\t\t\t\tch_pad = ' ';\n\t\t\t\t\tn_pad = 0;\n\t\t\t\t\tin_identifier = 0;\n\t\t\t\t\tlf = 0;\n\t\t\t\t\tsw_l = 0;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'o':\n\t\t\t\t\tnum = va_arg(args, unsigned int);\n\t\t\t\t\tif(num < 0) {\n\t\t\t\t\t\tnum *= -1;\n\t\t\t\t\t}\n\t\t\t\t\tptr_s = str;\n\t\t\t\t\tdo {\n\t\t\t\t\t\t*(ptr_s++) = '0' + (num % 8);\n\t\t\t\t\t} while(num /= 8);\n\t\t\t\t\tif(lf) {\n\t\t\t\t\t\tp = ptr_s;\n\t\t\t\t\t} else {\n\t\t\t\t\t\twhile(*ptr_s) {\n\t\t\t\t\t\t\tptr_s++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdo {\n\t\t\t\t\t\t*(buffer++) = *(--ptr_s);\n\t\t\t\t\t\tcount++;\n\t\t\t\t\t} while(ptr_s != str && count < MAX_BUF);\n\t\t\t\t\tif(lf) {\n\t\t\t\t\t\twhile(*p && count < MAX_BUF) {\n\t\t\t\t\t\t\t*(buffer++) = *(p++);\n\t\t\t\t\t\t\tcount++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tformat++;\n\t\t\t\t\tch_pad = ' ';\n\t\t\t\t\tn_pad = 0;\n\t\t\t\t\tin_identifier = 0;\n\t\t\t\t\tlf = 0;\n\t\t\t\t\tsw_l = 0;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'c':\n\t\t\t\t\tsimplechar = va_arg(args, int);\n\t\t\t\t\t*(buffer++) = simplechar;\n\t\t\t\t\tformat++;\n\t\t\t\t\tin_identifier = 0;\n\t\t\t\t\tlf = 0;\n\t\t\t\t\tsw_l = 0;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 's':\n\t\t\t\t\tnum = 0;\n\t\t\t\t\tptr_s = va_arg(args, char *);\n\t\t\t\t\tif(n_pad) {\n\t\t\t\t\t\tnum = n_pad - strlen(ptr_s);\n\t\t\t\t\t\tif(num < 0) {\n\t\t\t\t\t\t\tnum *= -1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t/* if it's a NULL then show \"<NULL>\" */\n\t\t\t\t\tif(ptr_s == NULL) {\n\t\t\t\t\t  \tptr_s = (char *)nullstr;\n\t\t\t\t\t}\n\t\t\t\t\tif(lf) {\n\t\t\t\t\t\twhile(num-- > 0 && count < MAX_BUF) {\n\t\t\t\t\t\t\t*(buffer++) = ' ';\n\t\t\t\t\t\t\tcount++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\twhile((c = *(ptr_s++)) && count < MAX_BUF) {\n\t\t\t\t\t\t*(buffer++) = c;\n\t\t\t\t\t\tcount++;\n\t\t\t\t\t}\n\t\t\t\t\twhile(num-- > 0 && count < MAX_BUF) {\n\t\t\t\t\t\t*(buffer++) = ' ';\n\t\t\t\t\t\tcount++;\n\t\t\t\t\t}\n\t\t\t\t\tformat++;\n\t\t\t\t\tn_pad = 0;\n\t\t\t\t\tin_identifier = 0;\n\t\t\t\t\tlf = 0;\n\t\t\t\t\tsw_l = 0;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase ' ':\n\t\t\t\t\tch_pad = ' ';\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '0':\n\t\t\t\t\tif(!n_pad) {\n\t\t\t\t\t\tch_pad = '0';\n\t\t\t\t\t}\n\t\t\t\tcase '1':\n\t\t\t\tcase '2':\n\t\t\t\tcase '3':\n\t\t\t\tcase '4':\n\t\t\t\tcase '5':\n\t\t\t\tcase '6':\n\t\t\t\tcase '7':\n\t\t\t\tcase '8':\n\t\t\t\tcase '9':\n\t\t\t\t\tn_pad = !n_pad ? c - '0': ((n_pad * 10) + (c - '0'));\n\t\t\t\t\tn_pad = n_pad > 32 ? 32 : n_pad;\n\t\t\t\t\tfor(unum = 0; unum < n_pad; unum++) {\n\t\t\t\t\t\tstr[unum] = ch_pad;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'l':\n\t\t\t\t\tsw_l = 1;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '-':\n\t\t\t\t\tlf = 1;\n\t\t\t\t\tbreak;\n\t\t\t\tcase '%':\n\t\t\t\t\t*(buffer++) = c;\n\t\t\t\t\tformat++;\n\t\t\t\t\tin_identifier = 0;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tcount++;\n\t}\n\t*buffer = 0;\n\treturn msg_level;\n}\n\nvoid flush_log_buf(struct tty *tty)\n{\n\tint n;\n\tstatic char msg_level = -1;\n\n\tn = log_read;\n\twhile(n < log_size) {\n\t\tif(msg_level < 0) {\n\t\t\tmsg_level = log_buf[n + 1] - '0';\n\t\t\tn = n + 3;\n\t\t}\n\t\tif(msg_level < console_loglevel) {\n\t\t\tif(charq_putchar(&tty->write_q, log_buf[n]) < 0) {\n\t\t\t\ttty->output(tty);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\tif(log_buf[n] == '\\n') {\n\t\t\tmsg_level = -1;\n\t\t}\n\t\tn++;\n\t}\n\ttty->output(tty);\n}\n\nvoid printk(const char *format, ...)\n{\n\tva_list args;\n\tint msg_level;\n\n\tva_start(args, format);\n\tmsg_level = do_printk(buf, format, args);\n\tputs(buf, msg_level);\n\tva_end(args);\n}\n\nint sprintk(char *buffer, const char *format, ...)\n{\n\tva_list args;\n\n\tva_start(args, format);\n\tdo_printk(buffer, format, args);\n\tnewline = 1;\n\tva_end(args);\n\treturn strlen(buffer);\n}\n\nint snprintk(char *str, unsigned int size, const char *format, ...)\n{\n        va_list args;\n        char *buffer;\n\n\tif(size > MAX_BUF) {\n\t\tprintk(\"%(): size %d too big, truncating to MAX_BUF (%d bytes).\", __FUNCTION__, size, MAX_BUF - 1);\n\t\tsize = MAX_BUF - 1;\n\t}\n        if(!(buffer = (char *)kmalloc(MAX_BUF))) {\n                return 0;\n        }\n        va_start(args, format);\n        sprintk(buffer, format, args);\n        va_end(args);\n        strncpy(str, buffer, size);\n        str[size - 1] = '\\0';\n        kfree((unsigned int)buffer);\n\treturn strlen(str);\n}\n"
  },
  {
    "path": "lib/string.c",
    "content": "/*\n * fiwix/lib/string.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/types.h>\n#include <fiwix/tty.h>\n#include <fiwix/mm.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n#include <fiwix/ctype.h>\n\n/* convert from big-endian to little-endian (word swap) */\nvoid swap_asc_word(char *str, int len)\n{\n\tint n, n2;\n\tshort int *ptr;\n\tchar *buf;\n\n\tif(!(buf = (void *)kmalloc(PAGE_SIZE))) {\n\t\treturn;\n\t}\n\n\tptr = (short int *)str;\n\n\tfor(n = 0, n2 = 0; n < len; n++) {\n\t\tbuf[n2++] = *ptr >> 8;\n\t\tbuf[n2++] = *ptr & 0xFF;\n\t\tptr++;\n\t}\n\tfor(n = len - 1; n > 0; n--) {\n\t\tif(buf[n] == '\\0' || buf[n] == ' ') {\n\t\t\tbuf[n] = 0;\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t}\n\tmemcpy_b(str, buf, len);\n\tkfree((unsigned int)buf);\n}\n\nint strcmp(const char *str1, const char *str2)\n{\n\twhile(*str1) {\n\t\tif(*str1 != *str2) {\n\t\t\treturn 1;\n\t\t}\n\t\tstr1++;\n\t\tstr2++;\n\t}\n\tif(!(*str2)) {\n\t\treturn 0;\n\t}\n\treturn 1;\n}\n\nint strncmp(const char *str1, const char *str2, __ssize_t n)\n{\n\twhile(n > 0 && *str1) {\n\t\tif(*str1 != *str2) {\n\t\t\treturn 1;\n\t\t}\n\t\tstr1++;\n\t\tstr2++;\n\t\tn--;\n\t}\n\treturn 0;\n}\n\nchar *strcpy(char *dest, const char *src)\n{\n\tif(!dest || !src) {\n\t\treturn NULL;\n\t}\n\n\twhile(*src) {\n\t\t*dest = *src;\n\t\tdest++;\n\t\tsrc++;\n\t}\n\t*dest = 0;\t\t/* NULL-terminated */\n\treturn dest;\n}\n\nvoid strncpy(char *dest, const char *src, int len)\n{\n\tif(!dest || !src) {\n\t\treturn;\n\t}\n\n\twhile((*src) && len) {\n\t\t*dest = *src;\n\t\tdest++;\n\t\tsrc++;\n\t\tlen--;\n\t}\n\t*dest = 0;\t\t/* NULL-terminated */\n}\n\nchar *strcat(char *dest, const char *src)\n{\n\tchar *orig;\n\n\torig = dest;\n\twhile(*dest) {\n\t\tdest++;\n\t}\n\twhile(*src) {\n\t\t*dest = *src;\n\t\tdest++;\n\t\tsrc++;\n\t}\n\t*dest = 0;\t\t/* NULL-terminated */\n\treturn orig;\n}\n\nchar *strncat(char *dest, const char *src, __ssize_t len)\n{\n\tchar *orig;\n\n\torig = dest;\n\twhile(*dest) {\n\t\tdest++;\n\t}\n\twhile(*src && len) {\n\t\t*dest = *src;\n\t\tdest++;\n\t\tsrc++;\n\t\tlen--;\n\t}\n\t*dest = 0;\t\t/* NULL-terminated */\n\treturn orig;\n}\n\nint strlen(const char *str)\n{\n\tint n;\n\n\tn = 0;\n\twhile(str && *str) {\n\t\tn++;\n\t\tstr++;\n\t}\n\treturn n;\n}\n\nchar *strchr(const char *str, int c)\n{\n\twhile(*str) {\n\t\tif(*str == (char)c) {\n\t\t\tbreak;\n\t\t}\n\t\tstr++;\n\t}\n\treturn (char *)str;\n}\n\nchar *strrchr(const char *str, int c)\n{\n\tint len;\n\n\tif((len = strlen(str))) {\n\t\twhile(--len) {\n\t\t\tif(str[len] == (char)c) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\treturn (char *)(str + len);\n}\n\nint strtol(const char *nptr, char **endptr, int base)\n{\n\tint neg, value;\n\n\tvalue = neg = 0;\n\twhile(ISSPACE((int)*nptr)) {\n\t\tnptr++;\n\t}\n\tif(*nptr == '-') {\n\t\tneg = 1;\n\t\tnptr++;\n\t} else if(*nptr == '+') {\n\t\tnptr++;\n\t}\n\tif(!base) {\n\t\tif(*nptr == '0') {\n\t\t\tbase = 8;\n\t\t\tnptr++;\n\t\t\tif(*nptr == 'x' || *nptr == 'X') {\n\t\t\t\tbase = 16;\n\t\t\t\tnptr++;\n\t\t\t}\n\t\t} else {\n\t\t\tbase = 10;\n\t\t}\n\t}\n\twhile(*nptr) {\n\t\tif(ISXDIGIT((int)*nptr)) {\n\t\t\tif(ISDIGIT((int)*nptr)) {\n\t\t\t\tif((*nptr - '0') < base) {\n\t\t\t\t\tvalue = (value * base) + (*nptr - '0');\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tvalue = (value * base) + (TOUPPER((*nptr - 'A') + 10));\n\t\t\t}\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t\tnptr++;\n\t}\n\tif(endptr) {\n\t\t*endptr = (char *)nptr;\n\t}\n\treturn neg ? -value : value;\n}\n\nchar *get_basename(const char *path)\n{\n\tchar *basename;\n\tchar c;\n\n\tbasename = NULL;\n\n\twhile(path) {\n\t\twhile(*path == '/') {\n\t\t\tpath++;\n\t\t}\n\t\tif(*path != '\\0') {\n\t\t\tbasename = (char *)path;\n\t\t}\n\t\twhile((c = *(path++)) && (c != '/'));\n\t\tif(!c) {\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn basename;\n}\n\nchar *remove_trailing_slash(char *path)\n{\n\tchar *p;\n\n\tp = path + (strlen(path) - 1);\n\twhile(p > path && *p == '/') {\n\t\t*p = 0;\n\t\tp--;\n\t}\n\treturn path;\n}\n\nint is_dir(const char *path)\n{\n\twhile(*(path + 1)) {\n\t\tpath++;\n\t}\n\tif(*path == '/') {\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n\nint atoi(const char *str)\n{\n\treturn strtol(str, (char **)NULL, 10);\n}\n\nvoid memcpy_b(void *dest, const void *src, unsigned int count)\n{\n\tunsigned char *d;\n\tconst unsigned char *s;\n\n\td = (unsigned char *)dest;\n\ts = (const unsigned char *)src;\n\twhile(count--) {\n\t\t*d = *s;\n\t\td++;\n\t\ts++;\n\t}\n}\n\nvoid memcpy_w(void *dest, const void *src, unsigned int count)\n{\n\tunsigned short int *d;\n\tconst unsigned short int *s;\n\n\td = (unsigned short int *)dest;\n\ts = (const unsigned short int *)src;\n\twhile(count--) {\n\t\t*d = *s;\n\t\td++;\n\t\ts++;\n\t}\n}\n\nvoid memcpy_l(void *dest, const void *src, unsigned int count)\n{\n\tunsigned int *d;\n\tconst unsigned int *s;\n\n\td = (unsigned int *)dest;\n\ts = (const unsigned int *)src;\n\twhile(count--) {\n\t\t*d = *s;\n\t\td++;\n\t\ts++;\n\t}\n}\n\nvoid memset_b(void *dest, unsigned char value, unsigned int count)\n{\n\tunsigned char *d;\n\n\td = (unsigned char *)dest;\n\twhile(count--) {\n\t\t*d = value;\n\t\td++;\n\t}\n}\n\nvoid memset_w(void *dest, unsigned short int value, unsigned int count)\n{\n\tunsigned short int *d;\n\n\td = (unsigned short int *)dest;\n\twhile(count--) {\n\t\t*d = value;\n\t\td++;\n\t}\n}\n\nvoid memset_l(void *dest, unsigned int value, unsigned int count)\n{\n\tunsigned int *d;\n\n\td = (unsigned int *)dest;\n\twhile(count--) {\n\t\t*d = value;\n\t\td++;\n\t}\n}\n\nint memcmp(const void *str1, const void *str2, unsigned int count)\n{\n\tconst unsigned char *s1;\n\tconst unsigned char *s2;\n\n\ts1 = (const unsigned char *)str1;\n\ts2 = (const unsigned char *)str2;\n\twhile(count--) {\n\t\tif(*s1 != *s2) {\n\t\t\treturn s1 < s2 ? -1 : 1;\n\t\t}\n\t\ts1++;\n\t\ts2++;\n\t}\n\treturn 0;\n}\n\nvoid *memmove(void *dest, void const *src, int count)\n{\n\tif (dest < src) {\n\t\tmemcpy_b (dest, src, count);\n\t\treturn dest;\n\t} else {\n\t\tchar *p = dest;\n\t\tchar const *q = src;\n\t\tcount = count - 1;\n\t\twhile (count >= 0) {\n\t\t\tp[count] = q[count];\n\t\t\tcount = count - 1;\n\t\t}\n\t}\n\treturn dest;\n}\n"
  },
  {
    "path": "lib/sysconsole.c",
    "content": "/*\n * fiwix/lib/sysconsole.c\n *\n * Copyright 2024, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/sysconsole.h>\n#include <fiwix/tty.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n#include <fiwix/syslog.h>\n\nstruct sysconsole sysconsole_table[NR_SYSCONSOLES];\n\nint add_sysconsoledev(__dev_t dev)\n{\n\tint n;\n\n\tfor(n = 0; n < NR_SYSCONSOLES; n++) {\n\t\tif(!sysconsole_table[n].dev) {\n\t\t\tsysconsole_table[n].dev = dev;\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\treturn 0;\n}\n\nvoid register_console(struct tty *tty)\n{\n\tint n;\n\n\tfor(n = 0; n < NR_SYSCONSOLES; n++) {\n\t\tif(sysconsole_table[n].dev == tty->dev) {\n\t\t\tsysconsole_table[n].tty = tty;\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\nvoid sysconsole_init(void)\n{\n\tmemset_b(sysconsole_table, 0, sizeof(sysconsole_table));\n\tmemset_b(log_buf, 0, sizeof(log_buf));\n\tlog_read = log_write = log_size = log_new_chars = 0;\n}\n"
  },
  {
    "path": "mm/Makefile",
    "content": "# fiwix/mm/Makefile\n#\n# Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n# Distributed under the terms of the Fiwix License.\n#\n\n.c.o:\n\t$(CC) $(CFLAGS) -c -o $@ $<\n\nOBJS = bios_map.o buddy_low.o memory.o page.o alloc.o fault.o mmap.o swapper.o\n\nall:\t$(OBJS)\n\nclean:\n\trm -f *.o\n\n"
  },
  {
    "path": "mm/alloc.c",
    "content": "/*\n * fiwix/mm/alloc.c\n *\n * Copyright 2018, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/mm.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n/*\n * The kmalloc() function acts like a front-end for the two\n * memory allocators currently supported:\n *\n * - buddy_low() for requests up to 2048KB.\n * - get_free_page() rest of requests up to PAGE_SIZE.\n */\nunsigned int kmalloc(__size_t size)\n{\n\tstruct page *pg;\n\tint max_size;\n\tunsigned int addr;\n\n\t/* check if size can be managed by buddy_low */\n\tmax_size = bl_blocksize[BUDDY_MAX_LEVEL - 1];\n\tif(size + sizeof(struct bl_head) <= max_size) {\n\t\tsize += sizeof(struct bl_head);\n\t\treturn bl_malloc(size);\n\t}\n\n\t/* FIXME: pending to implement buddy_high */\n\tif(size > PAGE_SIZE) {\n\t\tprintk(\"WARNING: %s(): size (%d) is bigger than PAGE_SIZE!\\n\", __FUNCTION__, size);\n\t\treturn 0;\n\t}\n\n\tif((pg = get_free_page())) {\n\t\taddr = pg->page << PAGE_SHIFT;\n\t\treturn P2V(addr);\n\t}\n\n\t/* out of memory! */\n\treturn 0;\n}\n\nvoid kfree(unsigned int addr)\n{\n\tstruct page *pg;\n\tunsigned paddr;\n\n\tpaddr = V2P(addr);\n\tpg = &page_table[paddr >> PAGE_SHIFT];\n\n\tif(pg->flags & PAGE_BUDDYLOW) {\n\t\tbl_free(addr);\n\t} else {\n\t\trelease_page(pg);\n\t}\n}\n"
  },
  {
    "path": "mm/bios_map.c",
    "content": "/*\n * fiwix/mm/bios_map.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/kparms.h>\n#include <fiwix/mm.h>\n#include <fiwix/bios.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstruct bios_mem_map bios_mem_map[NR_BIOS_MM_ENT];\nstruct bios_mem_map kernel_mem_map[NR_BIOS_MM_ENT];\n\nstatic char *bios_mem_type[] = {\n\tNULL,\n\t\"available\",\n\t\"reserved\",\n\t\"ACPI Reclaim\",\n\t\"ACPI NVS\",\n\t\"unusable\",\n\t\"disabled\"\n};\n\nstatic void bios_map_add(unsigned int from, unsigned int to, int from_type, int to_type)\n{\n\tint n;\n\n\tfor(n = 0; n < NR_BIOS_MM_ENT; n++) {\n\t\tif(!kernel_mem_map[n].type) {\n\t\t\tif(from_type == to_type) {\n\t\t\t\tprintk(\"memory    0x%08x%08x-0x%08x%08x %s\\n\",\n\t\t\t\t\t0, from,\n\t\t\t\t\t0, to - 1,\n\t\t\t\t\tbios_mem_type[to_type]\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tprintk(\"memory    0x%08x%08x-0x%08x%08x %s -> %s\\n\",\n\t\t\t\t\t0, from,\n\t\t\t\t\t0, to - 1,\n\t\t\t\t\tbios_mem_type[from_type],\n\t\t\t\t\tbios_mem_type[to_type]\n\t\t\t\t);\n\t\t\t}\n\t\t\tkernel_mem_map[n].from = from;\n\t\t\tkernel_mem_map[n].to = to;\n\t\t\tkernel_mem_map[n].from_hi = 0;\n\t\t\tkernel_mem_map[n].to_hi = 0;\n\t\t\tkernel_mem_map[n].type = to_type;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif(n >= NR_BIOS_MM_ENT) {\n\t\tprintk(\"WARNING: %s(): no more entries in kernel_mem_map[].\\n\", __FUNCTION__);\n\t\treturn;\n\t}\n}\n\n/* check if an specific address is available in the BIOS memory map */\nint is_addr_in_bios_map(unsigned int addr)\n{\n\tint n, retval;\n\tstruct bios_mem_map *bmm;\n\n\tretval = 0;\n\tbmm = &kernel_mem_map[0];\n\n\tfor(n = 0; n < NR_BIOS_MM_ENT; n++, bmm++) {\n\t\tif(bmm->to && bmm->type == MULTIBOOT_MEMORY_AVAILABLE && !bmm->from_hi && !bmm->to_hi) {\n\t\t\tif(addr >= bmm->from && addr < (bmm->to & PAGE_MASK)) {\n\t\t\t\tretval = 1;\n\t\t\t}\n\t\t}\n\t}\n\n\t/* this second pass is necessary because the array is not sorted */\n\tbmm = &kernel_mem_map[0];\n\tfor(n = 0; n < NR_BIOS_MM_ENT; n++, bmm++) {\n\t\tif(bmm->to && bmm->type == MULTIBOOT_MEMORY_RESERVED && !bmm->from_hi && !bmm->to_hi) {\n\t\t\tif(addr >= bmm->from && addr < (bmm->to & PAGE_MASK)) {\n\t\t\t\tretval = 0;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn retval;\n}\n\nvoid bios_map_reserve(unsigned int from, unsigned int to)\n{\n\tif(is_addr_in_bios_map(from)) {\n\t\tbios_map_add(from, to, MULTIBOOT_MEMORY_AVAILABLE, MULTIBOOT_MEMORY_RESERVED);\n\t\tif (page_table_size) {\n\t\t\treserve_pages(from, to);\n\t\t}\n\t}\n}\n\nvoid bios_map_init(struct multiboot_mmap_entry *bmmap_addr, unsigned int bmmap_length)\n{\n\tstruct multiboot_mmap_entry *bmmap;\n\tunsigned int from_high, from_low, to_high, to_low;\n\tunsigned long long to, to_orig;\n\tint n, type;\n\n\tbmmap = bmmap_addr;\n\tkstat.physical_pages = 0;\n\n\tif(bmmap) {\n\t\tn = 0;\n\n\t\twhile((unsigned int)bmmap < (unsigned int)bmmap_addr + bmmap_length) {\n\t\t\tfrom_high = (unsigned int)(bmmap->addr >> 32);\n\t\t\tfrom_low = (unsigned int)(bmmap->addr & 0xFFFFFFFF);\n\t\t\tto_orig = (bmmap->addr + bmmap->len); /* preserve original end address */\n\t\t\tto = (bmmap->addr + bmmap->len) - 1;\n\t\t\tto_high = (unsigned int)(to >> 32);\n\t\t\tto_low = (unsigned int)(to & 0xFFFFFFFF);\n\t\t\ttype = (int)bmmap->type;\n\t\t\tprintk(\"%s    0x%08x%08x-0x%08x%08x %s\\n\",\n\t\t\t\tn ? \"      \" : \"memory\",\n\t\t\t\tfrom_high,\n\t\t\t\tfrom_low,\n\t\t\t\tto_high,\n\t\t\t\tto_low,\n\t\t\t\tbios_mem_type[type]\n\t\t\t);\n\t\t\t/* restore the original end address */\n\t\t\tto_high = (unsigned int)(to_orig >> 32);\n\t\t\tto_low = (unsigned int)(to_orig & 0xFFFFFFFF);\n\t\t\tif(n < NR_BIOS_MM_ENT && bmmap->len) {\n\t\t\t\tbios_mem_map[n].from = from_low;\n\t\t\t\tbios_mem_map[n].from_hi = from_high;\n\t\t\t\tbios_mem_map[n].to = to_low;\n\t\t\t\tbios_mem_map[n].to_hi = to_high;\n\t\t\t\tbios_mem_map[n].type = type;\n\t\t\t\t/* only memory addresses below 4GB are counted */\n\t\t\t\tif(!from_high && !to_high) {\n\t\t\t\t\tif(type == MULTIBOOT_MEMORY_AVAILABLE) {\n\t\t\t\t\t\tfrom_low &= PAGE_MASK;\n\t\t\t\t\t\tto_low &= PAGE_MASK;\n\n\t\t\t\t\t\t/* the first MB is not counted here */\n\t\t\t\t\t\tif(from_low >= 0x100000) {\n\t\t\t\t\t\t\tkstat.physical_pages += (to_low - from_low) / PAGE_SIZE;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tn++;\n\t\t\t}\n\t\t\tbmmap = (struct multiboot_mmap_entry *)((unsigned int)bmmap + bmmap->size + sizeof(bmmap->size));\n\t\t}\n\t\tkstat.physical_pages += (1024 >> 2);\t/* add the first MB as a whole */\n\t\tif(kstat.physical_pages > (GDT_BASE >> PAGE_SHIFT)) {\n\t\t\tprintk(\"WARNING: detected a total of %dMB of available memory below 4GB.\\n\", (kstat.physical_pages << 2) / 1024);\n\t\t}\n\t} else {\n\t\tprintk(\"WARNING: your BIOS has not provided a memory map.\\n\");\n\t\tbios_mem_map[0].from = 0;\n\t\tbios_mem_map[0].to = kparms.memsize * 1024;\n\t\tbios_mem_map[0].from_hi = 0;\n\t\tbios_mem_map[0].to_hi = 0;\n\t\tbios_mem_map[0].type = MULTIBOOT_MEMORY_AVAILABLE;\n\t\tbios_mem_map[1].from = 0x00100000;\n\t\tbios_mem_map[1].to = (kparms.extmemsize + 1024) * 1024;\n\t\tbios_mem_map[1].from_hi = 0;\n\t\tbios_mem_map[1].to_hi = 0;\n\t\tbios_mem_map[1].type = MULTIBOOT_MEMORY_AVAILABLE;\n\t\tkstat.physical_pages = (kparms.extmemsize + 1024) >> 2;\n\t}\n\n\t/*\n\t * Truncate physical memory to upper kernel address space size (1GB or 2GB), since\n\t * currently all memory is permanently mapped there.\n\t */\n\tif(kstat.physical_pages > (GDT_BASE >> PAGE_SHIFT)) {\n\t\tkstat.physical_pages = (GDT_BASE >> PAGE_SHIFT);\n\t\tprintk(\"WARNING: only up to %dGB of physical memory will be used.\\n\", GDT_BASE >> 30);\n\t}\n\n\tmemcpy_b(kernel_mem_map, bios_mem_map, NR_BIOS_MM_ENT * sizeof(struct bios_mem_map));\n}\n"
  },
  {
    "path": "mm/buddy_low.c",
    "content": "/*\n * fiwix/mm/buddy_low.c\n *\n * Copyright 2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n/*\n * This buddy algorithm is intended to handle memory requests smaller\n * than a PAGE_SIZE.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/mm.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\nstatic struct bl_head *freelist[BUDDY_MAX_LEVEL + 1];\n\nstatic struct bl_head *get_buddy(struct bl_head *block)\n{\n\tint mask;\n\n\tmask = 1 << (block->level + 5);\n\treturn (struct bl_head *)((unsigned int)block ^ mask);\n}\n\nstatic void deallocate(struct bl_head *block)\n{\n\tstruct bl_head **h, *buddy, *p;\n\tstruct page *pg;\n\tunsigned int addr, paddr;\n\tint level;\n\n\tlevel = block->level;\n\tbuddy = get_buddy(block);\n\n\tp = freelist[level];\n\twhile(p != NULL) {\n\t\tif(p == buddy) {\n\t\t\tbreak;\n\t\t}\n\t\tp = p->next;\n\t}\n\n\tif(p == buddy) {\n\t\t/* remove buddy from its free list */\n\t\tif(buddy->next) {\n\t\t\tbuddy->next->prev = buddy->prev;\n\t\t}\n\t\tif(buddy->prev) {\n\t\t\tbuddy->prev->next = buddy->next;\n\t\t}\n\t\tif(buddy == freelist[level]) {\n\t\t\tfreelist[level] = buddy->next;\n\t\t}\n\t\t/* deallocate block and its buddy as one single block */\n\t\tif(level < BUDDY_MAX_LEVEL - 1) {\n\t\t\tif(block > buddy) {\n\t\t\t\tbuddy->level++;\n\t\t\t\tdeallocate(buddy);\n\t\t\t} else {\n\t\t\t\tblock->level++;\n\t\t\t\tdeallocate(block);\n\t\t\t}\n\t\t}\n\n\t\tif(level == BUDDY_MAX_LEVEL - 1) {\n\t\t\taddr = (unsigned int)block;\n\t\t\tpaddr = V2P(addr);\n\t\t\tpg = &page_table[paddr >> PAGE_SHIFT];\n\t\t\tpg->flags &= ~PAGE_BUDDYLOW;\n\t\t\tkfree(addr);\n\t\t\tkstat.buddy_low_num_pages--;\n\t\t}\n\t} else {\n\t\t/* buddy not free, put block on its free list */\n\t\th = &freelist[level];\n\n\t\tif(!*h) {\n\t\t\t*h = block;\n\t\t\tblock->prev = block->next = NULL;\n\t\t} else {\n\t\t\tblock->next = *h;\n\t\t\tblock->prev = NULL;\n\t\t\t(*h)->prev = block;\n\t\t\t*h = block;\n\t\t}\n\t}\n}\n\nstatic struct bl_head *allocate(int size)\n{\n\tstruct bl_head *block, *buddy;\n\tstruct page *pg;\n\tunsigned int addr, paddr;\n\tint level;\n\n\tfor(level = 0; bl_blocksize[level] < size; level++);\n\n\tif(level == BUDDY_MAX_LEVEL) {\n\t\tif((addr = kmalloc(PAGE_SIZE))) {\n\t\t\tpaddr = V2P(addr);\n\t\t\tpg = &page_table[paddr >> PAGE_SHIFT];\n\t\t\tpg->flags |= PAGE_BUDDYLOW;\n\t\t\tblock = (struct bl_head *)addr;\n\t\t} else {\n\t\t\tprintk(\"WARNING: %s(): not enough memory!\\n\", __FUNCTION__);\n\t\t\treturn NULL;\n\t\t}\n\t\tkstat.buddy_low_num_pages++;\n\t\tblock->prev = block->next = NULL;\n\t\treturn block;\n\t}\n\n\tif(freelist[level] != NULL) {\n\t\t/* we have a block on freelist */\n\t\tblock = freelist[level];\n\t\tif(block->next) {\n\t\t\tblock->next->prev = block->prev;\n\t\t}\n\t\tif(block->prev) {\n\t\t\tblock->prev->next = block->next;\n\t\t}\n\t\tfreelist[level] = block->next;\n\t} else {\n\t\t/* split a bigger block */\n\t\tblock = allocate(bl_blocksize[level + 1]);\n\n\t\tif(block != NULL) {\n\t\t\t/* put the buddy on the free list */\n\t\t\tblock->level = level;\n\t\t\tbuddy = get_buddy(block);\n\t\t\tbuddy->level = level;\n\t\t\tbuddy->prev = buddy->next = NULL;\n\t\t\tfreelist[level] = buddy;\n\t\t}\n\t}\n\n\treturn block;\n}\n\nunsigned int bl_malloc(__size_t size)\n{\n\tstruct bl_head *block;\n\tint level;\n\n\tfor(level = 0; bl_blocksize[level] < size; level++);\n\n\tkstat.buddy_low_count[level]++;\n\tkstat.buddy_low_mem_requested += bl_blocksize[level];\n\tblock = allocate(size);\n\treturn block ? (unsigned int)(block + 1) : 0;\n}\n\nvoid bl_free(unsigned int addr)\n{\n\tstruct bl_head *block;\n\tint level;\n\n\tblock = (struct bl_head *)addr;\n\tblock--;\n\tlevel = block->level;\n\tkstat.buddy_low_count[level]--;\n\tkstat.buddy_low_mem_requested -= bl_blocksize[level];\n\tdeallocate(block);\n}\n\nvoid buddy_low_init(void)\n{\n\tmemset_b(freelist, 0, sizeof(freelist));\n}\n"
  },
  {
    "path": "mm/fault.c",
    "content": "/*\n * fiwix/mm/fault.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/sigcontext.h>\n#include <fiwix/asm.h>\n#include <fiwix/mm.h>\n#include <fiwix/process.h>\n#include <fiwix/traps.h>\n#include <fiwix/sched.h>\n#include <fiwix/fs.h>\n#include <fiwix/mman.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n#include <fiwix/syscalls.h>\n#include <fiwix/shm.h>\n\n/* send the SIGSEGV signal to the ofending process */\nstatic void send_sigsegv(struct sigcontext *sc)\n{\n#if defined(CONFIG_VERBOSE_SEGFAULTS)\n\tdump_registers(14, sc);\n\tprintk(\"Memory map:\\n\");\n\tshow_vma_regions(current);\n#endif /* CONFIG_VERBOSE_SEGFAULTS */\n\tsend_sig(current, SIGSEGV);\n}\n\nstatic int page_protection_violation(struct vma *vma, unsigned int cr2, struct sigcontext *sc)\n{\n\tunsigned int *pgdir;\n\tunsigned int *pgtbl;\n\tunsigned int pde, pte, addr;\n\tstruct page *pg;\n\tint page;\n\n\tpde = GET_PGDIR(cr2);\n\tpte = GET_PGTBL(cr2);\n\tpgdir = (unsigned int *)P2V(current->tss.cr3);\n\tpgtbl = (unsigned int *)P2V((pgdir[pde] & PAGE_MASK));\n\tpage = (pgtbl[pte] & PAGE_MASK) >> PAGE_SHIFT;\n\n\tpg = &page_table[page];\n\n\t/* Copy On Write feature */\n\tif(pg->count > 1) {\n\t\t/* a page not marked as copy-on-write means it's read-only */\n\t\tif(!(pg->flags & PAGE_COW)) {\n\t\t\tprintk(\"Oops!, page %d NOT marked for CoW.\\n\", pg->page);\n\t\t\tsend_sigsegv(sc);\n\t\t\treturn 0;\n\t\t}\n\t\tif(!(addr = kmalloc(PAGE_SIZE))) {\n\t\t\tprintk(\"%s(): not enough memory!\\n\", __FUNCTION__);\n\t\t\treturn 1;\n\t\t}\n\t\tcurrent->rss++;\n\t\tmemcpy_b((void *)addr, (void *)P2V((page << PAGE_SHIFT)), PAGE_SIZE);\n\t\tpgtbl[pte] = V2P(addr) | PAGE_PRESENT | PAGE_RW | PAGE_USER;\n\t\tkfree(P2V((page << PAGE_SHIFT)));\n\t\tcurrent->rss--;\n\t\tinvalidate_tlb();\n\t\treturn 0;\n\t} else {\n\t\t/* last page of Copy On Write procedure */\n\t\tif(pg->count == 1) {\n\t\t\t/* a page not marked as copy-on-write means it's read-only */\n\t\t\tif(!(pg->flags & PAGE_COW)) {\n\t\t\t\tprintk(\"Oops!, last page %d NOT marked for CoW.\\n\", pg->page);\n\t\t\t\tsend_sigsegv(sc);\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tpgtbl[pte] = (page << PAGE_SHIFT) | PAGE_PRESENT | PAGE_RW | PAGE_USER;\n\t\t\tinvalidate_tlb();\n\t\t\treturn 0;\n\t\t}\n\t}\n\tprintk(\"WARNING: %s(): page %d with pg->count = 0!\\n\", __FUNCTION__, pg->page);\n\treturn 1;\n}\n\nstatic int page_not_present(struct vma *vma, unsigned int cr2, struct sigcontext *sc)\n{\n\tunsigned int addr, file_offset;\n\tstruct page *pg;\n\n\tif(!vma) {\n\t\tif(cr2 >= (sc->oldesp - 32) && cr2 < PAGE_OFFSET) {\n\t\t\tif(!(vma = find_vma_region(PAGE_OFFSET - 1))) {\n\t\t\t\tprintk(\"WARNING: %s(): process %d doesn't have an stack region in vma_table!\\n\", __FUNCTION__, current->pid);\n\t\t\t\tsend_sigsegv(sc);\n\t\t\t\treturn 0;\n\t\t\t} else {\n\t\t\t\t/* assuming stack will never reach heap */\n\t\t\t\tvma->start = cr2;\n\t\t\t\tvma->start = vma->start & PAGE_MASK;\n\t\t\t}\n\t\t}\n\t}\n\n\t/* if still a non-valid vma is found then kill the process! */\n\tif(!vma || vma->prot == PROT_NONE) {\n\t\tsend_sigsegv(sc);\n\t\treturn 0;\n\t}\n\n\t/* fill the page with its corresponding file content */\n\tif(vma->inode) {\n\t\tfile_offset = (cr2 & PAGE_MASK) - vma->start + vma->offset;\n\t\tfile_offset &= PAGE_MASK;\n\t\tpg = NULL;\n\n\t\tif(!(vma->prot & PROT_WRITE) || vma->flags & MAP_SHARED) {\n\t\t\t/* check if it's already in cache */\n\t\t\tif((pg = search_page_hash(vma->inode, file_offset))) {\n\t\t\t\tif(!map_page(current, cr2, (unsigned int)V2P(pg->data), vma->prot)) {\n\t\t\t\t\tprintk(\"%s(): Oops, map_page() returned 0!\\n\", __FUNCTION__);\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t\tpage_lock(pg);\n\t\t\t\taddr = (unsigned int)pg->data;\n\t\t\t\tpage_unlock(pg);\n\t\t\t}\n\t\t}\n\t\tif(!pg) {\n\t\t\tif(!(addr = map_page(current, cr2, 0, vma->prot))) {\n\t\t\t\tprintk(\"%s(): Oops, map_page() returned 0!\\n\", __FUNCTION__);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tpg = &page_table[V2P(addr) >> PAGE_SHIFT];\n\t\t\tif(bread_page(pg, vma->inode, file_offset, vma->prot, vma->flags)) {\n\t\t\t\tunmap_page(cr2);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tcurrent->usage.ru_majflt++;\n\t\t}\n\t} else {\n\t\tcurrent->usage.ru_minflt++;\n\t\taddr = 0;\n#ifdef CONFIG_SYSVIPC\n\t\tif(vma->s_type == P_SHM) {\n\t\t\tif(shm_map_page(vma, cr2)) {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t}\n#endif /* CONFIG_SYSVIPC */\n\t}\n\n\tif(vma->flags & ZERO_PAGE) {\n\t\tif(!addr) {\n\t\t\tif(!(addr = map_page(current, cr2, 0, vma->prot))) {\n\t\t\t\tprintk(\"%s(): Oops, map_page() returned 0!\\n\", __FUNCTION__);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t}\n\t\tmemset_b((void *)(addr & PAGE_MASK), 0, PAGE_SIZE);\n\t}\n\n\treturn 0;\n}\n\n/*\n * Exception 0xE: Page Fault\n *\n *\t\t +------+------+------+------+------+------+\n *\t\t | user |kernel|  PV  |  PF  | read |write |\n * +-------------+------+------+------+------+------+------+\n * |the page     | U1   |    K1| U1 K1|      | U1 K1|    K1|\n * |has          | U2   |    K2| U2   |    K2|    K2| U2 K2|\n * |a vma region | U3   |      |      | U3   | U3   | U3   |\n * +-------------+------+------+------+------+------+------+\n * |the page     | U1   |    K1| U1   |    K1| U1 K1| U1 K1|\n * |doesn't have | U2   |    K2|    K2| U2   | U2 K2| U2 K2|\n * |a vma region |      |      |      |      |      |      |\n * +-------------+------+------+------+------+------+------+\n *\n * U1 - vma + user + PV + read\n *\t(vma page in user-mode, page-violation during read)\n *\tU1.1) if flags match\t\t\t-> Demand paging\n *\tU1.2) if flags don't match\t\t-> SIGSEV\n *\n * U2 - vma + user + PV + write\n *\t(vma page in user-mode, page-violation during write)\n *\tU2.1) if flags match\t\t\t-> Copy-On-Write\n *\tU2.2) if flags don't match\t\t-> SIGSEGV\n *\n * U3 - vma + user + PF + (read | write)\t-> Demand paging\n *\t(vma page in user-mode, page-fault during read or write)\n *\n * K1 - vma + kernel + PV + (read | write)\t-> PANIC\n *\t(vma page in kernel-mode, page-violation during read or write)\n * K2 - vma + kernel + PF + (read | write)\t-> Demand paging (mmap)\n *\t(vma page in kernel-mode, page-fault during read or write)\n *\n * ----------------------------------------------------------------------------\n *\n * U1 - !vma + user + PV + (read | write)\t-> SIGSEGV\n *\t(!vma page in user-mode, page-violation during read or write)\n * U2 - !vma + user + PF + (read | write)\t-> STACK?\n *\t(!vma page in user-mode, page-fault during read or write)\n *\n * K1 - !vma + kernel + PF + (read | write)\t-> STACK?\n *\t(!vma page in kernel-mode, page-fault during read or write)\n * K2 - !vma + kernel + PV + (read | write)\t-> PANIC\n *\t(!vma page in kernel-mode, page-violation during read or write)\n */\nvoid do_page_fault(unsigned int trap, struct sigcontext *sc)\n{\n\tunsigned int cr2;\n\tstruct vma *vma;\n\tint panic;\n\n\tGET_CR2(cr2);\n\tif((vma = find_vma_region(cr2))) {\n\n\t\t/* in user mode */\n\t\tif(sc->err & PFAULT_U) {\n\t\t\tif(sc->err & PFAULT_V) {\t/* violation */\n\t\t\t\tif(sc->err & PFAULT_W) {\n\t\t\t\t\tif((page_protection_violation(vma, cr2, sc))) {\n\t\t\t\t\t\tsend_sig(current, SIGKILL);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsend_sigsegv(sc);\n\t\t\t} else {\t\t\t/* page not present */\n\t\t\t\tif((page_not_present(vma, cr2, sc))) {\n\t\t\t\t\tsend_sig(current, SIGKILL);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\n\t\t/* in kernel mode */\n\t\t} else {\n\t\t\t/* \n\t\t\t * WP bit marks the order: first check if the page is\n\t\t\t * present, then check for protection violation.\n\t\t\t */\n\t\t\tif(!(sc->err & PFAULT_V)) {\t/* page not present */\n\t\t\t\tif((page_not_present(vma, cr2, sc))) {\n\t\t\t\t\tsend_sig(current, SIGKILL);\n\t\t\t\t\tprintk(\"%s(): kernel was unable to read a page of process '%s' (pid %d).\\n\", __FUNCTION__, current->argv0, current->pid);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif(sc->err & PFAULT_W) {\t/* copy-on-write? */\n\t\t\t\tif((page_protection_violation(vma, cr2, sc))) {\n\t\t\t\t\tsend_sig(current, SIGKILL);\n\t\t\t\t\tprintk(\"%s(): kernel was unable to write a page of process '%s' (pid %d).\\n\", __FUNCTION__, current->argv0, current->pid);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t} else {\n\t\t/* in user mode */\n\t\tif(sc->err & PFAULT_U) {\n\t\t\tif(sc->err & PFAULT_V) {\t/* violation */\n\t\t\t\tsend_sigsegv(sc);\n\t\t\t} else {\t\t\t/* stack? */\n\t\t\t\tif((page_not_present(vma, cr2, sc))) {\n\t\t\t\t\tsend_sig(current, SIGKILL);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\n\t\t/* in kernel mode */\n\t\t} else {\n\t\t\t/*\n\t\t\t * The kernel may incur in a page fault when trying to\n\t\t\t * access a possible user stack address. In that case,\n\t\t\t * sc->oldesp doesn't point to the user stack, but to\n\t\t\t * the kernel stack, because the page fault was raised\n\t\t\t * in kernel mode.\n\t\t\t * We need to get the original user sigcontext struct\n\t\t\t * from the current kernel stack, in order to obtain\n\t\t\t * the user stack pointer sc->oldesp, and see if CR2\n\t\t\t * looks like a user stack address.\n\t\t\t */\n\t\t\tstruct sigcontext *usc;\n\n\t\t\t/*\n\t\t\t * Since the page fault was raised in kernel mode, the\n\t\t\t * exception occurred at the same privilege level, hence\n\t\t\t * the %ss and %esp registers were not saved.\n\t\t\t */\n\t\t\tusc = (struct sigcontext *)((unsigned int *)sc->esp + 16);\n\t\t\tusc += 1;\n\n\t\t\t/* does it look like a user stack address? */\n\t\t\tif(cr2 >= (usc->oldesp - 32) && cr2 < PAGE_OFFSET) {\n\t\t\t\tif((!page_not_present(vma, cr2, usc))) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* no */\n\t\t}\n\t}\n\n\tpanic = dump_registers(trap, sc);\n\tshow_vma_regions(current);\n\tif(panic) {\n\t\tPANIC(\"\");\n\t}\n\tdo_exit(SIGTERM);\n}\n"
  },
  {
    "path": "mm/memory.c",
    "content": "/*\n * fiwix/mm/memory.c\n *\n * Copyright 2018-2023, Jordi Sanfeliu. All rights reserved.\n * Portions Copyright 2024, Greg Haerr.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/kernel.h>\n#include <fiwix/asm.h>\n#include <fiwix/multiboot1.h>\n#include <fiwix/kparms.h>\n#include <fiwix/mm.h>\n#include <fiwix/mman.h>\n#include <fiwix/bios.h>\n#include <fiwix/ramdisk.h>\n#include <fiwix/process.h>\n#include <fiwix/buffer.h>\n#include <fiwix/fs.h>\n#include <fiwix/kexec.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#define KERNEL_TEXT_SIZE\t((int)_etext - (PAGE_OFFSET + KERNEL_ADDR))\n#define KERNEL_DATA_SIZE\t((int)_edata - (int)_etext)\n#define KERNEL_BSS_SIZE\t\t((int)_end - (int)_edata)\n\nunsigned int *kpage_dir;\n\nunsigned int proc_table_size = 0;\nunsigned int buffer_hash_table_size = 0;\nunsigned int inode_table_size = 0;\nunsigned int inode_hash_table_size = 0;\nunsigned int fd_table_size = 0;\nunsigned int page_table_size = 0;\nunsigned int page_hash_table_size = 0;\n\nunsigned int map_kaddr(unsigned int *page_dir, unsigned int from, unsigned int to, unsigned int addr, int flags)\n{\n\tunsigned int n;\n\tunsigned int paddr;\n\tunsigned int *pgtbl;\n\tunsigned int pde, pte;\n\n\tpaddr = addr;\n\tfor(n = from; n < to; n += PAGE_SIZE) {\n\t\tpde = GET_PGDIR(n);\n\t\tpte = GET_PGTBL(n);\n\t\tif(!(page_dir[pde] & ~PAGE_MASK)) {\n\t\t\tif (!addr) {\n\t\t\t\tpaddr = kmalloc(PAGE_SIZE);\n\t\t\t\tif (!paddr) {\n\t\t\t\t\tprintk(\"%s(): no memory\\n\", __FUNCTION__);\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t\tpaddr = V2P(paddr);\n\t\t\t}\n\t\t\tpage_dir[pde] = paddr | flags;\n\t\t\tmemset_b((void *)(paddr + PAGE_OFFSET), 0, PAGE_SIZE);\n\t\t\tpaddr += PAGE_SIZE;\n\t\t}\n\t\tpgtbl = (unsigned int *)((page_dir[pde] & PAGE_MASK) + PAGE_OFFSET);\n\t\tpgtbl[pte] = n | flags;\n\t}\n\n\treturn paddr;\n}\n\nvoid bss_init(void)\n{\n\tmemset_b((void *)((int)_edata), 0, KERNEL_BSS_SIZE);\n}\n\n/*\n * This function creates a Page Directory covering all physical memory\n * pages and places it at the end of the memory. This ensures that it\n * won't be clobbered by a large initrd image.\n *\n * It returns the address of the PD to be activated by the CR3 register.\n */\nunsigned int setup_tmp_pgdir(unsigned int magic, unsigned int info)\n{\n\tint n, pd;\n\tunsigned int addr, memksize;\n\tunsigned int *pgtbl;\n\tstruct multiboot_info *mbi;\n\n\tif(magic != MULTIBOOT_BOOTLOADER_MAGIC) {\n\t\t/* 4MB of memory assumed */\n\t\tmemksize = 4096 - 1024;\t/* mem_upper */\n\t} else {\n\t\tmbi = (struct multiboot_info *)(PAGE_OFFSET + info);\n\t\tif(!(mbi->flags & MULTIBOOT_INFO_MEMORY)) {\n\t\t\t/* 4MB of memory assumed */\n\t\t\tmemksize = 4096 - 1024;\t/* mem_upper */\n\t\t} else {\n\t\t\tmemksize = (unsigned int)mbi->mem_upper;\n\t\t\t/* CONFIG_VM_SPLIT22 marks the maximum physical memory supported */\n\t\t\tif(memksize > ((0xFFFFFFFF - PAGE_OFFSET) / 1024)) {\n\t\t\t\tmemksize = (0xFFFFFFFF - PAGE_OFFSET) / 1024;\n\t\t\t}\n\t\t}\n\t}\n\n\taddr = PAGE_OFFSET + (memksize * 1024) - memksize;\n\taddr = PAGE_ALIGN(addr);\n\n\tkpage_dir = (unsigned int *)addr;\n\tmemset_b(kpage_dir, 0, PAGE_SIZE);\n\n\taddr += PAGE_SIZE;\n\tpgtbl = (unsigned int *)addr;\n\tmemset_b(pgtbl, 0, memksize);\n\n\tfor(n = 0; n < (memksize + 1024) / sizeof(unsigned int); n++) {\n\t\tpgtbl[n] = (n << PAGE_SHIFT) | PAGE_PRESENT | PAGE_RW;\n\t\tif(!(n % 1024)) {\n\t\t\tpd = n / 1024;\n\t\t\tkpage_dir[pd] = (unsigned int)(addr + (PAGE_SIZE * pd) + GDT_BASE) | PAGE_PRESENT | PAGE_RW;\n\t\t\tkpage_dir[GET_PGDIR(PAGE_OFFSET) + pd] = (unsigned int)(addr + (PAGE_SIZE * pd) + GDT_BASE) | PAGE_PRESENT | PAGE_RW;\n\t\t}\n\t}\n\treturn (unsigned int)kpage_dir - PAGE_OFFSET;\n}\n\n/* returns the mapped address of a virtual address */\nunsigned int get_mapped_addr(struct proc *p, unsigned int addr)\n{\n\tunsigned int *pgdir, *pgtbl;\n\tunsigned int pde, pte;\n\n\tpgdir = (unsigned int *)P2V(p->tss.cr3);\n\tpde = GET_PGDIR(addr);\n\tpte = GET_PGTBL(addr);\n\tpgtbl = (unsigned int *)P2V((pgdir[pde] & PAGE_MASK));\n\treturn pgtbl[pte];\n}\n\nint clone_pages(struct proc *child)\n{\n\tunsigned int *src_pgdir, *dst_pgdir;\n\tunsigned int *src_pgtbl, *dst_pgtbl;\n\tunsigned int pde, pte;\n\tunsigned int p_addr, c_addr;\n\tunsigned int n, pages;\n\tstruct page *pg;\n\tstruct vma *vma;\n\n\tsrc_pgdir = (unsigned int *)P2V(current->tss.cr3);\n\tdst_pgdir = (unsigned int *)P2V(child->tss.cr3);\n\tvma = current->vma_table;\n\tpages = 0;\n\n\twhile(vma) {\n\t\tif(vma->flags & MAP_SHARED) {\n\t\t\tvma = vma->next;\n\t\t\tcontinue;\n\t\t}\n\t\tfor(n = vma->start; n < vma->end; n += PAGE_SIZE) {\n\t\t\tpde = GET_PGDIR(n);\n\t\t\tpte = GET_PGTBL(n);\n\t\t\tif(src_pgdir[pde] & PAGE_PRESENT) {\n\t\t\t\tsrc_pgtbl = (unsigned int *)P2V((src_pgdir[pde] & PAGE_MASK));\n\t\t\t\tif(!(dst_pgdir[pde] & PAGE_PRESENT)) {\n\t\t\t\t\tif(!(c_addr = kmalloc(PAGE_SIZE))) {\n\t\t\t\t\t\tprintk(\"%s(): returning 0!\\n\", __FUNCTION__);\n\t\t\t\t\t\treturn 0;\n\t\t\t\t\t}\n\t\t\t\t\tcurrent->rss++;\n\t\t\t\t\tpages++;\n\t\t\t\t\tdst_pgdir[pde] = V2P(c_addr) | PAGE_PRESENT | PAGE_RW | PAGE_USER;\n\t\t\t\t\tmemset_b((void *)c_addr, 0, PAGE_SIZE);\n\t\t\t\t}\n\t\t\t\tdst_pgtbl = (unsigned int *)P2V((dst_pgdir[pde] & PAGE_MASK));\n\t\t\t\tif(src_pgtbl[pte] & PAGE_PRESENT) {\n\t\t\t\t\tif (src_pgtbl[pte] & PAGE_NOALLOC) {\n\t\t\t\t\t\tdst_pgtbl[pte] = src_pgtbl[pte];\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tp_addr = src_pgtbl[pte] >> PAGE_SHIFT;\n\t\t\t\t\tpg = &page_table[p_addr];\n\t\t\t\t\tif(pg->flags & PAGE_RESERVED) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tsrc_pgtbl[pte] &= ~PAGE_RW;\n\t\t\t\t\t/* mark writable pages as copy-on-write */\n\t\t\t\t\tif(vma->prot & PROT_WRITE) {\n\t\t\t\t\t\tpg->flags |= PAGE_COW;\n\t\t\t\t\t}\n\t\t\t\t\tdst_pgtbl[pte] = src_pgtbl[pte];\n\t\t\t\t\tif(!is_valid_page((dst_pgtbl[pte] & PAGE_MASK) >> PAGE_SHIFT)) {\n\t\t\t\t\t\tPANIC(\"%s: missing page %d during copy-on-write process.\\n\", __FUNCTION__, (dst_pgtbl[pte] & PAGE_MASK) >> PAGE_SHIFT);\n\t\t\t\t\t}\n\t\t\t\t\tpg = &page_table[(dst_pgtbl[pte] & PAGE_MASK) >> PAGE_SHIFT];\n\t\t\t\t\tpg->count++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tvma = vma->next;\n\t}\n\treturn pages;\n}\n\nint free_page_tables(struct proc *p)\n{\n\tunsigned int *pgdir;\n\tint n, count;\n\n\tpgdir = (unsigned int *)P2V(p->tss.cr3);\n\tfor(n = 0, count = 0; n < PD_ENTRIES; n++) {\n\t\tif((pgdir[n] & (PAGE_PRESENT | PAGE_RW | PAGE_USER)) == (PAGE_PRESENT | PAGE_RW | PAGE_USER)) {\n\t\t\tkfree(P2V(pgdir[n]) & PAGE_MASK);\n\t\t\tpgdir[n] = 0;\n\t\t\tcount++;\n\t\t}\n\t}\n\treturn count;\n}\n\nunsigned int map_page(struct proc *p, unsigned int vaddr, unsigned int addr, unsigned int prot)\n{\n\treturn map_page_flags(p, vaddr, addr, prot, 0);\n}\n\nunsigned int map_page_flags(struct proc *p, unsigned int vaddr, unsigned int addr, unsigned int prot, int flags)\n{\n\tunsigned int *pgdir, *pgtbl;\n\tunsigned int newaddr;\n\tint pde, pte;\n\n\tpgdir = (unsigned int *)P2V(p->tss.cr3);\n\tpde = GET_PGDIR(vaddr);\n\tpte = GET_PGTBL(vaddr);\n\n\tif(!(pgdir[pde] & PAGE_PRESENT)) {\t/* allocating page table */\n\t\tif(!(newaddr = kmalloc(PAGE_SIZE))) {\n\t\t\treturn 0;\n\t\t}\n\t\tp->rss++;\n\t\tpgdir[pde] = V2P(newaddr) | PAGE_PRESENT | PAGE_RW | PAGE_USER;\n\t\tmemset_b((void *)newaddr, 0, PAGE_SIZE);\n\t}\n\tpgtbl = (unsigned int *)P2V((pgdir[pde] & PAGE_MASK));\n\tif(!(pgtbl[pte] & PAGE_PRESENT)) {\t/* allocating page */\n\t\tif(!addr) {\n\t\t\tif(!(addr = kmalloc(PAGE_SIZE))) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\taddr = V2P(addr);\n\t\t\tp->rss++;\n\t\t}\n\t\tpgtbl[pte] = addr | PAGE_PRESENT | PAGE_USER | flags;\n\t}\n\tif(prot & PROT_WRITE) {\n\t\tpgtbl[pte] |= PAGE_RW;\n\t}\n\treturn P2V(addr);\n}\n\nint unmap_page(unsigned int vaddr)\n{\n\tunsigned int *pgdir, *pgtbl;\n\tunsigned int addr, desc;\n\tint pde, pte;\n\n\tpgdir = (unsigned int *)P2V(current->tss.cr3);\n\tpde = GET_PGDIR(vaddr);\n\tpte = GET_PGTBL(vaddr);\n\tif(!(pgdir[pde] & PAGE_PRESENT)) {\n\t\tprintk(\"WARNING: %s(): trying to unmap an unallocated pde '0x%08x'\\n\", __FUNCTION__, vaddr);\n\t\treturn 1;\n\t}\n\n\tpgtbl = (unsigned int *)P2V((pgdir[pde] & PAGE_MASK));\n\tif(!(pgtbl[pte] & PAGE_PRESENT)) {\n\t\tprintk(\"WARNING: %s(): trying to unmap an unallocated page '0x%08x'\\n\", __FUNCTION__, vaddr);\n\t\treturn 1;\n\t}\n\n\tdesc = pgtbl[pte];\n\taddr = desc & PAGE_MASK;\n\tpgtbl[pte] = 0;\n\tif (!(desc & PAGE_NOALLOC)) {\n\t\tkfree(P2V(addr));\n\t}\n\tcurrent->rss--;\n\treturn 0;\n}\n\n/*\n * This function initializes and setups the kernel page directory and page\n * tables. It also reserves areas of contiguous memory spaces for internal\n * structures and for the RAMdisk drives.\n */\nvoid mem_init(void)\n{\n\tunsigned int sizek;\n\tunsigned int physical_memory, physical_page_tables;\n\tunsigned int *pgtbl;\n\tint n, pages, last_ramdisk;\n\n\tphysical_page_tables = (kstat.physical_pages / 1024) + ((kstat.physical_pages % 1024) ? 1 : 0);\n\tphysical_memory = (kstat.physical_pages << PAGE_SHIFT);\t/* in bytes */\n\n\t/* align _last_data_addr to the next page */\n\t_last_data_addr = PAGE_ALIGN(_last_data_addr);\n\n\t/* Page Directory */\n\tkpage_dir = (unsigned int *)_last_data_addr;\n\tmemset_b(kpage_dir, 0, PAGE_SIZE);\n\t_last_data_addr += PAGE_SIZE;\n\n\t/* Page Tables */\n\tpgtbl = (unsigned int *)_last_data_addr;\n\tmemset_b(pgtbl, 0, physical_page_tables * PAGE_SIZE);\n\t_last_data_addr += physical_page_tables * PAGE_SIZE;\n\n\t/* Page Directory and Page Tables initialization */\n\tfor(n = 0; n < kstat.physical_pages; n++) {\n\t\tpgtbl[n] = (n << PAGE_SHIFT) | PAGE_PRESENT | PAGE_RW;\n\t\tif(!(n % 1024)) {\n\t\t\tkpage_dir[GET_PGDIR(PAGE_OFFSET) + (n / 1024)] = (unsigned int)&pgtbl[n] | PAGE_PRESENT | PAGE_RW;\n\t\t}\n\t}\n\tactivate_kpage_dir();\n\n\t/* since Page Directory is now activated we can use virtual addresses */\n\tkpage_dir = (unsigned int *)P2V((unsigned int)kpage_dir);\n\t_last_data_addr = P2V(_last_data_addr);\n\n\t/* reserve memory space for proc_table[NR_PROCS] */\n\tproc_table_size = PAGE_ALIGN(sizeof(struct proc) * NR_PROCS);\n\tif(!is_addr_in_bios_map(V2P(_last_data_addr) + proc_table_size)) {\n\t\tPANIC(\"Not enough memory for proc_table.\\n\");\n\t}\n\tproc_table = (struct proc *)_last_data_addr;\n\t_last_data_addr += proc_table_size;\n\n\n\t/* reserve memory space for buffer_hash_table */\n\tkstat.max_buffers_size = kstat.physical_pages * (PAGE_SIZE / 1024);\n\tkstat.max_buffers_size = (kstat.max_buffers_size * BUFFER_PERCENTAGE) / 100;\n\tn = (kstat.max_buffers_size * BUFFER_HASH_PERCENTAGE) / 100;\n\tn = MAX(n, 10);\t/* 10 buffer hashes as minimum */\n\t/* buffer_hash_table is an array of pointers */\n\tpages = ((n * sizeof(unsigned int)) / PAGE_SIZE) + 1;\n\tbuffer_hash_table_size = pages << PAGE_SHIFT;\n\tif(!is_addr_in_bios_map(V2P(_last_data_addr) + buffer_hash_table_size)) {\n\t\tPANIC(\"Not enough memory for buffer_hash_table.\\n\");\n\t}\n\tbuffer_hash_table = (struct buffer **)_last_data_addr;\n\t_last_data_addr += buffer_hash_table_size;\n\n\n\t/* calculate the inode table size */\n\tsizek = physical_memory / 1024;\t/* this helps to avoid overflow */\n\tinode_table_size = (sizek * INODE_PERCENTAGE) / 100;\n\tinode_table_size *= 1024;\n\tpages = inode_table_size >> PAGE_SHIFT;\n\tinode_table_size = pages << PAGE_SHIFT;\n\n\t/* reserve memory space for inode_hash_table */\n\tkstat.max_inodes = inode_table_size / sizeof(struct inode);\n\tn = (kstat.max_inodes * INODE_HASH_PERCENTAGE) / 100;\n\tn = MAX(n, 10);\t/* 10 inode hash buckets as minimum */\n\t/* inode_hash_table is an array of pointers */\n\tpages = ((n * sizeof(unsigned int)) / PAGE_SIZE) + 1;\n\tinode_hash_table_size = pages << PAGE_SHIFT;\n\tif(!is_addr_in_bios_map(V2P(_last_data_addr) + inode_hash_table_size)) {\n\t\tPANIC(\"Not enough memory for inode_hash_table.\\n\");\n\t}\n\tinode_hash_table = (struct inode **)_last_data_addr;\n\t_last_data_addr += inode_hash_table_size;\n\n\n\t/* reserve memory space for fd_table[NR_OPENS] */\n\tfd_table_size = PAGE_ALIGN(sizeof(struct fd) * NR_OPENS);\n\tif(!is_addr_in_bios_map(V2P(_last_data_addr) + fd_table_size)) {\n\t\tPANIC(\"Not enough memory for fd_table.\\n\");\n\t}\n\tfd_table = (struct fd *)_last_data_addr;\n\t_last_data_addr += fd_table_size;\n\n\n\t/* reserve memory space for RAMdisk drives */\n\tlast_ramdisk = 0;\n\tif(kparms.ramdisksize > 0 || ramdisk_table[0].addr) {\n\t\t/*\n\t\t * If the 'initrd=' parameter was supplied, then the first\n\t\t * RAMdisk drive was already assigned to the initrd image.\n\t\t */\n\t\tif(ramdisk_table[0].addr) {\n\t\t\tramdisk_table[0].addr += PAGE_OFFSET;\n\t\t\tlast_ramdisk = 1;\n\t\t}\n\t\tfor(; last_ramdisk < ramdisk_minors; last_ramdisk++) {\n\t\t\tif(!is_addr_in_bios_map(V2P(_last_data_addr) + (kparms.ramdisksize * 1024))) {\n\t\t\t\tkparms.ramdisksize = 0;\n\t\t\t\tramdisk_minors -= RAMDISK_DRIVES;\n\t\t\t\tprintk(\"WARNING: RAMdisk drive disabled (not enough physical memory).\\n\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tramdisk_table[last_ramdisk].addr = (char *)_last_data_addr;\n\t\t\tramdisk_table[last_ramdisk].size = kparms.ramdisksize;\n\t\t\t_last_data_addr += kparms.ramdisksize * 1024;\n\t\t}\n\t}\n\n\t/*\n\t * FIXME: this is ugly!\n\t * It should go in console_init() once we have a proper kernel memory/page management.\n\t */\n\t#include <fiwix/console.h>\n\tfor(n = 1; n <= NR_VCONSOLES; n++) {\n\t\tvc_screen[n] = (short int *)_last_data_addr;\n\t\t_last_data_addr += (video.columns * video.lines * 2);\n\t}\n\t/*\n\t * FIXME: this is ugly!\n\t * It should go in console_init() once we have a proper kernel memory/page management.\n\t */\n\tvcbuf = (short int *)_last_data_addr;\n\t_last_data_addr += (video.columns * video.lines * SCREENS_LOG * 2 * sizeof(short int));\n\n#ifdef CONFIG_KEXEC\n\tif(kexec_size > 0) {\n\t\tbios_map_reserve(KEXEC_BOOT_ADDR, KEXEC_BOOT_ADDR + (PAGE_SIZE * 2));\n\t\tramdisk_minors++;\n\t\tif(last_ramdisk < ramdisk_minors) {\n\t\t\tif(!is_addr_in_bios_map(V2P(_last_data_addr) + (kexec_size * 1024))) {\n\t\t\t\tkexec_size = 0;\n\t\t\t\tramdisk_minors--;\n\t\t\t\tprintk(\"WARNING: RAMdisk drive for kexec disabled (not enough physical memory).\\n\");\n\t\t\t} else {\n\t\t\t\tramdisk_table[last_ramdisk].addr = (char *)_last_data_addr;\n\t\t\t\tramdisk_table[last_ramdisk].size = kexec_size;\n\t\t\t\t_last_data_addr += kexec_size * 1024;\n\t\t\t}\n\t\t}\n\t}\n#endif /* CONFIG_KEXEC */\n\n\t/* the last one must be the page_table structure */\n\tn = (kstat.physical_pages * PAGE_HASH_PER_10K) / 10000;\n\tn = MAX(n, 1);\t/* 1 page for the hash table as minimum */\n\tn = MIN(n, MAX_PAGES_HASH);\n\tpage_hash_table_size = n * PAGE_SIZE;\n\tif(!is_addr_in_bios_map(V2P(_last_data_addr) + page_hash_table_size)) {\n\t\tPANIC(\"Not enough memory for page_hash_table.\\n\");\n\t}\n\tpage_hash_table = (struct page **)_last_data_addr;\n\t_last_data_addr += page_hash_table_size;\n\n\tpage_table_size = PAGE_ALIGN(kstat.physical_pages * sizeof(struct page));\n\tif(!is_addr_in_bios_map(V2P(_last_data_addr) + page_table_size)) {\n\t\tPANIC(\"Not enough memory for page_table.\\n\");\n\t}\n\tpage_table = (struct page *)_last_data_addr;\n\t_last_data_addr += page_table_size;\n\n\tpage_init(kstat.physical_pages);\n\tbuddy_low_init();\n}\n\nvoid mem_stats(void)\n{\n\tkstat.kernel_reserved <<= 2;\n\tkstat.physical_reserved <<= 2;\n\n\tprintk(\"\\n\");\n\tprintk(\"memory: total=%dKB, user=%dKB, kernel=%dKB, reserved=%dKB\\n\",\n\t\tkstat.physical_pages << 2,\n\t\tkstat.total_mem_pages << 2,\n\t\tkstat.kernel_reserved, kstat.physical_reserved);\n\tprintk(\"tables: procs=%d (%dKB), opens=%d (%dKB), pages=%dKB, inodes=%d\\n\",\n\t\tNR_PROCS, proc_table_size / 1024,\n\t\tNR_OPENS, fd_table_size / 1024,\n\t\tpage_table_size / 1024,\n\t\tkstat.max_inodes);\n\tprintk(\"hash tables: buffers=%d (%dKB), inodes=%d (%dKB), pages=%d (%dKB)\\n\",\n\t\tbuffer_hash_table_size / sizeof(unsigned int), buffer_hash_table_size / 1024,\n\t\tinode_hash_table_size / sizeof(unsigned int), inode_hash_table_size / 1024,\n\t\tpage_hash_table_size / sizeof(unsigned int), page_hash_table_size / 1024);\n\tprintk(\"kernel: text=%dKB, data=%dKB, bss=%dKB\\n\\n\",\n\t\tKERNEL_TEXT_SIZE / 1024, KERNEL_DATA_SIZE / 1024, KERNEL_BSS_SIZE / 1024);\n}\n"
  },
  {
    "path": "mm/mmap.c",
    "content": "/*\n * fiwix/mm/mmap.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Portions Copyright 2024, Greg Haerr.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/mm.h>\n#include <fiwix/fs.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/stat.h>\n#include <fiwix/process.h>\n#include <fiwix/mman.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n#include <fiwix/shm.h>\n\nvoid merge_vma_regions(struct vma *, struct vma *);\n\nvoid show_vma_regions(struct proc *p)\n{\n\t__ino_t inode;\n\tint major, minor;\n\tchar *section;\n\tchar r, w, x, f;\n\tstruct vma *vma;\n\tunsigned int n;\n\tint count;\n\n\tif(!p) {\n\t\treturn;\n\t}\n\n\tvma = p->vma_table;\n\tn = 0;\n\tprintk(\"num  address range         flag offset     dev   inode      mod section cnt\\n\");\n\tprintk(\"---- --------------------- ---- ---------- ----- ---------- --- ------- ----\\n\");\n\n\twhile(vma) {\n\t\tr = vma->prot & PROT_READ ? 'r' : '-';\n\t\tw = vma->prot & PROT_WRITE ? 'w' : '-';\n\t\tx = vma->prot & PROT_EXEC ? 'x' : '-';\n\t\tif(vma->flags & MAP_SHARED) {\n\t\t\tf = 's';\n\t\t} else if(vma->flags & MAP_PRIVATE) {\n\t\t\tf = 'p';\n\t\t} else {\n\t\t\tf = '-';\n\t\t}\n\t\tswitch(vma->s_type) {\n\t\t\tcase P_TEXT:\tsection = \"text \";\n\t\t\t\t\tbreak;\n\t\t\tcase P_DATA:\tsection = \"data \";\n\t\t\t\t\tbreak;\n\t\t\tcase P_BSS:\tsection = \"bss  \";\n\t\t\t\t\tbreak;\n\t\t\tcase P_HEAP:\tsection = \"heap \";\n\t\t\t\t\tbreak;\n\t\t\tcase P_STACK:\tsection = \"stack\";\n\t\t\t\t\tbreak;\n\t\t\tcase P_MMAP:\tsection = \"mmap \";\n\t\t\t\t\tbreak;\n#ifdef CONFIG_SYSVIPC\n\t\t\tcase P_SHM:\tsection = \"shm  \";\n\t\t\t\t\tbreak;\n#endif /* CONFIG_SYSVIPC */\n\t\t\tdefault:\n\t\t\t\tsection = NULL;\n\t\t\t\tbreak;\n\t\t}\n\t\tinode = major = minor = count = 0;\n\t\tif(vma->inode) {\n\t\t\tinode = vma->inode->inode;\n\t\t\tmajor = MAJOR(vma->inode->dev);\n\t\t\tminor = MINOR(vma->inode->dev);\n\t\t\tcount = vma->inode->count;\n\t\t}\n\t\tprintk(\"[%02d] 0x%08x-0x%08x %c%c%c%c 0x%08x %02d:%02d %- 10u <%d> [%s]  (%d)\\n\", n, vma->start, vma->end, r, w, x, f, vma->offset, major, minor, inode, vma->o_mode, section, count);\n\t\tvma = vma->next;\n\t\tn++;\n\t}\n\tif(!n) {\n\t\tprintk(\"[no vma regions]\\n\");\n\t}\n}\n\n/* insert a vma structure into vma_table sorted by address */\nstatic void insert_vma_region(struct vma *vma)\n{\n\tstruct vma *vmat;\n\n\tvmat = current->vma_table;\n\n\twhile(vmat) {\n\t\tif(vmat->start > vma->start) {\n\t\t\tbreak;\n\t\t}\n\t\tvmat = vmat->next;\n\t}\n\n\tif(!vmat) {\n\t\t/* append */\n\t\tvma->prev = current->vma_table->prev;\n\t\tcurrent->vma_table->prev->next = vma;\n\t\tcurrent->vma_table->prev = vma;\n\t} else {\n\t\t/* insert */\n\t\tvma->prev = vmat->prev;\n\t\tvma->next = vmat;\n\t\tif(vmat == current->vma_table) {\n\t\t\t/* insert in the head */\n\t\t\tcurrent->vma_table = vma;\n\t\t} else {\n\t\t\t/* insert in the middle */\n\t\t\tvmat->prev->next = vma;\n\t\t}\n\t\tvmat->prev = vma;\n\t}\n\tif(vma->inode) {\n\t\tvma->inode->count++;\n\t}\n\n\tif(vma != vma->prev && vma->start >= vma->prev->start && vma->start <= vma->prev->end) {\n\t\tmerge_vma_regions(vma->prev, vma);\n\t}\n}\n\nstatic void add_vma_region(struct vma *vma)\n{\n\tunsigned int flags;\n\n\tSAVE_FLAGS(flags); CLI();\n\tif(!current->vma_table) {\n\t\tcurrent->vma_table = vma;\n\t\tcurrent->vma_table->prev = vma;\n\t\tif(vma->inode) {\n\t\t\tvma->inode->count++;\n\t\t}\n\t} else {\n\t\tinsert_vma_region(vma);\n\t}\n\tRESTORE_FLAGS(flags);\n}\n\nstatic void del_vma_region(struct vma *vma)\n{\n\tunsigned int flags;\n\tstruct vma *tmp;\n\n\ttmp = vma;\n\n\tif(!vma->next && !vma->prev) {\n\t\tprintk(\"WARNING: %s(): trying to delete an unexistent vma region (%x).\\n\", __FUNCTION__, vma->start);\n\t\treturn;\n\t}\n\n\tSAVE_FLAGS(flags); CLI();\n\tif(vma->next) {\n\t\tvma->next->prev = vma->prev;\n\t}\n\tif(vma->prev) {\n\t\tif(vma != current->vma_table) {\n\t\t\tvma->prev->next = vma->next;\n\t\t}\n\t}\n\tif(!vma->next) {\n\t\tcurrent->vma_table->prev = vma->prev;\n\t}\n\tif(vma == current->vma_table) {\n\t\tcurrent->vma_table = vma->next;\n\t}\n\tRESTORE_FLAGS(flags);\n\n\tkfree((unsigned int)tmp);\n}\n\nstatic int can_be_merged(struct vma *a, struct vma *b)\n{\n\tif((a->end == b->start) &&\n\t   (a->prot == b->prot) &&\n\t   (a->flags == b->flags) &&\n\t   (a->offset == b->offset) &&\n\t   (a->s_type == b->s_type) &&\n#ifdef CONFIG_SYSVIPC\n\t   (a->s_type != P_SHM) &&\n#endif /* CONFIG_SYSVIPC */\n\t   (a->inode == b->inode)) {\n\t\treturn 1;\n\t}\n\n\treturn 0;\n}\n\nstatic int free_vma_region(struct vma *vma, unsigned int start, __ssize_t length)\n{\n\tstruct vma *new;\n\n\tif(start + length < vma->end) {\n\t\tif(!(new = (struct vma *)kmalloc(sizeof(struct vma)))) {\n\t\t\treturn -ENOMEM;\n\t\t}\n\t\tmemset_b(new, 0, sizeof(struct vma));\n\t\tnew->start = start + length;\n\t\tnew->end = vma->end;\n\t\tnew->prot = vma->prot;\n\t\tnew->flags = vma->flags;\n\t\tnew->offset = vma->offset;\n\t\tnew->s_type = vma->s_type;\n\t\tnew->inode = vma->inode;\n\t\tnew->o_mode = vma->o_mode;\n\t} else {\n\t\tnew = NULL;\n\t}\n\n\tif(vma->start == start) {\n\t\tif(vma->inode) {\n\t\t\tiput(vma->inode);\n\t\t}\n\t\tdel_vma_region(vma);\n\t} else {\n\t\tvma->end = start;\n\t}\n\n\tif(new) {\n\t\tadd_vma_region(new);\n\t}\n\n\treturn 0;\n}\n\n/* this assumes that vma_table is sorted by address */\nvoid merge_vma_regions(struct vma *a, struct vma *b)\n{\n\tstruct vma *new;\n\n\tif(b->start == a->end) {\n\t\tif(can_be_merged(a, b)) {\n\t\t\ta->end = b->end;\n\t\t\tdel_vma_region(b);\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif((b->start < a->end)) {\n\t\tif(!(new = (struct vma *)kmalloc(sizeof(struct vma)))) {\n\t\t\treturn;\n\t\t}\n\t\tmemset_b(new, 0, sizeof(struct vma));\n\t\tnew->start = b->end;\n\t\tnew->end = a->end;\n\t\tnew->prot = a->prot;\n\t\tnew->flags = a->flags;\n\t\tnew->offset = a->offset;\n\t\tnew->s_type = a->s_type;\n\t\tnew->inode = a->inode;\n\t\tnew->o_mode = a->o_mode;\n\t\tfree_vma_pages(a, b->start, b->end - b->start);\n\t\tinvalidate_tlb();\n\t\ta->end = b->start;\n\t\tif(a->start == a->end) {\n\t\t\tdel_vma_region(a);\n\t\t}\n\t\tif(new->start >= new->end) {\n\t\t\tkfree((unsigned int)new);\n\t\t} else {\n\t\t\tinsert_vma_region(new);\n\t\t}\n\t}\n}\n\nvoid free_vma_pages(struct vma *vma, unsigned int start, __size_t length)\n{\n\tunsigned int n, offset;\n\tunsigned int *pgdir, *pgtbl;\n\tunsigned int pde, pte;\n\tstruct page *pg;\n\tint page;\n\n\tpgdir = (unsigned int *)P2V(current->tss.cr3);\n\tpgtbl = NULL;\n\n\tfor(n = 0; n < (length / PAGE_SIZE); n++) {\n\t\tpde = GET_PGDIR(start + (n * PAGE_SIZE));\n\t\tpte = GET_PGTBL(start + (n * PAGE_SIZE));\n\t\tif(pgdir[pde] & PAGE_PRESENT) {\n\t\t\tpgtbl = (unsigned int *)P2V((pgdir[pde] & PAGE_MASK));\n\t\t\tif(pgtbl[pte] & PAGE_PRESENT) {\n\t\t\t\tif (!(pgtbl[pte] & PAGE_NOALLOC)) {\n\t\t\t\t\t/* make sure to not free reserved pages */\n\t\t\t\t\tpage = pgtbl[pte] >> PAGE_SHIFT;\n\t\t\t\t\tpg = &page_table[page];\n\t\t\t\t\tif(pg->flags & PAGE_RESERVED) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif(vma->prot & PROT_WRITE && vma->flags & MAP_SHARED) {\n\t\t\t\t\t\toffset = start - vma->start + vma->offset + n * PAGE_SIZE;\n\t\t\t\t\t\twrite_page(pg, vma->inode, offset, PAGE_SIZE);\n\t\t\t\t\t}\n\n\t\t\t\t\tkfree(P2V(pgtbl[pte]) & PAGE_MASK);\n\t\t\t\t}\n\t\t\t\tcurrent->rss--;\n#ifdef CONFIG_SYSVIPC\n\t\t\t\tif(vma->object) {\n\t\t\t\t\tshm_rss--;\n\t\t\t\t}\n#endif /* CONFIG_SYSVIPC */\n\t\t\t\tpgtbl[pte] = 0;\n\n\t\t\t\t/* check if a page table can be freed */\n\t\t\t\tfor(pte = 0; pte < PT_ENTRIES; pte++) {\n\t\t\t\t\tif(pgtbl[pte] & PAGE_MASK) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(pte == PT_ENTRIES) {\n\t\t\t\t\tkfree((unsigned int)pgtbl & PAGE_MASK);\n\t\t\t\t\tcurrent->rss--;\n\t\t\t\t\tpgdir[pde] = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid release_binary(void)\n{\n\tstruct vma *vma, *tmp;\n\n\tvma = current->vma_table;\n\n\twhile(vma) {\n\t\ttmp = vma->next;\n\t\tfree_vma_pages(vma, vma->start, vma->end - vma->start);\n\t\tfree_vma_region(vma, vma->start, vma->end - vma->start);\n\t\tvma = tmp;\n\t}\n\n\tinvalidate_tlb();\n}\n\nstruct vma *find_vma_region(unsigned int addr)\n{\n\tstruct vma *vma;\n\n\tif(!addr) {\n\t\treturn NULL;\n\t}\n\n\taddr &= PAGE_MASK;\n\tvma = current->vma_table;\n\n\twhile(vma) {\n\t\tif((addr >= vma->start) && (addr < vma->end)) {\n\t\t\treturn vma;\n\t\t}\n\t\tvma = vma->next;\n\t}\n\treturn NULL;\n}\n\nstruct vma *find_vma_intersection(unsigned int start, unsigned int end)\n{\n\tstruct vma *vma;\n\n\tvma = current->vma_table;\n\n\twhile(vma) {\n\t\tif(end <= vma->start) {\n\t\t\tbreak;\n\t\t}\n\t\tif(start < vma->end) {\n\t\t\treturn vma;\n\t\t}\n\t\tvma = vma->next;\n\t}\n\treturn NULL;\n}\n\nint expand_heap(unsigned int new)\n{\n\tstruct vma *vma, *heap;\n\n\tvma = current->vma_table;\n\theap = NULL;\n\n\twhile(vma) {\n\t\t/* make sure the new heap won't overlap the next region */\n\t\tif(heap && new < vma->start) {\n\t\t\theap->end = new;\n\t\t\treturn 0;\n\t\t} else {\n\t\t\theap = NULL;\t/* was a bad candidate */\n\t\t}\n\t\tif(!heap && vma->s_type == P_HEAP) {\n\t\t\theap = vma;\t/* possible candidate */\n\t\t}\n\t\tvma = vma->next;\n\t}\n\n\t/* out of memory! */\n\treturn 1;\n}\n\n/* return the first free address that matches with the size of length */\nunsigned int get_unmapped_vma_region(unsigned int length)\n{\n\tunsigned int addr;\n\tstruct vma *vma;\n\n\tif(!length) {\n\t\treturn 0;\n\t}\n\n\taddr = MMAP_START;\n\tvma = current->vma_table;\n\n\twhile(vma) {\n\t\tif(vma->start < MMAP_START) {\n\t\t\tvma = vma->next;\n\t\t\tcontinue;\n\t\t}\n\t\tif(vma->start - addr >= length) {\n\t\t\treturn PAGE_ALIGN(addr);\n\t\t}\n\t\taddr = PAGE_ALIGN(vma->end);\n\t\tvma = vma->next;\n\t}\n\treturn 0;\n}\n\nint do_mmap(struct inode *i, unsigned int start, unsigned int length, unsigned int prot, unsigned int flags, unsigned int offset, char type, char mode, void *object)\n{\n\tstruct vma *vma;\n\tint errno;\n\n\tif(!(length = PAGE_ALIGN(length))) {\n\t\treturn start;\n\t}\n\n\tif(start > PAGE_OFFSET || start + length > PAGE_OFFSET) {\n\t\treturn -EINVAL;\n\t}\n\n\t/* file mapping */\n\tif(i) {\n\t\tif(!S_ISREG(i->i_mode) && !S_ISCHR(i->i_mode)) {\n\t\t\treturn -ENODEV;\n\t\t}\n\n\t\t/* \n\t\t * The file shall have been opened with read permission,\n\t\t * regardless of the protection options specified.\n\t\t * IEEE Std 1003.1, 2004 Edition.\n\t\t */\n\t\tif(mode == O_WRONLY) {\n\t\t\treturn -EACCES;\n\t\t}\n\t\tswitch(flags & MAP_TYPE) {\n\t\t\tcase MAP_SHARED:\n\t\t\t\tif(prot & PROT_WRITE) {\n\t\t\t\t\tif(!(mode & (O_WRONLY | O_RDWR))) {\n\t\t\t\t\t\treturn -EACCES;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase MAP_PRIVATE:\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\treturn -EINVAL;\n\t\t}\n\n\t/* anonymous mapping */\n\t} else {\n\t\tif((flags & MAP_TYPE) != MAP_PRIVATE) {\n\t\t\treturn -EINVAL;\n\t\t}\n\n\t\t/* anonymous objects must be filled with zeros */\n\t\tflags |= ZERO_PAGE;\n#ifdef CONFIG_SYSVIPC\n\t\t/* ... except for SHM regions */\n\t\tif(type == P_SHM) {\n\t\t\tflags &= ~ZERO_PAGE;\n\t\t}\n#endif /* CONFIG_SYSVIPC */\n\t}\n\n\tif(flags & MAP_FIXED) {\n\t\tif(start & ~PAGE_MASK) {\n\t\t\treturn -EINVAL;\n\t\t}\n\t} else {\n\t\tstart = get_unmapped_vma_region(length);\n\t\tif(!start) {\n\t\t\tprintk(\"WARNING: %s(): unable to get an unmapped vma region.\\n\", __FUNCTION__);\n\t\t\treturn -ENOMEM;\n\t\t}\n\t}\n\n\tif(!(vma = (struct vma *)kmalloc(sizeof(struct vma)))) {\n                return -ENOMEM;\n        }\n        memset_b(vma, 0, sizeof(struct vma));\n\tvma->start = start;\n\tvma->end = start + length;\n\tvma->prot = prot;\n\tvma->flags = flags;\n\tvma->offset = offset;\n\tvma->s_type = type;\n\tvma->inode = i;\n\tvma->o_mode = mode;\n#ifdef CONFIG_SYSVIPC\n\tvma->object = (struct shmid_ds *)object;\n#endif /* CONFIG_SYSVIPC */\n\n\tdo_munmap(start, length);   /* clear old maps */\n\n\tif(i && i->fsop->mmap) {\n\t\tif((errno = i->fsop->mmap(i, vma))) {\n\t\t\tfree_vma_region(vma, start, length);\n\t\t\tkfree((unsigned int)vma);\n\t\t\treturn errno;\n\t\t}\n\t}\n\n\tadd_vma_region(vma);\n\treturn start;\n}\n\nint do_munmap(unsigned int addr, __size_t length)\n{\n\tstruct vma *vma;\n\tunsigned int size;\n\n\tif(addr & ~PAGE_MASK) {\n\t\treturn -EINVAL;\n\t}\n\n\tlength = PAGE_ALIGN(length);\n\n\twhile(length) {\n\t\tif(!(vma = find_vma_region(addr))) {\n\t\t\tbreak;\n\t\t}\n\t\tif((addr + length) > vma->end) {\n\t\t\tsize = vma->end - addr;\n\t\t} else {\n\t\t\tsize = length;\n\t\t}\n\n\t\tfree_vma_pages(vma, addr, size);\n\t\tinvalidate_tlb();\n\t\tfree_vma_region(vma, addr, size);\n\t\tlength -= size;\n\t\taddr += size;\n\t}\n\treturn 0;\n}\n\nint do_mprotect(struct vma *vma, unsigned int addr, __size_t length, int prot)\n{\n\tstruct vma *new;\n\n\tif(!(new = (struct vma *)kmalloc(sizeof(struct vma)))) {\n                return -ENOMEM;\n        }\n        memset_b(new, 0, sizeof(struct vma));\n\tnew->start = addr;\n\tnew->end = addr + length;\n\tnew->prot = prot;\n\tnew->flags = vma->flags;\n\tnew->offset = vma->offset;\n\tnew->s_type = vma->s_type;\n\tnew->inode = vma->inode;\n\tnew->o_mode = vma->o_mode;\n\tadd_vma_region(new);\n\n\treturn 0;\n}\n"
  },
  {
    "path": "mm/page.c",
    "content": "/*\n * fiwix/mm/page.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n/*\n * page.c implements a cache with a free list as a doubly circular linked\n * list and a chained hash table with doubly linked lists.\n *\n * hash table\n * +--------+  +--------------+  +--------------+  +--------------+\n * | index  |  |prev|data|next|  |prev|data|next|  |prev|data|next|\n * |   0   --> | /  |    | --->  <--- |    | --->  <--- |    |  / |\n * +--------+  +--------------+  +--------------+  +--------------+\n * +--------+  +--------------+  +--------------+  +--------------+\n * | index  |  |prev|data|next|  |prev|data|next|  |prev|data|next|\n * |   1   --> | /  |    | --->  <--- |    | --->  <--- |    |  / |\n * +--------+  +--------------+  +--------------+  +--------------+\n *              (page)            (page)            (page)  \n *    ...\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/mm.h>\n#include <fiwix/mman.h>\n#include <fiwix/bios.h>\n#include <fiwix/sleep.h>\n#include <fiwix/sched.h>\n#include <fiwix/devices.h>\n#include <fiwix/buffer.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n#include <fiwix/blk_queue.h>\n\n#define PAGE_HASH(inode, offset)\t(((__ino_t)(inode) ^ (__off_t)(offset)) % (NR_PAGE_HASH))\n#define NR_PAGES\t(page_table_size / sizeof(struct page))\n#define NR_PAGE_HASH\t(page_hash_table_size / sizeof(unsigned int))\n\nstruct page *page_table;\t\t/* page pool */\nstruct page *page_head;\t\t\t/* page pool head */\nstruct page **page_hash_table;\n\nstatic void insert_to_hash(struct page *pg)\n{\n\tstruct page **h;\n\tint i;\n\n\ti = PAGE_HASH(pg->inode, pg->offset);\n\th = &page_hash_table[i];\n\n\tif(!*h) {\n\t\t*h = pg;\n\t\t(*h)->prev_hash = (*h)->next_hash = NULL;\n\t} else {\n\t\tpg->prev_hash = NULL;\n\t\tpg->next_hash = *h;\n\t\t(*h)->prev_hash = pg;\n\t\t*h = pg;\n\t}\n\tkstat.cached += (PAGE_SIZE / 1024);\n}\n\nstatic void remove_from_hash(struct page *pg)\n{\n\tstruct page **h;\n\tint i;\n\n\tif(!pg->inode) {\n\t\treturn;\n\t}\n\n\ti = PAGE_HASH(pg->inode, pg->offset);\n\th = &page_hash_table[i];\n\n\twhile(*h) {\n\t\tif(*h == pg) {\n\t\t\tif((*h)->next_hash) {\n\t\t\t\t(*h)->next_hash->prev_hash = (*h)->prev_hash;\n\t\t\t}\n\t\t\tif((*h)->prev_hash) {\n\t\t\t\t(*h)->prev_hash->next_hash = (*h)->next_hash;\n\t\t\t}\n\t\t\tif(h == &page_hash_table[i]) {\n\t\t\t\t*h = (*h)->next_hash;\n\t\t\t}\n\t\t\tkstat.cached -= (PAGE_SIZE / 1024);\n\t\t\tbreak;\n\t\t}\n\t\th = &(*h)->next_hash;\n\t}\n}\n\nstatic void insert_on_free_list(struct page *pg)\n{\n\tif(!page_head) {\n\t\tpg->prev_free = pg->next_free = pg;\n\t\tpage_head = pg;\n\t} else {\n\t\tpg->next_free = page_head;\n\t\tpg->prev_free = page_head->prev_free;\n\t\tpage_head->prev_free->next_free = pg;\n\t\tpage_head->prev_free = pg;\n\t}\n\n\tkstat.free_pages++;\n}\n\nstatic void remove_from_free_list(struct page *pg)\n{\n\tif(!kstat.free_pages) {\n\t\treturn;\n\t}\n\n\tpg->prev_free->next_free = pg->next_free;\n\tpg->next_free->prev_free = pg->prev_free;\n\tkstat.free_pages--;\n\tif(pg == page_head) {\n\t\tpage_head = pg->next_free;\n\t}\n\n\tif(!kstat.free_pages) {\n\t\tpage_head = NULL;\n\t}\n}\n\nvoid page_lock(struct page *pg)\n{\n\tunsigned int flags;\n\n\tfor(;;) {\n\t\tSAVE_FLAGS(flags); CLI();\n\t\tif(pg->flags & PAGE_LOCKED) {\n\t\t\tRESTORE_FLAGS(flags);\n\t\t\tsleep(pg, PROC_UNINTERRUPTIBLE);\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t}\n\tpg->flags |= PAGE_LOCKED;\n\tRESTORE_FLAGS(flags);\n}\n\nvoid page_unlock(struct page *pg)\n{\n\tunsigned int flags;\n\n\tSAVE_FLAGS(flags); CLI();\n\tpg->flags &= ~PAGE_LOCKED;\n\twakeup(pg);\n\tRESTORE_FLAGS(flags);\n}\n\nstruct page *get_free_page(void)\n{\n\tunsigned int flags;\n\tstruct page *pg;\n\nrepeat:\n\t/* if the number of pages is low then reclaim some buffers */\n\tif(kstat.free_pages <= kstat.min_free_pages) {\n\t\t/* reclaim memory from buffer cache */\n\t\twakeup(&kswapd);\n\t\tif(!kstat.free_pages) {\n\t\t\tsleep(&get_free_page, PROC_UNINTERRUPTIBLE);\n\t\t\tif(!kstat.free_pages) {\n\t\t\t\tif(kstat.pages_reclaimed) {\n\t\t\t\t\tgoto repeat;\n\t\t\t\t}\n\t\t\t\t/* definitely out of memory! (no more pages) */\n\t\t\t\tprintk(\"WARNING: %s(): out of memory and swapping is not implemented yet, sorry.\\n\", __FUNCTION__);\n\t\t\t\tprintk(\"%s(): pid %d ran out of memory. OOM killer needed!\\n\", __FUNCTION__, current->pid);\n\t\t\t\treturn NULL;\n\t\t\t}\n\t\t}\n\t\t/* this reduces the number of iterations */\n\t\tif(kstat.min_free_pages > NR_BUF_RECLAIM) {\n\t\t\tkstat.min_free_pages -= NR_BUF_RECLAIM;\n\t\t}\n\t} else {\n\t\t/* recalculate if free memory is back to normal levels */\n\t\tif(kstat.min_free_pages <= NR_BUF_RECLAIM) {\n\t\t\tif(kstat.free_pages > NR_BUF_RECLAIM) {\n\t\t\t\tkstat.min_free_pages = (kstat.total_mem_pages * FREE_PAGES_RATIO) / 100;\n\t\t\t}\n\t\t}\n\t}\n\n\tSAVE_FLAGS(flags); CLI();\n\n\tif(!(pg = page_head)) {\n\t\tprintk(\"WARNING: page_head returned NULL! (free_pages = %d)\\n\", kstat.free_pages);\n\t\tRESTORE_FLAGS(flags);\n\t\treturn NULL;\n\t}\n\n\tremove_from_free_list(pg);\n\tremove_from_hash(pg);\t/* remove it from its old hash */\n\tpg->count = 1;\n\tpg->inode = 0;\n\tpg->offset = 0;\n\tpg->dev = 0;\n\n\tRESTORE_FLAGS(flags);\n\treturn pg;\n}\n\nstruct page *search_page_hash(struct inode *inode, __off_t offset)\n{\n\tstruct page *pg;\n\tint i;\n\n\ti = PAGE_HASH(inode->inode, offset);\n\tpg = page_hash_table[i];\n\n\twhile(pg) {\n\t\tif(pg->inode == inode->inode && pg->offset == offset && pg->dev == inode->dev) {\n\t\t\tif(!pg->count) {\n\t\t\t\tremove_from_free_list(pg);\n\t\t\t}\n\t\t\tpg->count++;\n\t\t\treturn pg;\n\t\t}\n\t\tpg = pg->next_hash;\n\t}\n\n\treturn NULL;\n}\n\nvoid release_page(struct page *pg)\n{\n\tunsigned int flags;\n\n\tif(!is_valid_page(pg->page)) {\n\t\tPANIC(\"Unexpected inconsistency in hash_table. Missing page %d (0x%x).\\n\", pg->page, pg->page);\n\t}\n\n\tif(!pg->count) {\n\t\tprintk(\"WARNING: %s(): trying to free an already freed page (%d)!\\n\", __FUNCTION__, pg->page);\n\t\treturn;\n\t}\n\n\tif(--pg->count > 0) {\n\t\treturn;\n\t}\n\n\tSAVE_FLAGS(flags); CLI();\n\n\tinsert_on_free_list(pg);\n\n\t/* remove all flags except PAGE_RESERVED */\n\tpg->flags &= PAGE_RESERVED;\n\n\t/* if page is not cached then place it at the head of the free list */\n\tif(!pg->inode) {\n\t\tpage_head = pg;\n\t}\n\n\tRESTORE_FLAGS(flags);\n\n\t/*\n\t * We need to wait for free pages to be far greater than NR_BUF_RECLAIM,\n\t * otherwise get_free_pages() could run out of pages _again_, and it\n\t * would think that 'definitely there are no more free pages', killing\n\t * the current process prematurely.\n\t */\n\tif(kstat.free_pages > (NR_BUF_RECLAIM * 3)) {\n\t\twakeup(&get_free_page);\n\t}\n}\n\nint is_valid_page(int page)\n{\n\treturn (page >= 0 && page < NR_PAGES);\n}\n\nvoid invalidate_inode_pages(struct inode *i)\n{\n\tstruct page *pg;\n\t__off_t offset;\n\n\tfor(offset = 0; offset < i->i_size; offset += PAGE_SIZE) {\n\t\tif((pg = search_page_hash(i, offset))) {\n\t\t\tpage_lock(pg);\n\t\t\trelease_page(pg);\n\t\t\tpage_unlock(pg);\n\t\t\tremove_from_hash(pg);\n\t\t}\n\t}\n}\n\nvoid update_page_cache(struct inode *i, __off_t offset, const char *buf, int count)\n{\n\t__off_t poffset;\n\tstruct page *pg;\n\tint bytes;\n\n\tpoffset = offset & (PAGE_SIZE - 1);\t/* mod PAGE_SIZE */\n\toffset &= PAGE_MASK;\n\tbytes = PAGE_SIZE - poffset;\n\n\tif(count) {\n\t\tbytes = MIN(bytes, count);\n\t\tif((pg = search_page_hash(i, offset))) {\n\t\t\tpage_lock(pg);\n\t\t\tmemcpy_b(pg->data + poffset, buf, bytes);\n\t\t\tpage_unlock(pg);\n\t\t\trelease_page(pg);\n\t\t}\n\t}\n}\n\nint write_page(struct page *pg, struct inode *i, __off_t offset, unsigned int length)\n{\n\tstruct fd fdt;\n\tunsigned int size;\n\tint errno;\n\n\tsize = MIN(i->i_size - offset, length);\n\tfdt.inode = i;\n\tfdt.flags = 0;\n\tfdt.count = 0;\n\tfdt.offset = offset;\n\tif(i->fsop && i->fsop->write) {\n\t\terrno = i->fsop->write(i, &fdt, pg->data, size);\n\t} else {\n\t\terrno = -EINVAL;\n\t}\n\n\treturn errno;\n}\n\nint bread_page(struct page *pg, struct inode *i, __off_t offset, char prot, char flags)\n{\n\t__blk_t block;\n\t__off_t size_read;\n\tint blksize, retval;\n\tstruct device *d;\n\tstruct blk_request brh, *br, *tmp;\n\n\tblksize = i->sb->s_blocksize;\n\tretval = size_read = 0;\n\ttmp = NULL;\n\n\tif(!(d = get_device(BLK_DEV, i->dev))) {\n\t\tprintk(\"WARNING: %s(): device major %d not found!\\n\", __FUNCTION__, MAJOR(i->dev));\n\t\treturn 1;\n\t}\n\n\tmemset_b(&brh, 0, sizeof(struct blk_request));\n\tpage_lock(pg);\n\n\t/* cache any read-only or public (shared) pages */\n\tif(!(prot & PROT_WRITE) || flags & MAP_SHARED) {\n\t\tpg->inode = i->inode;\n\t\tpg->offset = offset;\n\t\tpg->dev = i->dev;\n\t\tinsert_to_hash(pg);\n\t}\n\n\twhile(size_read < PAGE_SIZE) {\n\t\tif(!(br = (struct blk_request *)kmalloc(sizeof(struct blk_request)))) {\n\t\t\tprintk(\"WARNING: %s(): no more free memory for block requests.\\n\", __FUNCTION__);\n\t\t\tretval = 1;\n\t\t\tbreak;\n\t\t}\n\t\tif((block = bmap(i, offset + size_read, FOR_READING)) < 0) {\n\t\t\tretval = 1;\n\t\t\tbreak;\n\t\t}\n\t\tmemset_b(br, 0, sizeof(struct blk_request));\n\t\tbr->dev = i->dev;\n\t\tbr->block = block;\n\t\tbr->flags = block ? 0 : BRF_NOBLOCK;\n\t\tbr->size = blksize;\n\t\tbr->device = d;\n\t\tbr->fn = d->fsop->read_block;\n\t\tbr->head_group = &brh;\n\t\tif(!brh.next_group) {\n\t\t\tbrh.next_group = br;\n\t\t} else {\n\t\t\ttmp->next_group = br;\n\t\t}\n\t\ttmp = br;\n\t\tsize_read += blksize;\n\t}\n\tif(!retval) {\n\t\tretval = gbread(d, &brh);\n\t}\n\t/*\n\t * We must zero retval if is not negative because block drivers\n\t * that still don't use the new I/O mechanism will return the\n\t * bytes read, and this value could be interpreted below as an error.\n\t */\n\tretval = retval < 0 ? retval : 0;\n\tbr = brh.next_group;\n\tsize_read = 0;\n\twhile(br) {\n\t\tif(!retval) {\n\t\t\tif(br->block) {\n\t\t\t\tmemcpy_b(pg->data + size_read, br->buffer->data, br->size);\n\t\t\t\tbr->buffer->flags |= BUFFER_VALID;\n\t\t\t} else {\n\t\t\t\t/* fill the hole with zeros */\n\t\t\t\tmemset_b(pg->data + size_read, 0, br->size);\n\t\t\t}\n\t\t\tsize_read += br->size;\n\t\t}\n\t\tif(br->block) {\n\t\t\tbrelse(br->buffer);\n\t\t}\n\t\ttmp = br->next_group;\n\t\tkfree((unsigned int)br);\n\t\tbr = tmp;\n\t}\n\n\tpage_unlock(pg);\n\treturn retval;\n}\n\nint file_read(struct inode *i, struct fd *f, char *buffer, __size_t count)\n{\n\t__size_t total_read;\n\tunsigned int addr, poffset, bytes;\n\tstruct page *pg;\n\n\tinode_lock(i);\n\n\tif(f->offset > i->i_size) {\n\t\tf->offset = i->i_size;\n\t}\n\n\ttotal_read = 0;\n\n\tfor(;;) {\n\t\tcount = (f->offset + count > i->i_size) ? i->i_size - f->offset : count;\n\t\tif(!count) {\n\t\t\tbreak;\n\t\t}\n\n\t\tpoffset = f->offset & (PAGE_SIZE - 1);\t/* mod PAGE_SIZE */\n\t\tif(!(pg = search_page_hash(i, f->offset & PAGE_MASK))) {\n\t\t\tif(!(addr = kmalloc(PAGE_SIZE))) {\n\t\t\t\tinode_unlock(i);\n\t\t\t\tprintk(\"%s(): returning -ENOMEM\\n\", __FUNCTION__);\n\t\t\t\treturn -ENOMEM;\n\t\t\t}\n\t\t\tpg = &page_table[V2P(addr) >> PAGE_SHIFT];\n\t\t\tif(bread_page(pg, i, f->offset & PAGE_MASK, 0, MAP_SHARED)) {\n\t\t\t\tkfree(addr);\n\t\t\t\tinode_unlock(i);\n\t\t\t\tprintk(\"%s(): returning -EIO\\n\", __FUNCTION__);\n\t\t\t\treturn -EIO;\n\t\t\t}\n\t\t} else {\n\t\t\taddr = (unsigned int)pg->data;\n\t\t}\n\n\t\tpage_lock(pg);\n\t\tbytes = PAGE_SIZE - poffset;\n\t\tbytes = MIN(bytes, count);\n\t\tmemcpy_b(buffer + total_read, pg->data + poffset, bytes);\n\t\ttotal_read += bytes;\n\t\tcount -= bytes;\n\t\tf->offset += bytes;\n\t\tkfree(addr);\n\t\tpage_unlock(pg);\n\t}\n\n\tinode_unlock(i);\n\treturn total_read;\n}\n\nvoid reserve_pages(unsigned int from, unsigned int to)\n{\n\tstruct page *pg;\n\n\twhile(from < to) {\n\t\tpg = &page_table[from >> PAGE_SHIFT];\n\t\tpg->data = NULL;\n\t\tpg->flags = PAGE_RESERVED;\n\t\tkstat.physical_reserved++;\n\t\tremove_from_hash(pg);\n\t\tremove_from_free_list(pg);\n\t\tfrom += PAGE_SIZE;\n\t}\n\n\t/* recalculate */\n\tkstat.total_mem_pages = kstat.free_pages;\n\tkstat.min_free_pages = (kstat.total_mem_pages * FREE_PAGES_RATIO) / 100;\n}\n\nvoid page_init(int pages)\n{\n\tstruct page *pg;\n\tunsigned int n, addr;\n\n\tmemset_b(page_table, 0, page_table_size);\n\tmemset_b(page_hash_table, 0, page_hash_table_size);\n\n\tfor(n = 0; n < pages; n++) {\n\t\tpg = &page_table[n];\n\t\tpg->page = n;\n\n\t\taddr = n << PAGE_SHIFT;\n\t\tif(addr >= KERNEL_ADDR && addr < V2P(_last_data_addr)) {\n\t\t\tpg->flags = PAGE_RESERVED;\n\t\t\tkstat.kernel_reserved++;\n\t\t\tcontinue;\n\t\t}\n\n\t\t/* reserve the kernel stack page */\n\t\tif(addr == 0x0000F000) {\n\t\t\tpg->flags = PAGE_RESERVED;\n\t\t\tkstat.physical_reserved++;\n\t\t\tcontinue;\n\t\t}\n\n\t\t/*\n\t\t * Some memory addresses are reserved, like the memory between\n\t\t * 0xA0000 and 0x100000 and other addresses, mostly used by the\n\t\t * VGA graphics adapter and BIOS.\n\t\t */\n\t\tif(!is_addr_in_bios_map(addr)) {\n\t\t\tpg->flags = PAGE_RESERVED;\n\t\t\tkstat.physical_reserved++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tpg->data = (char *)P2V(addr);\n\t\tinsert_on_free_list(pg);\n\t}\n\n\tkstat.total_mem_pages = kstat.free_pages;\n\tkstat.min_free_pages = (kstat.total_mem_pages * FREE_PAGES_RATIO) / 100;\n}\n"
  },
  {
    "path": "mm/swapper.c",
    "content": "/*\n * fiwix/mm/swapper.c\n *\n * Copyright 2018-2022, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/asm.h>\n#include <fiwix/kernel.h>\n#include <fiwix/config.h>\n#include <fiwix/process.h>\n#include <fiwix/sleep.h>\n#include <fiwix/sched.h>\n#include <fiwix/ipc.h>\n#include <fiwix/memdev.h>\n#include <fiwix/serial.h>\n#include <fiwix/lp.h>\n#include <fiwix/ramdisk.h>\n#include <fiwix/floppy.h>\n#include <fiwix/ata.h>\n#include <fiwix/buffer.h>\n#include <fiwix/mm.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/pty.h>\n#include <fiwix/net.h>\n#include <fiwix/stdio.h>\n\n/* kswapd continues the kernel initialization */\nint kswapd(void)\n{\n\tSTI();\n\n#ifdef CONFIG_SYSVIPC\n\tipc_init();\n#endif /* CONFIG_SYSVIPC */\n\n\t/* char devices */\n\tmemdev_init();\n\tserial_init();\n\tlp_init();\n#ifdef CONFIG_UNIX98_PTYS\n\tpty_init();\n#endif /* CONFIG_UNIX98_PTYS */\n\n\t/* network */\n#ifdef CONFIG_NET\n\tnet_init();\n#endif /* CONFIG_NET */\n\n\t/* block devices */\n\tramdisk_init();\n\tfloppy_init();\n\tata_init();\n\n\t/* starting system */\n\tmem_stats();\n\tfs_init();\n\tmount_root();\n\tinit_init();\n\n\t/* make sure interrupts are enabled after initializing devices */\n\tSTI();\n\n\tfor(;;) {\n\t\tsleep(&kswapd, PROC_INTERRUPTIBLE);\n\t\tif((kstat.pages_reclaimed = reclaim_buffers())) {\n\t\t\tcontinue;\n\t\t}\n\t\twakeup(&get_free_page);\n\t}\n}\n"
  },
  {
    "path": "net/Makefile",
    "content": "# fiwix/net/Makefile\n#\n# Copyright 2023, Jordi Sanfeliu. All rights reserved.\n# Distributed under the terms of the Fiwix License.\n#\n\n.c.o:\n\t$(CC) $(CFLAGS) -c -o $@ $<\n\nOBJS = domains.o socket.o packet.o core.o unix.o ipv4.o\n\nall:\t$(OBJS)\n\nclean:\n\trm -f *.o\n\n"
  },
  {
    "path": "net/core.c",
    "content": "/*\n * fiwix/net/core.c\n *\n * Copyright 2025, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/config.h>\n#include <fiwix/errno.h>\n#include <fiwix/ioctl.h>\n#include <fiwix/fs.h>\n#include <fiwix/socket.h>\n#include <fiwix/string.h>\n\n#ifdef CONFIG_NET\nint dev_ioctl(int cmd, void *arg)\n{\n\tint n;\n\n\tswitch(cmd) {\n\t\tdefault:\n\t\t\treturn -EINVAL;\n\t}\n}\n#endif /* CONFIG_NET */\n"
  },
  {
    "path": "net/domains.c",
    "content": "/*\n * fiwix/net/domains.c\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/config.h>\n#include <fiwix/errno.h>\n#include <fiwix/net.h>\n#include <fiwix/socket.h>\n#include <fiwix/string.h>\n\n#ifdef CONFIG_NET\nstruct domain_table domains[] = {\n        { AF_UNIX, \"AF_UNIX\", &unix_ops },\n        { AF_INET, \"AF_INET\", &ipv4_ops },\n        { 0, 0, 0 }\n};\n\nstruct proto_ops unix_ops = {\n\tunix_create,\n\tunix_free,\n\tunix_bind,\n\tunix_listen,\n\tunix_connect,\n\tunix_accept,\n\tunix_getname,\n\tunix_socketpair,\n\tunix_send,\n\tunix_recv,\n\tunix_sendto,\n\tunix_recvfrom,\n\tunix_read,\n\tunix_write,\n\tunix_ioctl,\n\tunix_select,\n\tunix_shutdown,\n\tunix_setsockopt,\n\tunix_getsockopt,\n\tunix_init,\n};\n\nstruct proto_ops ipv4_ops = {\n\tipv4_create,\n\tipv4_free,\n\tipv4_bind,\n\tipv4_listen,\n\tipv4_connect,\n\tipv4_accept,\n\tipv4_getname,\n\tipv4_socketpair,\n\tipv4_send,\n\tipv4_recv,\n\tipv4_sendto,\n\tipv4_recvfrom,\n\tipv4_read,\n\tipv4_write,\n\tipv4_ioctl,\n\tipv4_select,\n\tipv4_shutdown,\n\tipv4_setsockopt,\n\tipv4_getsockopt,\n\tipv4_init,\n};\n\nint assign_proto(struct socket *so, int domain)\n{\n\tstruct domain_table *d;\n\n\td = &domains[0];\n\twhile(d->ops) {\n\t\tif(d->family == domain) {\n\t\t\tso->ops = d->ops;\n\t\t\treturn 0;\n\t\t}\n\t\td++;\n\t}\n\n\treturn -EINVAL;\n}\n\nvoid net_init(void)\n{\n\tstruct domain_table *d;\n\tstruct proto_ops *ops;\n\n\td = &domains[0];\n\twhile(d->ops) {\n\t\tops = d->ops;\n\t\tops->init();\n\t\td++;\n\t}\n\n\t/* call to the external TCP/IP API */\n\text_init();\n}\n#endif /* CONFIG_NET */\n"
  },
  {
    "path": "net/ipv4.c",
    "content": "/*\n * fiwix/net/ipv4.c\n *\n * Copyright 2025, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/config.h>\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n#include <fiwix/socket.h>\n#include <fiwix/net.h>\n#include <fiwix/net/ipv4.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/sched.h>\n#include <fiwix/sleep.h>\n#include <fiwix/mm.h>\n#include <fiwix/string.h>\n#include <fiwix/stdio.h>\n\n#ifdef CONFIG_NET\nstruct ipv4_info *ipv4_socket_head;\n\nstatic struct resource packet_resource = { 0, 0 };\n\nstatic void add_ipv4_socket(struct ipv4_info *ip4)\n{\n\tstruct ipv4_info *h;\n\n\tif((h = ipv4_socket_head)) {\n\t\twhile(h->next) {\n\t\t\th = h->next;\n\t\t}\n\t\th->next = ip4;\n\t} else {\n\t\tipv4_socket_head = ip4;\n\t}\n}\n\nstatic void remove_ipv4_socket(struct ipv4_info *ip4)\n{\n\tstruct ipv4_info *h;\n\n\tif(ipv4_socket_head == ip4) {\n\t\tipv4_socket_head = ip4->next;\n\t\treturn;\n\t}\n\n\th = ipv4_socket_head;\n\twhile(h && h->next != ip4) {\n\t\th = h->next;\n\t}\n\tif(h && h->next == ip4) {\n\t\th->next = ip4->next;\n\t}\n}\n\nint ipv4_create(struct socket *s, int domain, int type, int protocol)\n{\n\tint fd;\n\tstruct ipv4_info *ip4;\n\n\tif((fd = ext_open(domain, type, protocol)) < 0) {\n\t\treturn fd;\n\t}\n\ts->fd_ext = fd;\n\n\tip4 = &s->u.ipv4_info;\n\tmemset_b(ip4, 0, sizeof(struct ipv4_info));\n\tip4->count = 1;\n\tip4->socket = s;\n\tadd_ipv4_socket(ip4);\n\treturn fd;\n}\n\nvoid ipv4_free(struct socket *s)\n{\n\tint errno;\n\tstruct ipv4_info *ip4;\n\n\tif((errno = ext_close(s->fd_ext)) < 0) {\n\t\treturn errno;\n\t}\n\ts->fd_ext = 0;\n\tip4 = &s->u.ipv4_info;\n\tremove_ipv4_socket(ip4);\n\treturn errno;\n}\n\nint ipv4_bind(struct socket *s, const struct sockaddr *addr, int addrlen)\n{\n\treturn ext_bind(s->fd_ext, addr, addrlen);\n}\n\nint ipv4_listen(struct socket *s, int backlog)\n{\n\treturn ext_listen(s->fd_ext, backlog);\n}\n\nint ipv4_connect(struct socket *s, const struct sockaddr *addr, int addrlen)\n{\n\treturn ext_connect(s->fd_ext, addr, addrlen);\n}\n\nint ipv4_accept(struct socket *s, struct sockaddr *addr, unsigned int *addrlen)\n{\n\tint fd, ufd;\n\tstruct socket *sc;\n\tstruct ipv4_info *ip4;\n\n\tif((fd = ext_accept(s->fd_ext, addr, addrlen)) < 0) {\n\t\treturn fd;\n\t}\n\n\tsc = NULL;\n\tif((ufd = sock_alloc(&sc)) < 0) {\n\t\treturn ufd;\n\t}\n\tsc->type = s->type;\n\tsc->ops = s->ops;\n\tsc->fd_ext = fd;\n\n\tip4 = &s->u.ipv4_info;\n\tmemset_b(ip4, 0, sizeof(struct ipv4_info));\n\tip4->count = 1;\n\tip4->socket = sc;\n\tadd_ipv4_socket(ip4);\n\treturn ufd;\n}\n\nint ipv4_getname(struct socket *s, struct sockaddr *addr, unsigned int *addrlen, int call)\n{\n\treturn -EOPNOTSUPP;\n}\n\nint ipv4_socketpair(struct socket *s1, struct socket *s2)\n{\n\treturn -EOPNOTSUPP;\n}\n\nint ipv4_send(struct socket *s, struct fd *f, const char *buffer, __size_t count, int flags)\n{\n\tif(flags & ~MSG_DONTWAIT) {\n\t\treturn -EINVAL;\n\t}\n\treturn ipv4_write(s, f, buffer, count);\n}\n\nint ipv4_recv(struct socket *s, struct fd *f, char *buffer, __size_t count, int flags)\n{\n\tif(flags & ~MSG_DONTWAIT) {\n\t\treturn -EINVAL;\n\t}\n\treturn ipv4_read(s, f, buffer, count);\n}\n\nint ipv4_sendto(struct socket *s, struct fd *f, const char *buffer, __size_t count, int flags, const struct sockaddr *addr, int addrlen)\n{\n\treturn ext_sendto(s->fd_ext, buffer, count, addr, addrlen);\n}\n\nint ipv4_recvfrom(struct socket *s, struct fd *f, char *buffer, __size_t count, int flags, struct sockaddr *addr, int *addrlen)\n{\n\treturn ext_recvfrom(s->fd_ext, buffer, count, addr, addrlen);\n}\n\nint ipv4_read(struct socket *s, struct fd *f, char *buffer, __size_t count)\n{\n\treturn ext_read(s->fd_ext, buffer, count);\n}\n\nint ipv4_write(struct socket *s, struct fd *f, const char *buffer, __size_t count)\n{\n\treturn ext_write(s->fd_ext, buffer, count);\n}\n\nint ipv4_ioctl(struct socket *s, struct fd *f, int cmd, unsigned int arg)\n{\n\tint errno;\n\n\tif((errno = ext_ioctl(s->fd_ext, cmd, (void *)arg)) < 0) {\n\t\tswitch(cmd) {\n\t\t\tdefault:\n\t\t\t\terrno = dev_ioctl(cmd, (void *)arg);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\treturn errno;\n}\n\nint ipv4_select(struct socket *s, int flag)\n{\n\treturn -EOPNOTSUPP;\n}\n\nint ipv4_shutdown(struct socket *s, int how)\n{\n\treturn -EOPNOTSUPP;\n}\n\nint ipv4_setsockopt(struct socket *s, int level, int optname, const void *optval, socklen_t optlen)\n{\n\treturn -EOPNOTSUPP;\n}\n\nint ipv4_getsockopt(struct socket *s, int level, int optname, void *optval, socklen_t *optlen)\n{\n\treturn -EOPNOTSUPP;\n}\n\nint ipv4_init(void)\n{\n\tipv4_socket_head = NULL;\n\treturn 0;\n}\n#endif /* CONFIG_NET */\n"
  },
  {
    "path": "net/packet.c",
    "content": "/*\n * fiwix/net/packet.c\n *\n * Copyright 2024, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/config.h>\n#include <fiwix/net.h>\n#include <fiwix/net/packet.h>\n#include <fiwix/socket.h>\n\n#ifdef CONFIG_NET\nstruct packet *peek_packet(struct packet *queue_head)\n{\n\treturn queue_head;\n}\n\nstruct packet *remove_packet_from_queue(struct packet **queue_head)\n{\n\tstruct packet *p;\n\n\tif((p = *queue_head)) {\n\t\t*queue_head = (*queue_head)->next;\n\t}\n\n\treturn p;\n}\n\nvoid append_packet_to_queue(struct packet *p, struct packet **queue_head)\n{\n\tstruct packet *h;\n\n\tif((h = *queue_head)) {\n\t\twhile(h->next) {\n\t\t\th = h->next;\n\t\t}\n\t\th->next = p;\n\t} else {\n\t\t*queue_head = p;\n\t}\n}\n#endif /* CONFIG_NET */\n"
  },
  {
    "path": "net/socket.c",
    "content": "/*\n * fiwix/net/socket.c\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/config.h>\n#include <fiwix/asm.h>\n#include <fiwix/fs.h>\n#include <fiwix/filesystems.h>\n#include <fiwix/stat.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/net.h>\n#include <fiwix/socket.h>\n#include <fiwix/sleep.h>\n#include <fiwix/sched.h>\n#include <fiwix/errno.h>\n#include <fiwix/stdio.h>\n#include <fiwix/string.h>\n\n#ifdef __DEBUG__\n#include <fiwix/process.h>\n#endif /*__DEBUG__ */\n\n#ifdef CONFIG_NET\nstatic int check_sd(int sd)\n{\n\tstruct inode *i;\n\n\tCHECK_UFD(sd);\n\ti = fd_table[current->fd[sd]].inode;\n\tif(!i || !S_ISSOCK(i->i_mode)) {\n\t\treturn -ENOTSOCK;\n\t}\n\n\treturn 0;\n}\n\nstatic struct socket *get_socket(int fd)\n{\n\tstruct inode *i;\n\n\ti = fd_table[current->fd[fd]].inode;\n\treturn &i->u.sockfs.sock;\n}\n\nstruct socket *get_socket_from_queue(struct socket *ss)\n{\n\tunsigned int flags;\n\tstruct socket *sc;\n\n\tsc = NULL;\n\n\tSAVE_FLAGS(flags); CLI();\n\tif((sc = ss->queue_head)) {\n\t\tss->queue_head = sc->next_queue;\n\t\tss->queue_len--;\n\t}\n\tRESTORE_FLAGS(flags);\n\n\treturn sc;\n}\n\n/* append a socket to the list of pending connections */\nint insert_socket_to_queue(struct socket *ss, struct socket *sc)\n{\n\tunsigned int flags;\n\tstruct socket *s;\n\n\tif(ss->queue_len + 1 > ss->queue_limit) {\n\t\tprintk(\"WARNING: backlog exceeded!\\n\");\n\t\treturn -ECONNREFUSED;\n\t}\n\n\tSAVE_FLAGS(flags); CLI();\n\tif((s = ss->queue_head)) {\n\t\twhile(s->next_queue) {\n\t\t\ts = s->next_queue;\n\t\t}\n\t\ts->next_queue = sc;\n\t} else {\n\t\tss->queue_head = sc;\n\t}\n\tRESTORE_FLAGS(flags);\n\n\tss->queue_len++;\n\treturn 0;\n}\n\nint sock_alloc(struct socket **s)\n{\n\tint fd, ufd;\n\tstruct filesystems *fs;\n\tstruct inode *i;\n\tstruct socket *ns;\n\n\tif(!(fs = get_filesystem(\"sockfs\"))) {\n\t\tprintk(\"WARNING: %s(): sockfs filesystem is not registered!\\n\", __FUNCTION__);\n\t\treturn -EINVAL;\n\t}\n\tif(!(i = ialloc(&fs->mp->sb, S_IFSOCK))) {\n\t\treturn -EINVAL;\n\t}\n\tif((fd = get_new_fd(i)) < 0) {\n\t\tiput(i);\n\t\treturn -ENFILE;\n\t}\n\tif((ufd = get_new_user_fd(0)) < 0) {\n\t\trelease_fd(fd);\n\t\tiput(i);\n\t\treturn -EMFILE;\n\t}\n\tcurrent->fd[ufd] = fd;\n\ti = fd_table[fd].inode;\n\tns = &i->u.sockfs.sock;\n\tns->state = SS_UNCONNECTED;\n\tfd_table[fd].flags = O_RDWR;\n\tns->fd = &fd_table[fd];\n\t*s = ns;\n\treturn ufd;\n}\n\nvoid sock_free(struct socket *s)\n{\n\tint fd, ufd, n;\n\tstruct inode *i;\n\n\tufd = -1;\n\n\t/* pointer arithmetic */\n\tfd = ((unsigned int)s->fd - (unsigned int)&fd_table[0]) / sizeof(struct fd);\n\n\tfor(n = 0; n < OPEN_MAX; n++) {\n\t\tif(current->fd[n] == fd) {\n\t\t\tufd = n;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif(ufd >= 0) {\n\t\trelease_user_fd(ufd);\n\t}\n\tif(!(--fd_table[fd].count)) {\n\t\ti = s->fd->inode;\n\t\tiput(i);\n\t\trelease_fd(fd);\n\t}\n\tif(s->ops) {\n\t\ts->ops->free(s);\n\t}\n\twakeup(s);\n}\n\nint socket(int domain, int type, int protocol)\n{\n\tint ufd;\n\tstruct socket *s;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) socket(%d, %d, %d)\\n\", current->pid, domain, type, protocol);\n#endif /*__DEBUG__ */\n\n\tif(type != SOCK_STREAM && type != SOCK_DGRAM) {\n\t\treturn -EINVAL;\n\t}\n\n\ts = NULL;\n\tif((ufd = sock_alloc(&s)) < 0) {\n\t\treturn ufd;\n\t}\n\ts->type = type;\n\tif(assign_proto(s, domain)) {\n\t\tsock_free(s);\n\t\treturn -EINVAL;\n\t}\n\tif((errno = s->ops->create(s, domain, type, protocol)) < 0) {\n\t\tsock_free(s);\n\t\treturn errno;\n\t}\n\treturn ufd;\n}\n\nint bind(int sd, struct sockaddr *addr, int addrlen)\n{\n\tstruct socket *s;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) bind(%d, 0x%08x, %d)\\n\", current->pid, sd, (int)addr, addrlen);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_sd(sd)) < 0) {\n\t\treturn errno;\n\t}\n\ts = get_socket(sd);\n\tif((errno = check_user_area(VERIFY_READ, addr, addrlen))) {\n\t\treturn errno;\n\t}\n\treturn s->ops->bind(s, addr, addrlen);\n}\n\nint listen(int sd, int backlog)\n{\n\tstruct socket *ss;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) listen(%d, %d)\\n\", current->pid, sd, backlog);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_sd(sd)) < 0) {\n\t\treturn errno;\n\t}\n\tss = get_socket(sd);\n\tif(ss->type != SOCK_STREAM) {\n\t\treturn -EOPNOTSUPP;\n\t}\n\tss->flags |= SO_ACCEPTCONN;\n\tbacklog = backlog < 0 ? 0 : backlog;\n\tss->queue_limit = MIN(backlog, SOMAXCONN);\n\treturn ss->ops->listen(ss, backlog);\n}\n\nint connect(int sd, struct sockaddr *addr, int addrlen)\n{\n\tstruct socket *sc;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) connect(%d, 0x%08x, %d)\\n\", current->pid, sd, (int)addr, addrlen);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_sd(sd)) < 0) {\n\t\treturn errno;\n\t}\n\tsc = get_socket(sd);\n\tif((errno = check_user_area(VERIFY_READ, addr, addrlen))) {\n\t\treturn errno;\n\t}\n\treturn sc->ops->connect(sc, addr, addrlen);\n}\n\nint accept(int sd, struct sockaddr *addr, unsigned int *addrlen)\n{\n\tstruct socket *ss;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) accept(%d, 0x%08x, 0x%08x)\\n\", current->pid, sd, (int)addr, addrlen);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_sd(sd)) < 0) {\n\t\treturn errno;\n\t}\n\tss = get_socket(sd);\n\tif(!(ss->flags & SO_ACCEPTCONN)) {\n\t\treturn -EINVAL;\n\t}\n\tif(ss->type != SOCK_STREAM) {\n\t\treturn -EOPNOTSUPP;\n\t}\n\treturn ss->ops->accept(ss, addr, addrlen);\n}\n\nint getname(int sd, struct sockaddr *addr, unsigned int *addrlen, int call)\n{\n\tstruct socket *s;\n\tint errno;\n\n#ifdef __DEBUG__\n\tif(call == SYS_GETSOCKNAME) {\n\t\tprintk(\"(pid %d) getsockname(%d, 0x%08x, 0x%08x)\\n\", current->pid, sd, (int)addr, addrlen);\n\t} else {\n\t\tprintk(\"(pid %d) getpeername(%d, 0x%08x, 0x%08x)\\n\", current->pid, sd, (int)addr, addrlen);\n\t}\n#endif /*__DEBUG__ */\n\n\tif((errno = check_sd(sd)) < 0) {\n\t\treturn errno;\n\t}\n\ts = get_socket(sd);\n\treturn s->ops->getname(s, addr, addrlen, call);\n}\n\nint socketpair(int domain, int type, int protocol, int sockfd[2])\n{\n\tint ufd1, ufd2;\n\tstruct socket *s1, *s2;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) socketpair(%d, %d, %d, 0x%08x)\\n\", current->pid, domain, type, protocol, sockfd);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_user_area(VERIFY_WRITE, sockfd, sizeof(int) * 2))) {\n\t\treturn errno;\n\t}\n\n\t/* create first socket */\n\ts1 = NULL;\n\tif((ufd1 = sock_alloc(&s1)) < 0) {\n\t\treturn ufd1;\n\t}\n\ts1->type = type;\n\tif(assign_proto(s1, domain)) {\n\t\tsock_free(s1);\n\t\treturn -EINVAL;\n\t}\n\t/* check if socketpair() is supported by the domain */\n\tif(!s1->ops->socketpair) {\n\t\tsock_free(s1);\n\t\treturn -EINVAL;\n\t}\n\tif((errno = s1->ops->create(s1, domain, type, protocol)) < 0) {\n\t\tsock_free(s1);\n\t\treturn errno;\n\t}\n\n\t/* create second socket */\n\ts2 = NULL;\n\tif((ufd2 = sock_alloc(&s2)) < 0) {\n\t\tsock_free(s1);\n\t\treturn ufd2;\n\t}\n\ts2->type = type;\n\tassign_proto(s2, domain);\n\tif((errno = s2->ops->create(s2, domain, type, protocol)) < 0) {\n\t\tsock_free(s1);\n\t\tsock_free(s2);\n\t\treturn errno;\n\t}\n\n\tif((errno = s1->ops->socketpair(s1, s2)) < 0) {\n\t\tsock_free(s1);\n\t\tsock_free(s2);\n\t\treturn errno;\n\t}\n\n\tsockfd[0] = ufd1;\n        sockfd[1] = ufd2;\n\treturn 0;\n}\n\nint send(int sd, const void *buf, __size_t len, int flags)\n{\n\tstruct socket *s;\n\tstruct fd fdt;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) send(%d, 0x%08x, %d, %d)\\n\", current->pid, sd, (int)buf, len, flags);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_sd(sd)) < 0) {\n\t\treturn errno;\n\t}\n\ts = get_socket(sd);\n\tif((errno = check_user_area(VERIFY_READ, buf, len))) {\n\t\treturn errno;\n\t}\n\tfdt.flags = s->fd->flags | ((flags & MSG_DONTWAIT) ? O_NONBLOCK : 0);\n\treturn s->ops->send(s, &fdt, buf, len, flags);\n}\n\nint recv(int sd, void *buf, __size_t len, int flags)\n{\n\tstruct socket *s;\n\tstruct fd fdt;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) recv(%d, 0x%08x, %d, %d)\\n\", current->pid, sd, (int)buf, len, flags);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_sd(sd)) < 0) {\n\t\treturn errno;\n\t}\n\ts = get_socket(sd);\n\tif((errno = check_user_area(VERIFY_WRITE, buf, len))) {\n\t\treturn errno;\n\t}\n\tfdt.flags = s->fd->flags | ((flags & MSG_DONTWAIT) ? O_NONBLOCK : 0);\n\treturn s->ops->recv(s, &fdt, buf, len, flags);\n}\n\nint sendto(int sd, const void *buf, __size_t len, int flags, const struct sockaddr *addr, int addrlen)\n{\n\tstruct socket *s;\n\tstruct fd fdt;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) sendto(%d, 0x%08x, %d, %d, 0x%08x, %d)\\n\", current->pid, sd, (int)buf, len, flags, (int)addr, addrlen);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_sd(sd)) < 0) {\n\t\treturn errno;\n\t}\n\ts = get_socket(sd);\n\tif((errno = check_user_area(VERIFY_READ, buf, len))) {\n\t\treturn errno;\n\t}\n\tfdt.flags = s->fd->flags | ((flags & MSG_DONTWAIT) ? O_NONBLOCK : 0);\n\treturn s->ops->sendto(s, &fdt, buf, len, flags, addr, addrlen);\n}\n\nint recvfrom(int sd, void *buf, __size_t len, int flags, struct sockaddr *addr, int *addrlen)\n{\n\tstruct socket *s;\n\tstruct fd fdt;\n\tchar ret_addr[108];\n\tint errno, ret_len, bytes_read;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) recvfrom(%d, 0x%08x, %d, %d, 0x%08x, 0x%08x)\\n\", current->pid, sd, (int)buf, len, flags, (int)addr, addrlen);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_sd(sd)) < 0) {\n\t\treturn errno;\n\t}\n\ts = get_socket(sd);\n\tif((errno = check_user_area(VERIFY_WRITE, buf, len))) {\n\t\treturn errno;\n\t}\n\tfdt.flags = s->fd->flags | ((flags & MSG_DONTWAIT) ? O_NONBLOCK : 0);\n\tmemset_b(ret_addr, 0, 108);\n\tif((errno = s->ops->recvfrom(s, &fdt, buf, len, flags, (struct sockaddr *)ret_addr, &ret_len)) < 0) {\n\t\treturn errno;\n\t}\n\tbytes_read = errno;\n\tif(ret_len && addr) {\n\t\tif((errno = check_user_area(VERIFY_WRITE, addr, ret_len))) {\n\t\t\treturn errno;\n\t\t}\n\t\tmemcpy_b(addr, ret_addr, ret_len);\n\t}\n\treturn bytes_read;\n}\n\nint shutdown(int sd, int how)\n{\n\tstruct socket *s;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) shutdown(%d, %d)\\n\", current->pid, sd, how);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_sd(sd)) < 0) {\n\t\treturn errno;\n\t}\n\ts = get_socket(sd);\n\treturn s->ops->shutdown(s, how);\n}\n\nint setsockopt(int sd, int level, int optname, const void *optval, socklen_t optlen)\n{\n\tstruct socket *s;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) setsockopt(%d, %d, %d, %x, %d)\\n\", current->pid, sd, level, optname, (int)optval, optlen);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_sd(sd)) < 0) {\n\t\treturn errno;\n\t}\n\ts = get_socket(sd);\n\treturn s->ops->setsockopt(s, level, optname, optval, optlen);\n}\n\nint getsockopt(int sd, int level, int optname, void *optval, socklen_t *optlen)\n{\n\tstruct socket *s;\n\tint errno;\n\n#ifdef __DEBUG__\n\tprintk(\"(pid %d) getsockopt(%d, %d, %d, %x, %x)\\n\", current->pid, sd, level, optname, (int)optval, (int)optlen);\n#endif /*__DEBUG__ */\n\n\tif((errno = check_sd(sd)) < 0) {\n\t\treturn errno;\n\t}\n\ts = get_socket(sd);\n\treturn s->ops->getsockopt(s, level, optname, optval, optlen);\n}\n#endif /* CONFIG_NET */\n"
  },
  {
    "path": "net/unix.c",
    "content": "/*\n * fiwix/net/unix.c\n *\n * Copyright 2023, Jordi Sanfeliu. All rights reserved.\n * Portions Copyright 2024, Greg Haerr.\n * Distributed under the terms of the Fiwix License.\n */\n\n#include <fiwix/config.h>\n#include <fiwix/fs.h>\n#include <fiwix/stat.h>\n#include <fiwix/errno.h>\n#include <fiwix/socket.h>\n#include <fiwix/net.h>\n#include <fiwix/netdevice.h>\n#include <fiwix/net/unix.h>\n#include <fiwix/fcntl.h>\n#include <fiwix/sched.h>\n#include <fiwix/sleep.h>\n#include <fiwix/mm.h>\n#include <fiwix/string.h>\n#include <fiwix/stdio.h>\n\n#ifdef CONFIG_NET\nstruct unix_info *unix_socket_head;\n\nstatic struct resource packet_resource = { 0, 0 };\n\nstatic void add_unix_socket(struct unix_info *u)\n{\n\tstruct unix_info *h;\n\n\tif((h = unix_socket_head)) {\n\t\twhile(h->next) {\n\t\t\th = h->next;\n\t\t}\n\t\th->next = u;\n\t} else {\n\t\tunix_socket_head = u;\n\t}\n}\n\nstatic void remove_unix_socket(struct unix_info *u)\n{\n\tstruct unix_info *h;\n\n\tif(unix_socket_head == u) {\n\t\tunix_socket_head = u->next;\n\t\treturn;\n\t}\n\n\th = unix_socket_head;\n\twhile(h && h->next != u) {\n\t\th = h->next;\n\t}\n\tif(h && h->next == u) {\n\t\th->next = u->next;\n\t}\n}\n\nstatic struct unix_info *lookup_unix_socket(char *path, struct inode *i)\n{\n\tstruct unix_info *u;\n\n\tu = unix_socket_head;\n\twhile(u) {\n\t\tif(u->sun) {\n\t\t\tif(!strcmp(u->sun->sun_path, path) && u->inode == i) {\n\t\t\t\treturn u;\n\t\t\t}\n\t\t}\n\t\tu = u->next;\n\t}\n\n\treturn NULL;\n}\n\nint unix_create(struct socket *s, int domain, int type, int protocol)\n{\n\tstruct unix_info *u;\n\n\tu = &s->u.unix_info;\n\tmemset_b(u, 0, sizeof(struct unix_info));\n\tu->count = 1;\n\tu->socket = s;\n\tadd_unix_socket(u);\n\treturn 0;\n}\n\nvoid unix_free(struct socket *s)\n{\n\tstruct unix_info *u;\n\n\tu = &s->u.unix_info;\n\tif(!(--u->count)) {\n\t\tif(u->data) {\n\t\t\tkfree((unsigned int)u->data);\n\t\t}\n\t\tif(u->sun) {\n\t\t\tkfree((unsigned int)u->sun);\n\t\t}\n\t\tif(u->inode) {\n\t\t\tiput(u->inode);\n\t\t}\n\t\tu->peer = NULL;\n\t\tremove_unix_socket(u);\n\t\treturn;\n\t}\n\n\tif(u->peer) {\n\t\tif(!--u->peer->count) {\n\t\t\tremove_unix_socket(u->peer);\n\t\t}\n\t\tif(u->peer->socket) {\n\t\t\tu->peer->socket->state = SS_DISCONNECTING;\n\t\t}\n\t\twakeup(u->peer);\n\t\twakeup(&do_select);\n\t}\n\tremove_unix_socket(u);\n\treturn;\n}\n\nint unix_bind(struct socket *s, const struct sockaddr *addr, int addrlen)\n{\n\tstruct inode *i;\n\tstruct sockaddr_un *su;\n\tint errno;\n\n\tsu = (struct sockaddr_un *)addr;\n\tif(su->sun_family != AF_UNIX) {\n                return -EINVAL;\n\t}\n\tif(addrlen < 0 || addrlen > sizeof(struct sockaddr_un)) {\n                return -EINVAL;\n\t}\n\n\tif(s->u.unix_info.sun) {\n\t\treturn -EINVAL;\n\t}\n\tif(!(s->u.unix_info.sun = (struct sockaddr_un *)kmalloc(sizeof(struct sockaddr_un)))) {\n\t\treturn -ENOMEM;\n\t}\n\tmemset_b(s->u.unix_info.sun, 0, sizeof(struct sockaddr_un));\n\tmemcpy_b(s->u.unix_info.sun, su, addrlen);\n\ts->u.unix_info.sun_len = addrlen;\n\n\terrno = do_mknod((char *)su->sun_path, S_IFSOCK | (S_IRWXU | S_IRWXG | S_IRWXO), 0);\n\tif(errno < 0) {\n\t\tkfree((unsigned int)s->u.unix_info.sun);\n\t\ts->u.unix_info.sun = NULL;\n\t\tif(errno == -EEXIST) {\n\t\t\terrno = -EADDRINUSE;\n\t\t}\n\t\treturn errno;\n\t}\n\tif((errno = namei(su->sun_path, &i, NULL, FOLLOW_LINKS))) {\n\t\tkfree((unsigned int)s->u.unix_info.sun);\n\t\ts->u.unix_info.sun = NULL;\n\t\treturn errno;\n\t}\n\ts->u.unix_info.inode = i;\n\treturn errno;\n}\n\nint unix_listen(struct socket *s, int backlog)\n{\n\treturn 0;\n}\n\nint unix_connect(struct socket *sc, const struct sockaddr *addr, int addrlen)\n{\n\tstruct inode *i;\n\tstruct sockaddr_un *su;\n\tstruct unix_info *up;\n\tchar *tmp_name;\n\tint errno;\n\n\tsu = (struct sockaddr_un *)addr;\n\tif(su->sun_family != AF_UNIX) {\n                return -EINVAL;\n\t}\n\tif(addrlen < 0 || addrlen > sizeof(struct sockaddr_un)) {\n                return -EINVAL;\n\t}\n\n\tif((errno = malloc_name(su->sun_path, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = namei(tmp_name, &i, NULL, FOLLOW_LINKS))) {\n\t\tfree_name(tmp_name);\n\t\treturn errno;\n\t}\n\tif(!(up = lookup_unix_socket(tmp_name, i))) {\n\t\tiput(i);\n\t\tfree_name(tmp_name);\n\t\treturn -ECONNREFUSED;\n\t}\n\tiput(i);\n\tfree_name(tmp_name);\n\tif((errno = insert_socket_to_queue(up->socket, sc))) {\n\t\treturn errno;\n\t}\n\twakeup(up->socket);\n\tsleep(sc, PROC_INTERRUPTIBLE);\n\treturn 0;\n}\n\nint unix_accept(struct socket *ss, struct sockaddr *addr, unsigned int *addrlen)\n{\n\tint ufd;\n\tstruct socket *sc, *nss;\n\tstruct unix_info *uc, *us;\n\tint errno;\n\n\twhile(!(sc = get_socket_from_queue(ss))) {\n\t\tif(ss->fd->flags & O_NONBLOCK) {\n\t\t\treturn -EAGAIN;\n\t\t}\n\t\tif(sleep(ss, PROC_INTERRUPTIBLE)) {\n\t\t\treturn -EINTR;\n\t\t}\n\t}\n\n\tnss = NULL;\n\tif((ufd = sock_alloc(&nss)) < 0) {\n\t\treturn ufd;\n\t}\n\tnss->type = ss->type;\n\tnss->ops = ss->ops;\n\tif((errno = nss->ops->create(nss, 0, 0, 0)) < 0) {\n\t\tsock_free(nss);\n\t\treturn errno;\n\t}\n\n\n\tuc = &sc->u.unix_info;\n\tus = &nss->u.unix_info;\n\n\tif(!(uc->data = (char *)kmalloc(PIPE_BUF))) {\n\t\tsock_free(nss);\n\t\treturn -ENOMEM;\n\t}\n\tus->data = uc->data;\n\tus->sun = uc->sun;\n\tus->sun_len = uc->sun_len;\n\tus->peer = uc;\n\tus->count++;\n\tuc->peer = us;\t/* server socket */\n\tuc->count++;\n\tsc->state = SS_CONNECTED;\n\tnss->state = SS_CONNECTED;\n\twakeup(sc);\n\twakeup(&do_select);\n\tif(addr) {\n\t\tnss->ops->getname(nss, addr, addrlen, SYS_GETPEERNAME);\n\t}\n\treturn ufd;\n}\n\nint unix_getname(struct socket *s, struct sockaddr *addr, unsigned int *addrlen, int call)\n{\n\tstruct unix_info *u;\n\tint len, errno;\n\n\tif((errno = check_user_area(VERIFY_WRITE, addrlen, sizeof(int)))) {\n\t\treturn errno;\n\t}\n\tlen = *addrlen;\n\n\tif(call == SYS_GETSOCKNAME) {\n\t\tu = &s->u.unix_info;\n\t} else {\n\t\t/* SYS_GETPEERNAME */\n\t\tu = s->u.unix_info.peer;\n\t}\n\tif(len > u->sun_len) {\n\t\tlen = u->sun_len;\n\t}\n\tif(len) {\n\t\tif((errno = check_user_area(VERIFY_WRITE, addr, len))) {\n\t\t\treturn errno;\n\t\t}\n\t\tmemcpy_b(addr, u->sun, len);\n\t}\n\treturn 0;\n}\n\nint unix_socketpair(struct socket *s1, struct socket *s2)\n{\n\tstruct unix_info *u1, *u2;\n\n\tu1 = &s1->u.unix_info;\n\tu2 = &s2->u.unix_info;\n\n\tif(!(u1->data = (char *)kmalloc(PIPE_BUF))) {\n\t\treturn -ENOMEM;\n\t}\n\tu2->data = u1->data;\n\tu1->count++;\n\tu2->count++;\n\tu1->peer = u2;\n\tu2->peer = u1;\n\ts1->state = SS_CONNECTED;\n\ts2->state = SS_CONNECTED;\n\treturn 0;\n}\n\nint unix_send(struct socket *s, struct fd *f, const char *buffer, __size_t count, int flags)\n{\n\tif(flags & ~MSG_DONTWAIT) {\n\t\treturn -EINVAL;\n\t}\n\treturn unix_write(s, f, buffer, count);\n}\n\nint unix_recv(struct socket *s, struct fd *f, char *buffer, __size_t count, int flags)\n{\n\tif(flags & ~MSG_DONTWAIT) {\n\t\treturn -EINVAL;\n\t}\n\treturn unix_read(s, f, buffer, count);\n}\n\nint unix_sendto(struct socket *s, struct fd *f, const char *buffer, __size_t count, int flags, const struct sockaddr *addr, int addrlen)\n{\n\tstruct inode *i;\n\tstruct unix_info *u;\n\tstruct sockaddr_un *su;\n\tstruct packet *p;\n\tchar *tmp_name;\n\tint errno;\n\n\tsu = (struct sockaddr_un *)addr;\n\tif(su->sun_family != AF_UNIX) {\n                return -EINVAL;\n\t}\n\tif(addrlen < 0 || addrlen > sizeof(struct sockaddr_un)) {\n                return -EINVAL;\n\t}\n\n\tif((errno = malloc_name(su->sun_path, &tmp_name)) < 0) {\n\t\treturn errno;\n\t}\n\tif((errno = namei(tmp_name, &i, NULL, FOLLOW_LINKS))) {\n\t\tfree_name(tmp_name);\n\t\treturn errno;\n\t}\n\tif(!(u = lookup_unix_socket(tmp_name, i))) {\n\t\tiput(i);\n\t\tfree_name(tmp_name);\n\t\treturn -ECONNREFUSED;\n\t}\n\tiput(i);\n\tfree_name(tmp_name);\n\n\tif(!(p = (struct packet *)kmalloc(sizeof(struct packet)))) {\n\t\treturn -ENOMEM;\n\t}\n\tmemset_b(p, 0, sizeof(struct packet));\n\tif(!(p->data = (char *)kmalloc(count + 1))) {\n\t\tkfree((unsigned int)p);\n\t\treturn -ENOMEM;\n\t}\n\tmemset_b(p->data, 0, count + 1);\n\tmemcpy_b(p->data, buffer, count);\n\tp->len = count;\n\tp->socket = s;\n\tlock_resource(&packet_resource);\n\tappend_packet_to_queue(p, &u->packet_queue);\n\tunlock_resource(&packet_resource);\n\twakeup(u);\n\treturn count;\n}\n\nint unix_recvfrom(struct socket *s, struct fd *f, char *buffer, __size_t count, int flags, struct sockaddr *addr, int *addrlen)\n{\n\tstruct unix_info *u, *up;\n\tstruct sockaddr_un *sun;\n\tstruct packet *p;\n\tint size;\n\n\tu = &s->u.unix_info;\n\n\tlock_resource(&packet_resource);\n\twhile(!(p = peek_packet(u->packet_queue))) {\n\t\tunlock_resource(&packet_resource);\n\t\tif(!(f->flags & O_NONBLOCK)) {\n\t\t\tif(sleep(u, PROC_INTERRUPTIBLE)) {\n\t\t\t\treturn -EINTR;\n\t\t\t}\n\t\t\tlock_resource(&packet_resource);\n\t\t} else {\n\t\t\tunlock_resource(&packet_resource);\n\t\t\treturn -EAGAIN;\n\t\t}\n\t}\n\n\tsize = MIN(p->len - p->offset, count);\n\tmemcpy_b(buffer, p->data + p->offset, size);\n\tp->offset += size;\n\tif(!(flags & MSG_PEEK)) {\n\t\tp = remove_packet_from_queue(&u->packet_queue);\n\t\tkfree((unsigned int)p->data);\n\t\tkfree((unsigned int)p);\n\t}\n\tunlock_resource(&packet_resource);\n\n\tup = &p->socket->u.unix_info;\n\tsun = (struct sockaddr_un *)addr;\n\tsun->sun_family = AF_UNIX;\n\tmemcpy_b(sun->sun_path, up->sun->sun_path, up->sun_len);\n\t*addrlen = up->sun_len;\n\treturn size;\n}\n\nint unix_read(struct socket *s, struct fd *f, char *buffer, __size_t count)\n{\n\tstruct unix_info *u;\n\tint bytes_read;\n\tint n, limit;\n\n\tu = &s->u.unix_info;\n\tbytes_read = 0;\n\n\twhile(count) {\n\t\tif(u->writeoff) {\n\t\t\tif(u->readoff >= u->writeoff) {\n\t\t\t\tlimit = PIPE_BUF - u->readoff;\n\t\t\t} else {\n\t\t\t\tlimit = u->writeoff - u->readoff;\n\t\t\t}\n\t\t} else {\n\t\t\tlimit = PIPE_BUF - u->readoff;\n\t\t}\n\t\tn = MIN(limit, count);\n\t\tif(u->size && n) {\n\t\t\tmemcpy_b(buffer + bytes_read, u->data + u->readoff, n);\n\t\t\tbytes_read += n;\n\t\t\tu->readoff += n;\n\t\t\tu->size -= n;\n\t\t\tcount -= n;\n\t\t\tif(u->writeoff == PIPE_BUF) {\n\t\t\t\tu->writeoff = 0;\n\t\t\t}\n\t\t\twakeup(u->peer);\n\t\t\twakeup(&do_select);\n\t\t} else {\n\t\t\tif(s->state != SS_CONNECTED) {\n\t\t\t\tif(s->state == SS_DISCONNECTING) {\n\t\t\t\t\tif(u->size) {\n\t\t\t\t\t\tif(u->readoff == PIPE_BUF) {\n\t\t\t\t\t\t\tu->readoff = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\treturn bytes_read;\n\t\t\t\t}\n\t\t\t\treturn -EINVAL;\n\t\t\t}\n\t\t\tif(u->writeoff) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif(f->flags & O_NONBLOCK) {\n\t\t\t\treturn -EAGAIN;\n\t\t\t}\n\t\t\tif(sleep(u, PROC_INTERRUPTIBLE)) {\n\t\t\t\treturn -EINTR;\n\t\t\t}\n\t\t}\n\t}\n\tif(!u->size) {\n\t\tu->readoff = u->writeoff = 0;\n\t}\n\treturn bytes_read;\n}\n\nint unix_write(struct socket *s, struct fd *f, const char *buffer, __size_t count)\n{\n\tstruct unix_info *u, *up;\n\tint bytes_written;\n\tint n, limit;\n\n\tu = &s->u.unix_info;\n\tup = s->u.unix_info.peer;\n\tbytes_written = 0;\n\n\twhile(bytes_written < count) {\n\t\tif(s->state != SS_CONNECTED) {\n\t\t\tif(s->state == SS_DISCONNECTING) {\n\t\t\t\tsend_sig(current, SIGPIPE);\n\t\t\t\treturn -EPIPE;\n\t\t\t}\n\t\t\treturn -EINVAL;\n\t\t}\n\t\tif(up->readoff) {\n\t\t\tif(up->writeoff <= up->readoff) {\n\t\t\t\tlimit = up->readoff;\n\t\t\t} else {\n\t\t\t\tlimit = PIPE_BUF;\n\t\t\t}\n\t\t} else {\n\t\t\tlimit = PIPE_BUF;\n\t\t}\n\n\t\tn = MIN((count - bytes_written), (limit - up->writeoff));\n\n\t\tif(n && n <= PIPE_BUF) {\n\t\t\tmemcpy_b(up->data + up->writeoff, buffer + bytes_written, n);\n\t\t\tbytes_written += n;\n\t\t\tup->writeoff += n;\n\t\t\tup->size += n;\n\t\t\tif(up->readoff == PIPE_BUF) {\n\t\t\t\tup->readoff = 0;\n\t\t\t}\n\t\t\twakeup(u->peer);\n\t\t\twakeup(&do_select);\n\t\t\tcontinue;\n\t\t}\n\t\twakeup(u->peer);\n\t\twakeup(&do_select);\n\t\tif(!(f->flags & O_NONBLOCK)) {\n\t\t\tif(sleep(u, PROC_INTERRUPTIBLE)) {\n\t\t\t\treturn -EINTR;\n\t\t\t}\n\t\t} else {\n\t\t\treturn -EAGAIN;\n\t\t}\n\t}\n\treturn bytes_written;\n}\n\nint unix_ioctl(struct socket *s, struct fd *f, int cmd, unsigned int arg)\n{\n\tint errno;\n\n\tswitch(cmd) {\n\t\tdefault:\n\t\t\terrno = dev_ioctl(cmd, (void *)arg);\n\t\t\tbreak;\n\t}\n\treturn errno;\n}\n\nint unix_select(struct socket *s, int flag)\n{\n\tstruct unix_info *u, *up;\n\n\tif(s->flags & SO_ACCEPTCONN) {\n\t\tif (flag == SEL_R && s->queue_len) {\n\t\t\treturn 1;\n\t\t}\n\t\treturn 0;\n\t}\n\n\tu = &s->u.unix_info;\n\tup = s->u.unix_info.peer;\n\n\tswitch(flag) {\n\t\tcase SEL_R:\n\t\t\tif(u->size) {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tif(s->state != SS_CONNECTED) {\n\t\t\t\tprintk(\"UNIX: select: socket not connected (read EOF)\\n\");\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase SEL_W:\n\t\t\tif(s->state != SS_CONNECTED) {\n\t\t\t\tprintk(\"UNIX: select: socket not connected (write EOF)\\n\");\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tif(up->size < PIPE_BUF) {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tbreak;\n\t}\n\treturn 0;\n}\n\nint unix_shutdown(struct socket *s, int how)\n{\n\treturn -EOPNOTSUPP;\n}\n\nint unix_setsockopt(struct socket *s, int level, int optname, const void *optval, socklen_t optlen)\n{\n\treturn -EOPNOTSUPP;\n}\n\nint unix_getsockopt(struct socket *s, int level, int optname, void *optval, socklen_t *optlen)\n{\n\treturn -EOPNOTSUPP;\n}\n\nint unix_init(void)\n{\n\tunix_socket_head = NULL;\n\treturn 0;\n}\n#endif /* CONFIG_NET */\n"
  },
  {
    "path": "shell.nix",
    "content": "with import <nixpkgs> { };\n\npkgsCross.i686-embedded.stdenv.mkDerivation {\n  name = \"env\";\n}\n\n"
  }
]