From cb6bd3914c173af8048db5e98f66c12a27b8c4d1 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Mon, 28 Feb 2022 15:10:25 -0500 Subject: [PATCH] Remove HOS v0.16 sources --- .bochsrc | 43 - .gitignore | 6 - apps/Makefile | 5 - apps/hash/Makefile | 3 - apps/hash/hash | 1 - apps/hash/hash.asm | 6 - apps/test1.app | Bin 40 -> 0 bytes apps/test1.asm | 20 - apps/test1.lst | 22 - apps/test2.app | Bin 15 -> 0 bytes apps/test2.asm | 17 - build.txt | 2 - e2fs | Bin 16777216 -> 0 bytes grub.flp | Bin 1474560 -> 0 bytes initrd/bin/init | Bin 40 -> 0 bytes initrd/link | 1 - initrd/ulab | 46 - kernel/Makefile | 129 --- kernel/Makefile.bak | 123 --- kernel/block/ramdisk.cpp | 91 -- kernel/block/ramdisk.h | 38 - kernel/block/ramdisk_old.c | 100 -- kernel/block/ramdisk_old.h | 25 - kernel/boot.asm | 236 ----- kernel/char/keyboard.c | 151 --- kernel/char/keyboard.h | 36 - kernel/char/misc_char.cpp | 44 - kernel/char/misc_char.h | 31 - kernel/char/mouse.c | 52 -- kernel/char/mouse.h | 15 - kernel/char/vconsole.cpp | 274 ------ kernel/char/vconsole.h | 76 -- kernel/devices.cpp | 65 -- kernel/devices.h | 58 -- kernel/display/display.c | 75 -- kernel/display/display.h | 28 - kernel/display/kout.c | 141 --- kernel/display/kout.h | 20 - kernel/display/vesafb.c | 111 --- kernel/display/vesafb.h | 25 - kernel/fs/FileSystem.cpp | 21 - kernel/fs/FileSystem.h | 35 - kernel/fs/OpenDirectory.cpp | 15 - kernel/fs/OpenDirectory.h | 23 - kernel/fs/OpenFile.cpp | 13 - kernel/fs/OpenFile.h | 23 - kernel/fs/VFSMount.cpp | 39 - kernel/fs/VFSMount.h | 31 - kernel/fs/ext2/Ext2BlockCache.cpp | 143 --- kernel/fs/ext2/Ext2BlockCache.h | 34 - kernel/fs/ext2/Ext2OpenDirectory.cpp | 238 ----- kernel/fs/ext2/Ext2OpenDirectory.h | 37 - kernel/fs/ext2/Ext2OpenFile.cpp | 228 ----- kernel/fs/ext2/Ext2OpenFile.h | 47 - kernel/fs/ext2/ext2.cpp | 599 ------------ kernel/fs/ext2/ext2.h | 204 ----- kernel/fs/ext2/ext2_old.c | 762 --------------- kernel/fs/ext2/ext2_old.h | 241 ----- kernel/fs/ext2/ext2_working.c | 332 ------- kernel/fs/ext2/ext2_working.h | 241 ----- kernel/fs/sysfs/sysfs.cpp | 42 - kernel/fs/sysfs/sysfs.h | 37 - kernel/fs/sysfs/sysfs_entry.cpp | 20 - kernel/fs/sysfs/sysfs_entry.h | 30 - kernel/fs/vfs.cpp | 413 --------- kernel/fs/vfs.h | 129 --- kernel/fs/vfs_old.cpp | 432 --------- kernel/fs/vfs_old.h | 165 ---- kernel/functions.h | 111 --- kernel/gdt.inc | 57 -- kernel/hos_defines.h | 58 -- kernel/idt.inc | 117 --- kernel/kernel.c | 288 ------ kernel/kernel.h | 53 -- kernel/lang/conv.c | 109 --- kernel/lang/conv.h | 20 - kernel/lang/lang.asm | 362 -------- kernel/lang/lang.c | 114 --- kernel/lang/lang.h | 43 - kernel/lang/new.cpp | 25 - kernel/lang/string.cpp | 258 ------ kernel/lang/string.h | 110 --- kernel/lang/vector.h | 147 --- kernel/link.ld | 26 - kernel/mm/mm.c | 155 ---- kernel/mm/mm.h | 27 - kernel/mm/vmm.c | 528 ----------- kernel/mm/vmm.h | 58 -- kernel/module.h | 16 - kernel/multiboot.h | 145 --- kernel/proc/hash.cpp | 117 --- kernel/proc/hash.h | 58 -- kernel/proc/proc.cpp | 214 ----- kernel/proc/proc.h | 91 -- kernel/sys/cmos.c | 42 - kernel/sys/cmos.h | 18 - kernel/sys/io.h | 59 -- kernel/sys/pci.cpp | 59 -- kernel/sys/pci.h | 75 -- kernel/sys/pci_classes.c | 112 --- kernel/sys/pic.c | 30 - kernel/sys/pic.h | 65 -- kernel/sys/rtc.c | 83 -- kernel/sys/rtc.h | 28 - kernel/syscall.c | 25 - kernel/syscall.h | 14 - kernel/vmm.S | 1272 -------------------------- menu.lst | 9 - rmmod/Makefile | 9 - rmmod/conio.inc | 209 ----- rmmod/rmmod.asm | 325 ------- rmmod/rmmod.inc | 53 -- rmmod/vesa.inc | 85 -- 113 files changed, 12569 deletions(-) delete mode 100644 .bochsrc delete mode 100644 apps/Makefile delete mode 100644 apps/hash/Makefile delete mode 100644 apps/hash/hash delete mode 100644 apps/hash/hash.asm delete mode 100644 apps/test1.app delete mode 100644 apps/test1.asm delete mode 100644 apps/test1.lst delete mode 100644 apps/test2.app delete mode 100644 apps/test2.asm delete mode 100644 build.txt delete mode 100644 e2fs delete mode 100644 grub.flp delete mode 100644 initrd/bin/init delete mode 120000 initrd/link delete mode 100644 initrd/ulab delete mode 100644 kernel/Makefile delete mode 100644 kernel/Makefile.bak delete mode 100644 kernel/block/ramdisk.cpp delete mode 100644 kernel/block/ramdisk.h delete mode 100644 kernel/block/ramdisk_old.c delete mode 100644 kernel/block/ramdisk_old.h delete mode 100644 kernel/boot.asm delete mode 100644 kernel/char/keyboard.c delete mode 100644 kernel/char/keyboard.h delete mode 100644 kernel/char/misc_char.cpp delete mode 100644 kernel/char/misc_char.h delete mode 100644 kernel/char/mouse.c delete mode 100644 kernel/char/mouse.h delete mode 100644 kernel/char/vconsole.cpp delete mode 100644 kernel/char/vconsole.h delete mode 100644 kernel/devices.cpp delete mode 100644 kernel/devices.h delete mode 100644 kernel/display/display.c delete mode 100644 kernel/display/display.h delete mode 100644 kernel/display/kout.c delete mode 100644 kernel/display/kout.h delete mode 100644 kernel/display/vesafb.c delete mode 100644 kernel/display/vesafb.h delete mode 100644 kernel/fs/FileSystem.cpp delete mode 100644 kernel/fs/FileSystem.h delete mode 100644 kernel/fs/OpenDirectory.cpp delete mode 100644 kernel/fs/OpenDirectory.h delete mode 100644 kernel/fs/OpenFile.cpp delete mode 100644 kernel/fs/OpenFile.h delete mode 100644 kernel/fs/VFSMount.cpp delete mode 100644 kernel/fs/VFSMount.h delete mode 100644 kernel/fs/ext2/Ext2BlockCache.cpp delete mode 100644 kernel/fs/ext2/Ext2BlockCache.h delete mode 100644 kernel/fs/ext2/Ext2OpenDirectory.cpp delete mode 100644 kernel/fs/ext2/Ext2OpenDirectory.h delete mode 100644 kernel/fs/ext2/Ext2OpenFile.cpp delete mode 100644 kernel/fs/ext2/Ext2OpenFile.h delete mode 100644 kernel/fs/ext2/ext2.cpp delete mode 100644 kernel/fs/ext2/ext2.h delete mode 100644 kernel/fs/ext2/ext2_old.c delete mode 100644 kernel/fs/ext2/ext2_old.h delete mode 100644 kernel/fs/ext2/ext2_working.c delete mode 100644 kernel/fs/ext2/ext2_working.h delete mode 100644 kernel/fs/sysfs/sysfs.cpp delete mode 100644 kernel/fs/sysfs/sysfs.h delete mode 100644 kernel/fs/sysfs/sysfs_entry.cpp delete mode 100644 kernel/fs/sysfs/sysfs_entry.h delete mode 100644 kernel/fs/vfs.cpp delete mode 100644 kernel/fs/vfs.h delete mode 100644 kernel/fs/vfs_old.cpp delete mode 100644 kernel/fs/vfs_old.h delete mode 100644 kernel/functions.h delete mode 100644 kernel/gdt.inc delete mode 100644 kernel/hos_defines.h delete mode 100644 kernel/idt.inc delete mode 100644 kernel/kernel.c delete mode 100644 kernel/kernel.h delete mode 100644 kernel/lang/conv.c delete mode 100644 kernel/lang/conv.h delete mode 100644 kernel/lang/lang.asm delete mode 100644 kernel/lang/lang.c delete mode 100644 kernel/lang/lang.h delete mode 100644 kernel/lang/new.cpp delete mode 100644 kernel/lang/string.cpp delete mode 100644 kernel/lang/string.h delete mode 100644 kernel/lang/vector.h delete mode 100644 kernel/link.ld delete mode 100644 kernel/mm/mm.c delete mode 100644 kernel/mm/mm.h delete mode 100644 kernel/mm/vmm.c delete mode 100644 kernel/mm/vmm.h delete mode 100644 kernel/module.h delete mode 100644 kernel/multiboot.h delete mode 100644 kernel/proc/hash.cpp delete mode 100644 kernel/proc/hash.h delete mode 100644 kernel/proc/proc.cpp delete mode 100644 kernel/proc/proc.h delete mode 100644 kernel/sys/cmos.c delete mode 100644 kernel/sys/cmos.h delete mode 100644 kernel/sys/io.h delete mode 100644 kernel/sys/pci.cpp delete mode 100644 kernel/sys/pci.h delete mode 100644 kernel/sys/pci_classes.c delete mode 100644 kernel/sys/pic.c delete mode 100644 kernel/sys/pic.h delete mode 100644 kernel/sys/rtc.c delete mode 100644 kernel/sys/rtc.h delete mode 100644 kernel/syscall.c delete mode 100644 kernel/syscall.h delete mode 100644 kernel/vmm.S delete mode 100644 menu.lst delete mode 100644 rmmod/Makefile delete mode 100644 rmmod/conio.inc delete mode 100644 rmmod/rmmod.asm delete mode 100644 rmmod/rmmod.inc delete mode 100644 rmmod/vesa.inc diff --git a/.bochsrc b/.bochsrc deleted file mode 100644 index a6cc73d..0000000 --- a/.bochsrc +++ /dev/null @@ -1,43 +0,0 @@ -# configuration file generated by Bochs -config_interface: textconfig -display_library: x -megs: 32 -romimage: file=/usr/share/bochs/BIOS-bochs-latest, address=0xf0000 -vgaromimage: /usr/share/bochs/VGABIOS-lgpl-latest -boot: floppy -floppya: 1_44="hos.flp", status=inserted -# no floppyb -ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 -ata1: enabled=0 -ata2: enabled=0 -ata3: enabled=0 -parport1: enabled=1, file="parallel.out" -com1: enabled=1, dev="" -usb1: enabled=1, ioaddr=0xff80, irq=10 -# no sb16 -floppy_bootsig_check: disabled=0 -vga_update_interval: 30000 -keyboard_serial_delay: 20000 -keyboard_paste_delay: 100000 -floppy_command_delay: 50000 -ips: 500000 -text_snapshot_check: 0 -mouse: enabled=0 -private_colormap: enabled=0 -i440fxsupport: enabled=1 -clock: sync=realtime, time0=local -# no ne2k -#newharddrivesupport: enabled=1 -# no loader -log: - -logprefix: %t%e%d -debugger_log: - -panic: action=ask -error: action=report -info: action=report -debug: action=ignore -pass: action=fatal -keyboard_mapping: enabled=0, map= -keyboard_type: mf -user_shortcut: keys=ctrlaltdel -# no cmosimage diff --git a/.gitignore b/.gitignore index 671566f..2e145c0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,3 @@ -/hos.flp -/hos_initrd -/hos_initrd.gz -*.lst -*.map -*.bin .rscons* /i686-elf-gcc/ /build/ diff --git a/apps/Makefile b/apps/Makefile deleted file mode 100644 index b763425..0000000 --- a/apps/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -all: - make -C hash - nasm -f bin -l test1.lst test1.asm -o test1.app - nasm -f bin test2.asm -o test2.app - diff --git a/apps/hash/Makefile b/apps/hash/Makefile deleted file mode 100644 index 8a50d56..0000000 --- a/apps/hash/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -all: - nasm -f bin hash.asm -o hash - diff --git a/apps/hash/hash b/apps/hash/hash deleted file mode 100644 index bb3fd53..0000000 --- a/apps/hash/hash +++ /dev/null @@ -1 +0,0 @@ -Í0Ã \ No newline at end of file diff --git a/apps/hash/hash.asm b/apps/hash/hash.asm deleted file mode 100644 index 46f1328..0000000 --- a/apps/hash/hash.asm +++ /dev/null @@ -1,6 +0,0 @@ - -[bits 32] - -begin: - int 0x30 - ret diff --git a/apps/test1.app b/apps/test1.app deleted file mode 100644 index f5306369ddbf842cd1aa31a0e96475b563ec6856..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40 ucmdnZ&%nU2g9%8SHF*8$ut#c6PQF4(Mru*2LRwLNu0ly_afzWK7XttjW({5d diff --git a/apps/test1.asm b/apps/test1.asm deleted file mode 100644 index dee5ccc..0000000 --- a/apps/test1.asm +++ /dev/null @@ -1,20 +0,0 @@ -; test app 1 - -[bits 32] -org 0x0 - -;header: -; dd 0x4D534F48 ; magic identifier "HOSM" -; dd 2 ; test app -; dd start ; start address -; dd 0 ; reserved - -start: - mov ebx, astring - mov eax, 2 - int 0x30 - jmp start - ret - -astring: - db "Hello there from test1!", 10, 0 diff --git a/apps/test1.lst b/apps/test1.lst deleted file mode 100644 index 6fe7001..0000000 --- a/apps/test1.lst +++ /dev/null @@ -1,22 +0,0 @@ - 1 ; test app 1 - 2 - 3 [bits 32] - 4 org 0x0 - 5 - 6 ;header: - 7 ; dd 0x4D534F48 ; magic identifier "HOSM" - 8 ; dd 2 ; test app - 9 ; dd start ; start address - 10 ; dd 0 ; reserved - 11 - 12 start: - 13 00000000 BB[0F000000] mov ebx, astring - 14 00000005 B802000000 mov eax, 2 - 15 0000000A CD30 int 0x30 - 16 0000000C EBF2 jmp start - 17 0000000E C3 ret - 18 - 19 astring: - 20 0000000F 48656C6C6F20746865- db "Hello there from test1!", 10, 0 - 21 00000018 72652066726F6D2074- - 22 00000021 65737431210A00 diff --git a/apps/test2.app b/apps/test2.app deleted file mode 100644 index 3eaa9116ddab0d5f9ffa04e7d6b1147a316ae956..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15 VcmdnN$iTp`I}=EpHF*8$FaRJ81$zJh diff --git a/apps/test2.asm b/apps/test2.asm deleted file mode 100644 index 5bd78bb..0000000 --- a/apps/test2.asm +++ /dev/null @@ -1,17 +0,0 @@ -; test app 1 - -[bits 32] -org 0x0 - -;header: -; dd 0x4D534F48 ; magic identifier "HOSM" -; dd 2 ; test app -; dd start ; start address -; dd 0 ; reserved - -start: - mov eax, 1 - mov ebx, 'i' - int 0x30 - jmp start - ret diff --git a/build.txt b/build.txt deleted file mode 100644 index dc1841a..0000000 --- a/build.txt +++ /dev/null @@ -1,2 +0,0 @@ -To build the HOS kernel, just run 'make' -To build a HOS floppy image for bochs, run 'make initrd' and 'make install_img' as root (root permissions needed to mount floppy image) diff --git a/e2fs b/e2fs deleted file mode 100644 index ad150baf21406b1434e74bc47c9af13c9f6e106e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16777216 zcmeF$y=oLu6ae6}Ke}s@1v`rfNiS?~l|&INL_}Y}BHBa@_|sVU6n3_Ppdg4~BZwg6 zNi5QY6q-)Zb2AQ%%A_zV?Cf{p?47xHhne#Yb5C(2Gy(+XR$x6dU#+s=Uye9ftB!lw zm59?nVzrz^Y+ZYEG2%?z*zXU~( z{ij!tZe4i$^2NvHcjvEP={N3F<<%H)NMH^G$~Q2`7-oE)9IQ0IiIRRlzyCqTFyrf_ zUMb3qMt}eT0t5)ms=&A7wv}1U+;bO!Erv)IkCS=2c)uS1pfCfWTi6 zsMo!+|5Zml_CNZ)jom?vt9`}h{Wo)0qU=f3ZTRcPL_MJ=K!Cs>3Vhhe3)g>Ne{$#Z zr_Ih2x&EBY7-ftzPGu})EM_caXaoolAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PDa*6JaTOG0na@?#DDw7V~^}v=Dc;?>{(qd;8(tObqxO4G;en67zJS%3IHgyU5f{B=s8@S zoxFpW@JJRqx(F^_#T$rQq5ddB_PWHrz=x0!lK%qvx!#B4VSDaRxAkSS-&NV(pS-dG zT>=CM5Fqf!0;vYp5lzISeRg?GOlen9|Lce*Vr;)Zg*2lPAV7cs0Rp88Of%c6)Wn_p zEim)?Ehj*L0D(dUltBUnmMc)`v*p+X2>d``xi6p02@oJafB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t8;|(6Imj006)sf9px?EQAagFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA mz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#rj)4H}!NZ3D diff --git a/grub.flp b/grub.flp deleted file mode 100644 index 31e71d965d79f8cd3c3010c723965de3f8ac3e2e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1474560 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 z5l{pa0YyL&Py`eKML-cy1QY>9KoL*`6ahs*5l{pa0YyL&Py`eKML-cy1QY>9KoL*` z6ahs*5l{pa0YyL&Py`eKML-cy1QY>9KoL*`6ahs*5l{pa0YyL&Py`eKML-cy1QY>9 zKoL*`6ahs*5l{pa0YyL&Py`eKML-cy1QY>9KoL*`6ahs*5l{pa0YyL&Py`eKML-cy z1QY>9KoL*`6ahs*5l{pa0YyL&Py`eKML-cy1QY>9KoL*`6ahs*5l{pa0YyL&Py`eK zML-cy1QY>9KoL*`6ahs*5l{pa0YyL&Py`eKML-cy1QY>9KoL*`6ahs*5l{pa0YyL& zPy`eKML-cy1QY>9KoL*`6ahs*5l{pa0YyL&Py`eKML-cy1QY>9KoL*`6ahs*5l{pa z0YyL&Py`eKML-cy1QY>9KoL*`6ahs*5l{pa0YyL&Py`eKML-cy1QY>9KoL*`6ahs* z5l{pa0YyL&Py`eKML-cy1QY>9KoL*`6ahs*5l{pa0YyL&Py`eKML-cy1QY>9KoL*` z6ahs*5l{pa0YyL&Py`eKML-cy1QY>9KoL*`6ahs*5l{pa0YyL&Py`eKML-cy1QY>9 zKoL*`6ahs*5l{pa0YyL&Py`eKML-cy1QY>9KoL*`6ahs*5l{pa0YyL&Py`eKML-cy z1QY>9KoL*`6ahs*5l{pa0YyL&Py`eKML-cy1QY>9KoL*`6ahs*5l{pa0YyL&Py`eK zML-cy1QY>9KoL*`6ahs*5l{pa0YyL&Py`eKML-cy1QY>9KoL*`6ahs*5l{pa0YyL& zPy`eKML-cy1QY>9KoL*`6ahs*5l{pa0YyL&Py`eKML-cy1QY>9KoL*`6ahs*5l{pa z0YyL&Py`eKML-cy1QY>9KoL*`6ahs*5l{pa0YyL&Py`eKML-cy1QY>9KoL*`6ahs* z5l{pa0YyL&Py`eKML-cy1QY>9KoL*`6ahs*5l{pa0YyL&Py`eKML-cy1QY>9KoL*` z6ahs*5l{pa0YyL&Py`eKML-cy1QY>9KoL*`6ahs*5l{pa0YyL&Py`eKML-cy1QY>9 zKoL*`6ahs*5l{pa0YyL&Py`eKML-cy1QY>9KoL*`6ahs*5l{pa0YyL&Py`eKML-cy z1QY>9KoL*`6ahs*5l{pa0YyL&Py`eKML-cy1QY>9KoL*`6ahs*5l{pa0YyL&Py`eK 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ⅅciO!my= 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⪼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 z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmdXNyuhlpPmj4`=&Fi4|K{Ws z?Ss?%cT~Ch-GAqHet6jB-`zg=_V!u(KYh=fRMkCW22)j2Q&sI1)d#B@+(2_>`@s8a z4mO|TdRJ z|Jesp=iGkaaCJrMoDJ_daJXvVz^vg}KYZYur+)C*1NglWucSs;@8G=RRNI9zXxZhDG;Py~`E;{n`IK`TsBWtn{gfD!asdO`&=3L|Sc6i3dY&Jimqpz@WhNqeRe{>CkH?ysNJuc<$px&PD;J~{M)5^8f|;uMaOS(ZgAP8x}o>#ZTrBB z9qq%@ZMPqHwAWW$)T^cXXn%YE3l;Sf_qTuV;wzo2aqUkwIHhy{1BV|Ndf?Dt)ucx) zm5)raqdhn9#YgPjK-HvK`=5=Y7&!c>eVAclb?zypL#& zlI2-Sv#0&Xdif9pBxy{#dYAmHFftDYKHFDneRREz&BpJaPPNmr}m+1 zY|WuN*V|4lx7luczj$A2!v4dR?FWV`_a3;fFkbt%53Y~y%hcSLx~zTR;LsxNV^`JF zW8A>W7ca~;?0s$4{ueL2wf{|*ubTPIqu*;E`sX(l?JIZQwJt<_-mk1u)P zn>qs>)XtzU94g-DHrvQzdA#Pu3wOU>82iHmHx()$->~7GW@xj!I zfz<2!QYVI8|BmD5-aW4ViPZ7Esn>Rv6z;h z99TXwrqrv0iaT{`&;G(gigU?8N>S^;#|Bf!Z%iHAT6uJ;mg=8&1F4}wJM6LgC*0o3 z!8LkK4ehPmmpVRNvoCdQ*d2XQ`^RTe^PnQxd4nrd9=%XYwtLm2;Z)7gPb7HswRo!~ z`}`>$Oua18VVz6AtFo=1aN2Zl>IW*il}FP%cl@9+e}4VbsUIkgq0dJ{7lA(f%$or~YC)M1bAi&Ha2kq+uK&EJ?0 zrcPKk984XzcY~=@J8zg-xI(WthtnDQidOfZ+*TO3FLkQlRciYNt zF#C5LJ9opzt`F(!3vAazoy8FojuC^8icSBSU2xNQ52 z2iMdnl>^GfI_)~3qz_pF22(?^MOFWfnw#&wK)>I2&v|m`-yaF)=s8-{tM)D1F3OMB zcIW2L*Y9!p8vU+SW}JI4b;{yAI#vsMHNbc$ze%A^7r;2J9~x3hEnel$TTTrRCox+I zQuWx{xTgrzOw5d+F$>~ zeqRgs9}}i{P7W@w8(4m#blNwj8a`Zk^liHSWH7k=MEw(0HG|7f?yaizS#|VPf6BM5 z?LQV-1)#!e@rYx-PG-;k{Bpg$F;$m)`{441!9v~Ojv95S23}C*FmPO#>ws#9V@Idh zhpC1!sk(i=;?zRTzHP%l{lR0WMr|1F;> zb@eDg(cqefeW`}wnmu2+r}F4qtSCLB+Mv#A1C_m_hesacq#eUwQYvh!8bjT; zOsb)JSUGjz%FvD@#x!#O4Mts%EAQf!J;zul2pe&?D;ZO?<%k7*YxF#S8~+_rHl2{%^% zfmY=zkH)*crEJ$9s)M6V!u5FV!&XGroE+5usk*6$tiD`x@)28WZ%*h$4;((%PS3fq zs#A`u-n`KtuYUJFou1wfqz?P-RkaK7#?*uYwcEAFea8}E8;r&m=tl*@

VC!n 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 = start; - ramdisks[i]->size = size; - return i; - } - return -2; - } - } - return -1; -} - -minor_t ramdisk_register(void *ramdisk, u32_t size) -{ - int i; - for (i = 0; i < 256; i++) - { - if (!ramdisks[i]) - { - ramdisks[i] = (ramdisk_t *)New(ramdisk_t); - ramdisks[i]->start = ramdisk; - ramdisks[i]->size = size; - return i; - } - } - return -1; -} - -int ramdisk_remove(minor_t minor) -{ - if (ramdisks[minor]) - { - kfree(ramdisks[minor]->start); - kfree(ramdisks[minor]); - ramdisks[minor] = NULL; - return 0; - } - return -1; -} - - -int Ramdisk::block_read(minor_t minor, u32_t blockStart, u32_t blocks, void *buffer) -{ - if (!ramdisks[minor]) - return -1; - if ((blockStart << BLOCK_SIZE_LOG) >= ramdisks[minor]->size) - return -2; - void *rdAddr = (void *)((u32_t)ramdisks[minor]->start + (blockStart << BLOCK_SIZE_LOG)); - u32_t copyLen = min(blocks << BLOCK_SIZE_LOG, ramdisks[minor]->size + (u32_t)ramdisks[minor]->start - (u32_t)rdAddr); - memcpyd(buffer, rdAddr, copyLen >> 2); - return copyLen; -} - -int Ramdisk::block_write(minor_t minor, u32_t blockStart, u32_t blocks, void *buffer) -{ - if (!ramdisks[minor]) - return -1; - if ((blockStart << BLOCK_SIZE_LOG) >= ramdisks[minor]->size) - return -2; - void *rdAddr = (void *)((u32_t)ramdisks[minor]->start + (blockStart << BLOCK_SIZE_LOG)); - u32_t copyLen = min(blocks << BLOCK_SIZE_LOG, ramdisks[minor]->size + (u32_t)ramdisks[minor]->start - (u32_t)rdAddr); - memcpyd(rdAddr, buffer, copyLen >> 2); - return copyLen; -} - diff --git a/kernel/block/ramdisk.h b/kernel/block/ramdisk.h deleted file mode 100644 index ae4d532..0000000 --- a/kernel/block/ramdisk.h +++ /dev/null @@ -1,38 +0,0 @@ -// ramdisk.h -// Author: Josh Holtrop -// Date: 08/20/04 -// Modified: 08/22/04 - -#ifndef __HOS_RD_H__ -#define __HOS_RD_H__ __HOS_RD_H__ - -#ifdef _HOS_CPP_ -extern "C" { -#endif - -#include "hos_defines.h" -#include "devices.h" - -typedef struct { - void *start; - u32_t size; -} ramdisk_t; - -minor_t ramdisk_new(u32_t size); -minor_t ramdisk_register(void *ramdisk, u32_t size); -int ramdisk_remove(minor_t minor); - -#ifdef _HOS_CPP_ -} - -class Ramdisk : public DeviceDriver -{ -public: - int block_read(minor_t minor, u32_t blockStart, u32_t blocks, void *buffer); - int block_write(minor_t minor, u32_t blockStart, u32_t blocks, void *buffer); -}; - -#endif - -#endif - diff --git a/kernel/block/ramdisk_old.c b/kernel/block/ramdisk_old.c deleted file mode 100644 index 5f8f11c..0000000 --- a/kernel/block/ramdisk_old.c +++ /dev/null @@ -1,100 +0,0 @@ -// ramdisk.c -// Author: Josh Holtrop -// Date: 08/20/04 -// Modified: 08/22/04 - -#include "block/ramdisk.h" -#include "fs/devices.h" -#include "functions.h" -#include "mm/vmm.h" -#include "lang/lang.h" - -ramdisk_t *ramdisks[256]; - -int ramdisk_init(major_t major) -{ - dev_driver_t *ramdisk_driver; - if (( ramdisk_driver = New(dev_driver_t) )) - { - ramdisk_driver->block_read = ramdisk_block_read; - ramdisk_driver->block_write = ramdisk_block_write; - devices_register_major('b', major, ramdisk_driver); - return 0; - } - return -1; -} - -minor_t ramdisk_new(u32_t size) -{ - int i; - for (i = 0; i < 256; i++) - { - if (!ramdisks[i]) - { - void *start; - if (( start = kmalloc(size) )) - { - ramdisks[i] = New(ramdisk_t); - ramdisks[i]->start = start; - ramdisks[i]->size = size; - return i; - } - return -2; - } - } - return -1; -} - -minor_t ramdisk_register(void *ramdisk, u32_t size) -{ - int i; - for (i = 0; i < 256; i++) - { - if (!ramdisks[i]) - { - ramdisks[i] = New(ramdisk_t); - ramdisks[i]->start = ramdisk; - ramdisks[i]->size = size; - return i; - } - } - return -1; -} - -int ramdisk_remove(minor_t minor) -{ - if (ramdisks[minor]) - { - kfree(ramdisks[minor]->start); - kfree(ramdisks[minor]); - ramdisks[minor] = NULL; - return 0; - } - return -1; -} - -int ramdisk_block_read(minor_t minor, u32_t blockNum, u32_t count, void *buffer) -{ - if (!ramdisks[minor]) - return -1; - if ((blockNum << BLOCK_SIZE_LOG) >= ramdisks[minor]->size) - return -2; - void *rdAddr = ramdisks[minor]->start + (blockNum << BLOCK_SIZE_LOG); - u32_t copyLen = min(count << BLOCK_SIZE_LOG, ramdisks[minor]->size + (u32_t)ramdisks[minor]->start - (u32_t)rdAddr); - memcpyd(buffer, rdAddr, copyLen >> 2); - return copyLen; -} - -int ramdisk_block_write(minor_t minor, u32_t blockNum, u32_t count, void *buffer) -{ - if (!ramdisks[minor]) - return -1; - if ((blockNum << BLOCK_SIZE_LOG) >= ramdisks[minor]->size) - return -2; - void *rdAddr = ramdisks[minor]->start + (blockNum << BLOCK_SIZE_LOG); - u32_t copyLen = min(count << BLOCK_SIZE_LOG, ramdisks[minor]->size + (u32_t)ramdisks[minor]->start - (u32_t)rdAddr); - memcpyd(rdAddr, buffer, copyLen >> 2); - return copyLen; -} - - diff --git a/kernel/block/ramdisk_old.h b/kernel/block/ramdisk_old.h deleted file mode 100644 index 0273901..0000000 --- a/kernel/block/ramdisk_old.h +++ /dev/null @@ -1,25 +0,0 @@ -// ramdisk.h -// Author: Josh Holtrop -// Date: 08/20/04 -// Modified: 08/22/04 - -#ifndef __HOS_RD_H__ -#define __HOS_RD_H__ __HOS_RD_H__ - -#include "hos_defines.h" -#include "fs/devices.h" - -typedef struct { - void *start; - u32_t size; -} ramdisk_t; - -int ramdisk_init(major_t major); -minor_t ramdisk_new(u32_t size); -minor_t ramdisk_register(void *ramdisk, u32_t size); -int ramdisk_remove(minor_t minor); -int ramdisk_block_read(minor_t minor, u32_t blockNum, u32_t count, void *buffer); -int ramdisk_block_write(minor_t minor, u32_t blockNum, u32_t count, void *buffer); - -#endif - diff --git a/kernel/boot.asm b/kernel/boot.asm deleted file mode 100644 index 62f4f6a..0000000 --- a/kernel/boot.asm +++ /dev/null @@ -1,236 +0,0 @@ -;boot.asm -;Author: Josh Holtrop -;Date: 07/08/04 -;Modified: 11/01/05 - - -%define MULTIBOOT_MAGIC 0x1BADB002 -%define MULTIBOOT_FLAGS 0x00010003 - -%define VIRT_OFFSET 0xC0000000 ;3gb virtual address -%define PHYS_START 0x00100000 ;1mb physical address -%define VIRT_STACK_TOP 0xD0000000 ;3gb+256mb virtual address -%define GDT_P PHYS_START ;1mb physical - Global Descriptor Table space -%define GDT_V GDT_P+VIRT_OFFSET -%define IDT_P PHYS_START+0x2000 ;1mb+8kb - Interrupt Descriptor Table space -%define IDT_V IDT_P+VIRT_OFFSET -%define PDBR_P PHYS_START+0x4000 ;1mb+16kb - Page Directory Base Register (first PD) -%define PDBR_V PDBR_P+VIRT_OFFSET -%define LOPT_P PHYS_START+0x5000 ;1mb+20kb - LOw Page Table for mapping first 4mb -%define LOPT_V LOPT_P+VIRT_OFFSET -%define PT_STACK_P PHYS_START+0x6000 ;1mb+24kb - page table for initial kernel stack pages (under 0xD0000000) -%define PT_STACK_V PT_STACK_P+VIRT_OFFSET -%define STACK_P PHYS_START+0x7000 ;1mb+28kb - initial 4kb kernel stack page -%define STACK_V STACK_P+VIRT_OFFSET -%define KERNEL_P PHYS_START+0x8000 ;1mb+32kb - the kernel's physical address -%define KERNEL_V KERNEL_P+VIRT_OFFSET ;3gb+1mb+32kb, the virtual address of the kernel - -extern k_init, isr, k_mbsave, end, rm_params, initrd, tss0 - -[bits 32] - -[global start] -start: - -multiboot_header: - dd MULTIBOOT_MAGIC ;magic - dd MULTIBOOT_FLAGS ;flags - dd -(MULTIBOOT_MAGIC + MULTIBOOT_FLAGS) ;checksum - - dd 0x100000000+multiboot_header-VIRT_OFFSET ;header_addr - dd 0x100000000+start-VIRT_OFFSET ;load_addr - dd 0 ;load_end_addr - dd 0x100000000+end-VIRT_OFFSET ;bss_end_addr - dd 0x100000000+multiboot_entry-VIRT_OFFSET ;entry_addr - -; dd 1 ;mode_type -; dd 80 ;width -; dd 25 ;height -; dd 0 ;depth - -[global multiboot_entry] -multiboot_entry: -;This is where the kernel begins execution from the bootloader. -;At this point, a temporary gdt is set up to "map" 0xC000_0000 to 0x0. - cli ;should already be off... - lgdt [0x100000000+gdtrbs32-VIRT_OFFSET] - jmp KERNEL_CODE_BS32:segmented_start -segmented_start: - mov cx, KERNEL_DATA_BS32 - mov ss, cx - mov ds, cx - mov es, cx - mov gs, cx - mov fs, cx - mov esp, STACK_V+0x1000 ;ok, now we can access our data - -;Then the multiboot info structures are saved to local data variables. - add ebx, VIRT_OFFSET - push eax - push ebx ;pointer to multiboot info structure - call k_mbsave ;save multiboot info structures - add esp, 8 - - cmp eax, 0 ; eax = pointer to mb_module_t struct for rmmod - jz pm_return - -;go back to real mode to initialize video mode - mov ebx, eax ; pointer to mb_module_t - mov ecx, [ebx+4] ; end of module - mov eax, [ebx] ; start of module - mov esi, eax ; start of module - sub ecx, eax ; ecx = length of rmmod - shr ecx, 2 ; ecx = length of rmmod in dwords - mov edi, 0xC0005000 ; where to copy rmmod to (0x5000 physical) - - rep movsd ; copy rmmod to first 1mb - - mov ebx, pm_return ; return address - mov ecx, rm_params ; put real mode params here (video mode etc...) - sub ecx, VIRT_OFFSET - - jmp 0xC0005010 ; jump to rmmod - -;Next we enable paging with the first 4mb mapped 1:1 virtual:physical -; and with the 4mb starting at 0xC000_0000 mapped to the first 4mb physical. -pm_return: - mov esp, STACK_V+0x1000 ;ok, now we can access our data again - xor eax, eax - mov edi, PDBR_V - mov ecx, 1024 ;clear the PDBR - rep stosd - mov edi, PT_STACK_V - mov ecx, 1024 ;clear the PT_STACK - rep stosd - mov [PDBR_V], dword LOPT_P|0x03 ;store the physical address of the LOw Page Table | (read/write, present) - mov [PDBR_V+0xC00], dword LOPT_P|0x03 ;store the physical address of the LOw Page Table | (read/write, present) - mov [PDBR_V+0xCFC], dword PT_STACK_P|0x03 ;store the physical address of the initial stack page page table | (read/write, present) - mov [PDBR_V+0xFFC], dword PDBR_P|0x03 ;store the physical address of the page directory (identity map) | (read/write, present) - mov [PT_STACK_V+0xFFC], dword STACK_P|0x03 ;store the physical address of the initial stack page | (read/write, present) - - mov edi, LOPT_V - mov ecx, 1024 - mov eax, 0x03 ;starting physical address = 0x0 | (read/write, present flags) -fill_lopt_loop: ;fill the page table - stosd - add eax, 4096 ;increment next phsyical address by 4kb - loop fill_lopt_loop - - mov eax, PDBR_P - mov cr3, eax ;store the Page Directory Base Address - mov eax, cr0 - or eax, 0x80000000 ;set Page Enable bit - mov cr0, eax ;now paging is active! - - mov edi, GDT_V - mov esi, gdt - mov ecx, gdt_end-gdt - rep movsb - - mov edi, IDT_V ;destination - mov esi, isr_0 ;address of isr0 - mov edx, isr_1-isr_0 ;distance between isr labels - mov ecx, 50 ;number of isrlabels -fill_idt: - mov ebx, esi - mov ax, si - stosw ;0 offset 15:0 - mov ax, KERNEL_CODE - stosw ;2 selector 15:0 - mov ax, 0x8E00 - stosw ;4 [P][DPL][0][TYPE][0][0][0][0][0][0][0][0] - shr esi, 16 - mov ax, si - stosw ;6 offset 31:16 - mov esi, ebx - add esi, edx - loop fill_idt - mov word [IDT_V+0x30*8+4], 0xEE00 ;interrupt 0x30 has user priviledges - -;Then we can start using our "real" gdt, then unmap the lower 4mb. - lgdt [gdtr] ;load gdt - jmp KERNEL_CODE:newgdtcontinue -newgdtcontinue: - mov ax, KERNEL_DATA - mov es, ax - mov ds, ax - mov gs, ax - mov fs, ax - mov ss, ax - mov esp, VIRT_STACK_TOP ;stack just under 3gb+256mb, moves downward - lidt [idtr] ;load idt - mov [PDBR_V], dword 0 ;unmap 0x0, we are running completely paged at 0xC000_0000 - - mov edi, GDT_V + TSS0_SEG + 2 ; copy tss0 base address - mov eax, tss0 ; into the GDT descrtiptor - stosw ; for TSS0 - shr eax, 16 - stosb - add edi, 2 - shr eax, 8 - stosb - - call k_init ;C kernel initialization - - mov ax, TSS0_SEG - ltr ax - - mov eax, esp - push KERNEL_DATA - push eax - -idle_loop: ; system idle loop - sti - hlt - jmp idle_loop - -;------------------------------------------------------- -gdtrbs32: - dw gdt_endbs32-gdtbs32-1 - dd 0x100000000+gdtbs32-VIRT_OFFSET -gdtbs32: ; 0 = null descriptor - dd 0 - dd 0 - - ;a base of 0x4000_0000, when added to 0xC000_0000 will produce 0x0000_0000 physical before paging in effect -KERNEL_CODE_BS32 equ $-gdtbs32 ; 8 - db 0xff ;limit 7:0 - db 0xff ;limit 15:8 - db 0x00 ;base 7:0 - db 0x00 ;base 15:8 - db 0x00 ;base 23:16 - db 0x9a ;access - db 0xcf ;flags / limit 19:16 - db 0x40 ;base 31:24 - -KERNEL_DATA_BS32 equ $-gdtbs32 ; 16 - db 0xff ;limit 7:0 - db 0xff ;limit 15:8 - db 0x00 ;base 7:0 - db 0x00 ;base 15:8 - db 0x00 ;base 23:16 - db 0x92 ;access - db 0xcf ;flags / limit 19:16 - db 0x40 ;base 31:24 - -KERNEL_CODE_BS6_ equ $-gdtbs32 ; 24 - dw 0xffff ;limit 15:0 - dw 0x0000 ;base 15:0 - db 0x00 ;base 23:16 - db 0x9A ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A]) - db 0x00 ;flags ([G][D/B][0][0]) / limit 19:16 - db 0x00 ;base 31:24 - -KERNEL_DATA_BS16 equ $-gdtbs32 ; 32 - dw 0xffff ;limit 15:0 - dw 0x0000 ;base 15:0 - db 0x00 ;base 23:16 - db 0x92 ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A]) - db 0x00 ;flags ([G][D/B][0][0]) / limit 19:16 - db 0x00 ;base 31:24 - -gdt_endbs32: - -%include "gdt.inc" -%include "idt.inc" - diff --git a/kernel/char/keyboard.c b/kernel/char/keyboard.c deleted file mode 100644 index cf454b1..0000000 --- a/kernel/char/keyboard.c +++ /dev/null @@ -1,151 +0,0 @@ -// keyboard.c -// Author: Josh Holtrop -// Created: 04/17/03 -// Modified: 05/19/05 - -#include "hos_defines.h" -#include "char/keyboard.h" -#include "sys/io.h" // inportb, outportb -#include "functions.h" -#include "lang/conv.h" // asciiSwitchCase() -#include "display/kout.h" // kprintf() -#include "display/display.h" // display_activate() - -u8_t kbdFlags = 0; // holds current keyboard flags - caps/num/scroll/shift/ctrl/alt -u8_t lastWasE0 = 0; // was the last byte 0x0E ? -u8_t rawIgnore = 0; // how many signals to blatantly ignore -u8_t ackReason = 0; // used to record the reason why we would get an acknowledge byte (0xFA) - -//these arrays convert a keyboard scan code to an ASCII character value -const u8_t SCAN2ASCII[129] = // for normal keys - "\000\0331234567890-=\010\011" // null,esc,1234567890-=,bksp,tab - "qwertyuiop[]\n\000as" // qwertyuiop[],enter,lctrl,as - "dfghjkl;'`\000\\zxcv" // dfghjkl;'`,lshift,\zxcv - "bnm,./\000*\000 \000\000\000\000\000\000" // bnm,./,rshift,*,alt,space,caps,f1,f2,f3,f4,f5 - "\000\000\000\000\000\000\000\000\000\000-\000\000\000+\000" // f6,f7,f8,f9,f10,num,scrl,home,up,pgup,dash,left,center,right,plus,end - "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" // down,pgdn,ins,del,?,?,?,f11,f12,?,?,winL,winR,menu,?,? - "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" // ? - "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"; // ? -const u8_t SCAN2ASCII2[129] = // for shifted or numlocked keys - "\000\033!@#$%^&*()_+\010\011" // null,esc,!@#$%^&*()_+,bksp,tab - "QWERTYUIOP{}\n\000AS" // QWERTYUIOP{},enter,lctrl,AS - "DFGHJKL:\"~\000|ZXCV" // DFGHJKL:"~,lshift,|ZXCV - "BNM<>?\000*\000 \000\000\000\000\000\000" // BNM<>?,rshift,*,alt,space,caps,f1,f2,f3,f4,f5 - "\000\000\000\000\000\000\000789-456+1" // f6,f7,f8,f9,f10,num,scrl,789-456+1 - "230.\000\000\000\000\000\000\000\000\000\000\000\000" // 230.,?,?,?,f11,f12,?,?,winL,winR,menu,?,? - "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" // ? - "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"; // ? - -// The Keyboard Interrupt Service Routine -void isr_keyboard() -{ - u8_t kbdScan = inportb(0x60); - u8_t inState = inportb(0x61); - outportb(0x61, inState|0x80); - outportb(0x61, inState); - - if (kbdScan == 0xFA) //250 // ACKnowledge - { - //printf("KBD_ACK 0x%x!\n", ackReason); - switch (ackReason) - { - case 0xED: // reset LEDs - outportb(0x60, (kbdFlags & 0x07)); - break; - } - ackReason = 0; - } - if (rawIgnore) // ignore keycodes - { - rawIgnore--; - return; - } - if (lastWasE0 && (kbdScan == 0x2A || kbdScan == 0xAA)) // ignore extended "shift" - { - lastWasE0 = 0; - return; - } - if (kbdScan == 0xE0) // 0xE0 == extended key - { - lastWasE0 = 1; - return; - } - if (kbdScan == 0xE1) // 0xE1 == 2nd-set-extended key - { - rawIgnore = 2; - return; - } - - switch (kbdScan) // handle control keys - { - case KBD_SCAN_LSHIFT: - kbdFlags |= KBDF_SHIFT; - break; - case KBD_SCAN_RSHIFT: - kbdFlags |= KBDF_SHIFT; - break; - case KBD_SCAN_CTRL: - kbdFlags |= KBDF_CTRL; - break; - case KBD_SCAN_ALT: - kbdFlags |= KBDF_ALT; - break; - - case KBD_SCAN_LSHIFT + KBD_SCAN_RELEASED: - kbdFlags &= (KBDF_SHIFT ^ 0xFF); - break; - case KBD_SCAN_RSHIFT + KBD_SCAN_RELEASED: - kbdFlags &= (KBDF_SHIFT ^ 0xFF); - break; - case KBD_SCAN_CTRL + KBD_SCAN_RELEASED: - kbdFlags &= (KBDF_CTRL ^ 0xFF); - break; - case KBD_SCAN_ALT + KBD_SCAN_RELEASED: - kbdFlags &= (KBDF_ALT ^ 0xFF); - break; - - case KBD_SCAN_CAPS+KBD_SCAN_RELEASED: - kbdFlags ^= KBDF_CAPS; - kbd_resetLEDs(); // update LEDs - break; - case KBD_SCAN_SCROLL+KBD_SCAN_RELEASED: - kbdFlags ^= KBDF_SCROLL; - kbd_resetLEDs(); // update LEDs - break; - case KBD_SCAN_NUM+KBD_SCAN_RELEASED: - kbdFlags ^= KBDF_NUM; - kbd_resetLEDs(); // update LEDs - break; - } - u8_t kbdAscii; - // shift or (numlock and key from numpad) - if ( (kbdFlags & KBDF_SHIFT) || ((kbdFlags & KBDF_NUM) && (kbdScan >= 71) && (kbdScan <= 83)) ) - kbdAscii = SCAN2ASCII2[kbdScan & 0x7F]; - else // normal key - kbdAscii = SCAN2ASCII[kbdScan & 0x7F]; - if (kbdFlags & KBDF_CAPS) - kbdAscii = asciiSwitchCase(kbdAscii); // won't affect non-letter characters - -//====do something with key:: -// kprintf("kbdScan = \e[31;1m0x%x\e[0m\tkbdAscii = \e[1;32m0x%x\e[0m (\e[35m%c\e[0m)\tkbdFlags = \e[34m0x%x\e[0m\n", kbdScan, kbdAscii, kbdAscii, kbdFlags); - if ((kbdScan == 83) && (kbdFlags & KBDF_CTRL) && (kbdFlags & KBDF_ALT)) - { - kprintf("Initiating reboot."); - restart(); - } - if (kbdScan & KBD_SCAN_RELEASED) - kbdAscii = 0; - - // send a key event to the display subsystem - display_key_event((kbdFlags << 16) | (kbdScan << 8) | kbdAscii); -} - -//Resets the keyboard LEDs to reflect the current state of the num lock, caps lock, and scroll lock bits -void kbd_resetLEDs() -{ - outportb(0x60, 0xED); - ackReason = 0xED; -} - - - diff --git a/kernel/char/keyboard.h b/kernel/char/keyboard.h deleted file mode 100644 index 307b86a..0000000 --- a/kernel/char/keyboard.h +++ /dev/null @@ -1,36 +0,0 @@ -// keyboard.h -// Author: Josh Holtrop -// Created: 04/17/03 -// Modified: 05/19/05 - -#include "hos_defines.h" - -#ifndef __HOS_KEYBOARD__ -#define __HOS_KEYBOARD__ __HOS_KEYBOARD__ - -#define KBDF_SCROLL 0x01 -#define KBDF_NUM 0x02 -#define KBDF_CAPS 0x04 -#define KBDF_SHIFT 0x10 -#define KBDF_CTRL 0x20 -#define KBDF_ALT 0x40 - -#define KBD_SCAN_RELEASED 0x80 - -#define KBD_SCAN_CTRL 29 -#define KBD_SCAN_LSHIFT 42 -#define KBD_SCAN_RSHIFT 54 -#define KBD_SCAN_ALT 56 -#define KBD_SCAN_SCROLL 70 -#define KBD_SCAN_CAPS 58 -#define KBD_SCAN_NUM 69 - -#define KBD_ASCII(x) ((x) & 0xFF) -#define KBD_SCAN(x) (((x) >> 8) & 0xFF) -#define KBD_FLAGS(x) (((x) >> 16) &0xFF) - -void isr_keyboard(); -void kbd_resetLEDs(); - -#endif - diff --git a/kernel/char/misc_char.cpp b/kernel/char/misc_char.cpp deleted file mode 100644 index c95dd94..0000000 --- a/kernel/char/misc_char.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// misc_char.cpp -// Miscellaneous character devices -// Author: Josh Holtrop -// Date: 05/11/05 -// Modified: 05/11/05 - -#include "hos_defines.h" -#include "devices.h" -#include "misc_char.h" -#include "sys/io.h" - -int MiscChar::char_read(minor_t minor) -{ - switch (minor) - { - case MISC_CHAR_NULL: - return DEV_EOF; - case MISC_CHAR_ZERO: - return 0; - case MISC_CHAR_LP0: - return DEV_INVALID_ACCESS; - default: - return DEV_INVALID_ACCESS; - } -} - -int MiscChar::char_write(minor_t minor, int c) -{ - switch (minor) - { - case MISC_CHAR_NULL: - return 0; - case MISC_CHAR_ZERO: - return 0; - case MISC_CHAR_LP0: - outportb(0x37a, 0xc); - outportb(0x378, c); - outportb(0x37a, 0x1); - return 0; - default: - return DEV_INVALID_ACCESS; - } -} - diff --git a/kernel/char/misc_char.h b/kernel/char/misc_char.h deleted file mode 100644 index e8c417e..0000000 --- a/kernel/char/misc_char.h +++ /dev/null @@ -1,31 +0,0 @@ -// misc_char.h -// Miscellaneous character devices -// Author: Josh Holtrop -// Date: 05/11/05 -// Modified: 05/11/05 - -#ifndef __HOS_MISC_CHAR__ -#define __HOS_MISC_CHAR__ __HOS_MISC_CHAR__ - -#define MISC_CHAR_NULL 3 -#define MISC_CHAR_ZERO 5 -#define MISC_CHAR_LP0 10 - -#include "hos_defines.h" -#include "devices.h" -#include "misc_char.h" - -#ifdef _HOS_CPP_ - -class MiscChar : public DeviceDriver -{ -public: - int char_read(minor_t minor); - int char_write(minor_t minor, int c); - -}; - -#endif - -#endif - diff --git a/kernel/char/mouse.c b/kernel/char/mouse.c deleted file mode 100644 index 7519781..0000000 --- a/kernel/char/mouse.c +++ /dev/null @@ -1,52 +0,0 @@ -// mouse.c -// Author: Josh Holtrop -// Date: 10/03/03 -// Modified: 08/02/04 - -#include "hos_defines.h" -#include "char/mouse.h" -#include "video/video.h" -#include "sys/io.h" - -int mouse_bytesRead; -byte mouse_inbuffer[MOUSE_BUFFER_LENGTH]; - -//This method initializes the ps/2 mouse -void mouse_init() -{ - outportb(0x64, 0x20); //tell keyboard controller we are going to read keyboard controller command byte - byte temp = inportb(0x60); //read keyboard controller command byte - outportb(0x64, 0x60); //tell keyboard controller we are going to write keyboard controller command byte - outportb(0x60, 0x03 | (temp & 0x40)); //write keyboard controller command byte: enable mouse/keyboard ints, include original XLATE bit from temp (bit6) - - outportb(0x64, 0xA8); //enable mouse port - - outportb(0x64, 0xD4); //send command to mouse, not kbd - outportb(0x60, 0xF4); //enable data reporting - - mouse_bytesRead = 0; - - //outportb(0x64, 0xD4); - //outportb(0x60, 0xE7); //scaling 2:1 -} - - -//This method is called when a mouse interrupt occurs -void isr_mouse() -{ - byte inb = inportb(0x60); //read mouse byte - if ((inb == 0xFA) && (mouse_bytesRead < 1)) //ACK - return; - mouse_inbuffer[mouse_bytesRead] = inb; - mouse_bytesRead++; - if (mouse_bytesRead == 3) //complete packet received - { - mouse_bytesRead = 0; - int adjx = (char) mouse_inbuffer[1]; - int adjy = (char) mouse_inbuffer[2]; - // TODO: do something with adjx, adjy... - } -} - - - diff --git a/kernel/char/mouse.h b/kernel/char/mouse.h deleted file mode 100644 index 6331369..0000000 --- a/kernel/char/mouse.h +++ /dev/null @@ -1,15 +0,0 @@ -// mouse.h -// Author: Josh Holtrop -// Date: 10/03/03 -// Modified: 08/02/04 - -#ifndef __HOS_MOUSE__ -#define __HOS_MOUSE__ __HOS_MOUSE__ - -#define MOUSE_BUFFER_LENGTH 16 - -void mouse_init(); -void isr_mouse(); - -#endif - diff --git a/kernel/char/vconsole.cpp b/kernel/char/vconsole.cpp deleted file mode 100644 index 4f85153..0000000 --- a/kernel/char/vconsole.cpp +++ /dev/null @@ -1,274 +0,0 @@ -// vconsole.cpp -// Author: Josh Holtrop -// Date: 08/02/04 -// Modified: 05/11/05 - -extern "C" -{ -#include "hos_defines.h" -#include "mm/vmm.h" -#include "lang/lang.h" -#include "display/display.h" -#include "functions.h" -} - -#include "devices.h" -#include "char/vconsole.h" - -VConsole *vconsoles[VCONSOLE_MAX]; // pointer to virtual console structs -char ansi2vgaAttr[8] = {0, 4, 2, 6, 1, 5, 3, 7}; - -void vconsole_setup(int width, int height) -{ - for (int i = 0; i < VCONSOLE_MAX; i++) - vconsoles[i] = new VConsole(width, height); -} - -int vconsole_activate(u32_t id) -{ - if (id >= VCONSOLE_MAX) - return -1; - vconsoles[id]->activate(); - return 0; -} - -int vconsole_deactivate(u32_t id) -{ - if (id >= VCONSOLE_MAX) - return -1; - vconsoles[id]->deactivate(); - return 0; -} - -VConsoleDriver::~VConsoleDriver() -{ - for (int i = 0; i < VCONSOLE_MAX; i++) - if (vconsoles[i]) - delete vconsoles[i]; -} - -int VConsoleDriver::char_write(minor_t minor, int c) -{ - if (minor < 0 || minor >= VCONSOLE_MAX) - return -1; - if (!vconsoles[minor]) - return -2; - return vconsoles[minor]->char_write(c); -} - -VConsole::VConsole(int width, int height) -{ - myBuffer = new u16_t[width * height]; - myBuffer2 = NULL; - myWidth = width; - myHeight = height; - myAttribute = myForeground = 0x07; - memsetw(myBuffer, 0x0720, width * height); - myCursorPosition = 0; - myCursorStackPosition = myEscapeLevel = myEscapePosition = myBackground = - myBold = myReverse = myBlink = myConcealed = myActive = 0; - -} - -VConsole::~VConsole() -{ - delete[] myBuffer; -} - -void VConsole::activate() -{ - if (myActive) // don't activate if already active - return; - myActive = 1; - myBuffer2 = myBuffer; - myBuffer = (u16_t *)CONSOLE_MEMORY; - memcpyd(myBuffer, myBuffer2, (myWidth * myHeight) >> 1); - writeCursorPosition(myCursorPosition); -} - -void VConsole::deactivate() -{ - if (!myActive) // don't deactivate non-active console - return; - myActive = 0; - myBuffer = myBuffer2; - myBuffer2 = NULL; - memcpyd(myBuffer, (u16_t *)CONSOLE_MEMORY, (myWidth * myHeight) >> 1); -} - -int VConsole::char_write(int c) -{ - int cursorY = myCursorPosition / myWidth; - int cursorX = myCursorPosition % myWidth; - switch (myEscapeLevel) - { - case 2: - if (c >= '0' && c <= '9') // c is part of an escape value - { - myEscapeValue[myEscapePosition] *= 10; - myEscapeValue[myEscapePosition] += c - '0'; - return 0; - } - else if (c == ';') - { - if (myEscapePosition < 7) - myEscapePosition++; - return 0; - } - switch (c) - { - case 'A': // move cursor up n rows - update_cursor_coord(cursorY - myEscapeValue[0], cursorX); - break; - case 'B': // move cursor down n rows - update_cursor_coord(cursorY + myEscapeValue[0], cursorX); - break; - case 'C': // move cursor left n columns - update_cursor_coord(cursorY, cursorX - myEscapeValue[0]); - break; - case 'D': // move cursor right n columns - update_cursor_coord(cursorY, cursorX + myEscapeValue[0]); - break; - case 'H': - case 'f': // move cursor to position (x,y) upper left is (1,1) - update_cursor_coord(myEscapeValue[1] - 1, myEscapeValue[0] - 1); - break; - case 'J': // clear screen, home cursor - memsetw(myBuffer, 0x0720, myWidth * myHeight); - update_cursor_coord(0, 0); - break; - case 'K': // erase line from cursor position (including char. under cursor) to end of line - memsetw(myBuffer + myCursorPosition, 0x0720, myWidth - cursorX); - break; - case 's': // push cursor position on an internal stack - if (myCursorStackPosition < 16) - myCursorStack[myCursorStackPosition++] = myCursorPosition; - break; - case 'u': // pop cursor position from stack - if (myCursorStackPosition > 0) - update_cursor(myCursorStack[--myCursorStackPosition]); - break; - case 'm': // set text attributes - for (int evalEscapePosition = 0; evalEscapePosition <= myEscapePosition; evalEscapePosition++) - { - switch (myEscapeValue[evalEscapePosition]) - { - case 0: - myForeground = 0x07; - myBackground = myConcealed = myReverse = myBlink = myBold = 0; - update_attribute(); - break; - case 1: - myBold = 1; - update_attribute(); - break; - case 5: - myBlink = 1; - update_attribute(); - break; - case 7: - myReverse = 1; - update_attribute(); - break; - case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: - myForeground = ansi2vgaAttr[myEscapeValue[evalEscapePosition] - 30]; - update_attribute(); - break; - case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: - myBackground = ansi2vgaAttr[myEscapeValue[evalEscapePosition] - 40]; - update_attribute(); - break; - } - } - myEscapePosition = 0; - break; - } - memsetd(myEscapeValue, 0, 8); - myEscapePosition = 0; - myEscapeLevel = 0; - return 0; - case 1: - if (c == '[') - myEscapeLevel = 2; - break; - myEscapeLevel = 0; - return 0; // invalid escape sequence - default: - if (c == '\e') - { - myEscapeLevel = 1; - return 0; - } - put_char(c); - } - return 0; -} - - -void VConsole::put_char(int c) -{ - if (!myConcealed) - { - switch (c) - { - case '\t': - if (myCursorPosition % 8) - update_cursor(myCursorPosition + (8 - (myCursorPosition % 8))); - else - update_cursor(myCursorPosition + 8); - break; - case '\n': - if (myCursorPosition % myWidth) - update_cursor(myCursorPosition + (myWidth - (myCursorPosition % myWidth))); - else - update_cursor(myCursorPosition + myWidth); - break; - default: - myBuffer[myCursorPosition] = c | (myAttribute << 8); - update_cursor(myCursorPosition + 1); - } - } -} - -void VConsole::update_cursor_coord(int y, int x) -{ - if (y < 0) - y = 0; - else if (y >= myHeight) - y = myHeight - 1; - if (x < 0) - x = 0; - else if (x >= myWidth) - x = myWidth - 1; - update_cursor(myWidth * y + x); -} - -void VConsole::update_cursor(u16_t position) -{ - myCursorPosition = position; - if (position >= (myWidth * myHeight)) // time to scroll console - { - int i; - for (i = 0; i < myCursorStackPosition; i++) - { - myCursorStack[i] -= myWidth; - if (myCursorStack[i] < 0) - myCursorStack[i] = 0; - } - myCursorPosition -= myWidth; - memcpyw(myBuffer, myBuffer + myWidth, myWidth * (myHeight - 1)); - memsetw(myBuffer + (myWidth * (myHeight - 1)), 0x0720, myWidth); - } - if (myActive) - writeCursorPosition(position); -} - -void VConsole::update_attribute() -{ - if (myReverse) - myAttribute = myBlink << 7 | myForeground << 4 | myBold << 3 | myBackground; - else - myAttribute = myBlink << 7 | myBackground << 4 | myBold << 3 | myForeground; -} - - diff --git a/kernel/char/vconsole.h b/kernel/char/vconsole.h deleted file mode 100644 index e9eba39..0000000 --- a/kernel/char/vconsole.h +++ /dev/null @@ -1,76 +0,0 @@ -// vconsole.h -// Author: Josh Holtrop -// Date: 08/02/04 -// Modified: 05/11/05 - -#ifndef __HOS_VCONSOLE__ -#define __HOS_VCONSOLE__ __HOS_VCONSOLE__ - -#define VCONSOLE_MAX 12 - -#ifdef _HOS_CPP_ -extern "C" { -#endif - -#include "hos_defines.h" - -void vconsole_setup(int width, int height); -int vconsole_activate(u32_t id); -int vconsole_deactivate(u32_t id); - - -#ifdef _HOS_CPP_ -} - -#include "devices.h" - -class VConsoleDriver : public DeviceDriver -{ -public: - ~VConsoleDriver(); - int char_write(minor_t minor, int c); -}; - -class VConsole -{ -protected: - u16_t *myBuffer; - u16_t *myBuffer2; - u16_t myWidth; - u16_t myHeight; - u16_t myCursorPosition; - - short myCursorStack[16]; - u8_t myCursorStackPosition; - - u32_t myEscapeValue[8]; - u8_t myEscapeLevel; - u8_t myEscapePosition; - - u8_t myAttribute; - u8_t myForeground; - u8_t myBackground; - u8_t myBold; - u8_t myReverse; - u8_t myBlink; - u8_t myConcealed; - - u8_t myActive; - -public: - VConsole(int width, int height); - ~VConsole(); - int char_read(); - int char_write(int c); - void put_char(int c); - void update_cursor(u16_t position); - void update_cursor_coord(int y, int x); - void update_attribute(); - void activate(); - void deactivate(); -}; - -#endif - -#endif - diff --git a/kernel/devices.cpp b/kernel/devices.cpp deleted file mode 100644 index f982f26..0000000 --- a/kernel/devices.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// devices.cpp -// Device subsystem for HOS -// Author: Josh Holtrop -// Date: 05/11/05 -// Modified: 05/11/05 - -#include "hos_defines.h" -#include "devices.h" -#include "char/misc_char.h" -#include "char/vconsole.h" -#include "block/ramdisk.h" - -DeviceDriver *drivers[256]; - -int devices_init() -{ - drivers[MAJOR_MISC_CHAR] = new MiscChar(); - drivers[MAJOR_VCONSOLE] = new VConsoleDriver(); - drivers[MAJOR_RAMDISK] = new Ramdisk(); - return 0; -} - -int block_read(major_t major, minor_t minor, u32_t blockStart, u32_t blocks, void *buffer) -{ - if (drivers[major & 0xFF]) - return drivers[major & 0xFF]->block_read(minor, blockStart, blocks, buffer); - return DEV_INVALID_DEVICE; -} - -int block_write(major_t major, minor_t minor, u32_t blockStart, u32_t blocks, void *buffer) -{ - if (drivers[major & 0xFF]) - return drivers[major & 0xFF]->block_write(minor, blockStart, blocks, buffer); - return DEV_INVALID_DEVICE; -} - -int char_read(major_t major, minor_t minor) -{ - if (drivers[major & 0xFF]) - return drivers[major & 0xFF]->char_read(minor); - return DEV_INVALID_DEVICE; -} - -int char_write(major_t major, minor_t minor, int c) -{ - if (drivers[major & 0xFF]) - return drivers[major & 0xFF]->char_write(minor, c); - return DEV_INVALID_DEVICE; -} - -DeviceDriver::DeviceDriver() {} -DeviceDriver::~DeviceDriver() {} - -int DeviceDriver::char_read(minor_t minor) -{ return DEV_INVALID_ACCESS; } - -int DeviceDriver::char_write(minor_t minor, int c) -{ return DEV_INVALID_ACCESS; } - -int DeviceDriver::block_read(minor_t minor, u32_t blockStart, u32_t blocks, void *buffer) -{ return DEV_INVALID_ACCESS; } - -int DeviceDriver::block_write(minor_t minor, u32_t blockStart, u32_t blocks, void *buffer) -{ return DEV_INVALID_ACCESS; } - diff --git a/kernel/devices.h b/kernel/devices.h deleted file mode 100644 index 4e2cc75..0000000 --- a/kernel/devices.h +++ /dev/null @@ -1,58 +0,0 @@ -// devices.h -// Device subsystem for HOS -// Author: Josh Holtrop -// Date: 05/11/05 -// Modified: 06/02/05 - -#ifndef __HOS_DEVICES_H__ -#define __HOS_DEVICES_H__ __HOS_DEVICES_H__ - -#include "hos_defines.h" - -#define DEV_INVALID_ACCESS -256 -#define DEV_INVALID_DEVICE -257 -#define DEV_EOF -1 - -#define MAJOR_MISC_CHAR 1 -#define MAJOR_RAMDISK 2 -#define MAJOR_VCONSOLE 4 - -#define BLOCK_SIZE 512 -#define BLOCK_SIZE_LOG 9 - -#define DEV_MAJOR(x) (((x) >> 8) & 0xFF) -#define DEV_MINOR(x) ((x) & 0xFF) -#define DEV(x,y) ((x) << 8 | (y)) - -typedef short major_t; -typedef short minor_t; -typedef u32_t device_t; - -#ifdef _HOS_CPP_ -extern "C" { -#endif - -int devices_init(); -int block_read(major_t major, minor_t minor, u32_t blockStart, u32_t blocks, void *buffer); -int block_write(major_t major, minor_t minor, u32_t blockStart, u32_t blocks, void *buffer); -int char_read(major_t major, minor_t minor); -int char_write(major_t major, minor_t minor, int c); - -#ifdef _HOS_CPP_ -} - -class DeviceDriver -{ -public: - DeviceDriver(); - virtual ~DeviceDriver(); - virtual int char_read(minor_t minor); - virtual int char_write(minor_t minor, int c); - virtual int block_read(minor_t minor, u32_t blockStart, u32_t blocks, void *buffer); - virtual int block_write(minor_t minor, u32_t blockStart, u32_t blocks, void *buffer); -}; - -#endif - -#endif - diff --git a/kernel/display/display.c b/kernel/display/display.c deleted file mode 100644 index b40fa19..0000000 --- a/kernel/display/display.c +++ /dev/null @@ -1,75 +0,0 @@ -// display.c -// Author: Josh Holtrop -// Date: 08/07/04 -// Modified: 03/19/05 - -#include "devices.h" -#include "char/vconsole.h" -#include "display.h" -#include "lang/lang.h" -#include "kernel.h" -#include "char/keyboard.h" -#include "display/kout.h" - -extern real_mode_param_t rm_params; // check if a video mode is activated -int display_type; -int display_activeConsole = -1; // start with no active console - - -// initialization routine for display subsystem -int display_init() -{ - if (!rm_params.vid_addr) // framebuffer mode - { - vconsole_setup(80, 25); - display_activate(KERNEL_MSG_CONSOLE); - display_type = DISPLAY_CONSOLE; - } - else - display_type = DISPLAY_GRAPHICAL; - return 0; -} - - -// activate the given display -int display_activate(u32_t id) -{ - if (id == display_activeConsole) - return 0; - if (display_type != DISPLAY_CONSOLE) - return -1; - if (id >= VCONSOLE_MAX) - return -2; - if (display_activeConsole >= 0) - vconsole_deactivate(display_activeConsole); - if (vconsole_activate(id)) // if true, didn't work to activate console - { - vconsole_activate(display_activeConsole); // restore old one - return -3; - } - display_activeConsole = id; - return 0; -} - -void display_key_event(u32_t keyCode) -{ - if (display_type == DISPLAY_CONSOLE) - { - u32_t kbdScan = KBD_SCAN(keyCode); - if ( /* kbdFlags & KBDF_ALT && */ kbdScan >= 0x3B && kbdScan <= 0x44) // switch displays F1-F10 - { - display_activate(kbdScan - 0x3B); - return; - } - if ( /* kbdFlags & KBDF_ALT && */ kbdScan >= 0x57 && kbdScan <= 0x58) // F11-F12 - { - display_activate(kbdScan - 0x4D); - return; - } - if (KBD_ASCII(keyCode)) - putc(KBD_ASCII(keyCode)); - } - /* TODO: send key to process on active console - or graphical control process */ -} - diff --git a/kernel/display/display.h b/kernel/display/display.h deleted file mode 100644 index 0bdcdf0..0000000 --- a/kernel/display/display.h +++ /dev/null @@ -1,28 +0,0 @@ -// display.h -// Author: Josh Holtrop -// Date: 08/07/04 -// Modified: 03/19/05 - -#ifndef __HOS_CONSOLE__ -#define __HOS_CONSOLE__ __HOS_CONSOLE__ - -#include "hos_defines.h" -#include "devices.h" - -#define DISPLAY_CONSOLE 0 -#define DISPLAY_GRAPHICAL 1 - -typedef struct -{ - int type; - minor_t id; -} display_t; - -int display_init(); -int display_activate(u32_t id); - -void display_key_event(u32_t keyCode); - -#endif - - diff --git a/kernel/display/kout.c b/kernel/display/kout.c deleted file mode 100644 index 81dae3d..0000000 --- a/kernel/display/kout.c +++ /dev/null @@ -1,141 +0,0 @@ -// kout.c -// Author: Josh Holtrop -// Date: 08/02/04 -// Modified: 11/02/05 - -#include "hos_defines.h" -#include "kout.h" -#include "lang/conv.h" -#include "devices.h" -#include "char/misc_char.h" -#include "functions.h" - -char buffer[64]; // for hex/oct/dec/ascii conversion - -// print a character -void putc(int c) -{ -#ifdef PARALLEL_DEBUG - outportb(0x37a, 0xc); - outportb(0x378, c); - outportb(0x37a, 0x1); - // char_write(MAJOR_MISC_CHAR, MISC_CHAR_LP0, c); -#endif - char_write(MAJOR_VCONSOLE, KERNEL_MSG_CONSOLE, c); -} - - -// print a formatted string -void kprintf(char *fmt, ...) -{ - u32_t *params = ((u32_t *)(&fmt)) + 1; // points to the first paramater - int i; - int special = 0; - for (i = 0; ; i++) - { - if (special) - { - special = 0; - switch (fmt[i]) - { - case 0: - return; - case '%': - putc('%'); - break; - case 's': case 'S': - puts((char *)*params); - params++; - break; - case 'c': case 'C': - putc(*params); - params++; - break; - case 'd': case 'D': case 'i': case 'I': - putDec(*params); - params++; - break; - case 'u': case 'U': - putDecu(*params); - params++; - break; - case 'x': case 'X': - putHex(*params); - params++; - break; - case 'o': case 'O': - putOct(*params); - params++; - break; - case 'b': case 'B': - kio_putBCD(*params); - params++; - break; - } - } - else - { - switch (fmt[i]) - { - case '%': - special = 1; - break; - case 0: - return; - default: - putc(fmt[i]); - } - } - } -} - - -// This function prints a raw string -void puts(char *str) -{ - while (*str) - { - putc(*str++); - } -} - - -// This function prints a signed, decimal integer -void putDec(int num) -{ - itoa(num, buffer); - puts(buffer); -} - - -// This function prints an unsigned, decimal integer -void putDecu(u32_t num) -{ - utoa(num, buffer); - puts(buffer); -} - - -// This function displays a number in hexadecimal -void putHex(u32_t num) -{ - itox(num, buffer); - puts(buffer); -} - - -// This function displays a number in octal -void putOct(u32_t num) -{ - itoo(num, buffer); - puts(buffer); -} - - -// This function prints a two-digit binary-coded-decimal value -void kio_putBCD(u32_t bcd) -{ - bcdtoa(bcd, buffer); - -} - diff --git a/kernel/display/kout.h b/kernel/display/kout.h deleted file mode 100644 index 10cccd5..0000000 --- a/kernel/display/kout.h +++ /dev/null @@ -1,20 +0,0 @@ -// kout.h -// Author: Josh Holtrop -// Date: 08/02/04 - -#ifndef __HOS_KOUT__ -#define __HOS_KOUT__ __HOS_KOUT__ - -#include "hos_defines.h" - -void kprintf(char *fmt, ...); -void putHex(u32_t number); -void kio_putBCD(u32_t bcd); -void putc(int c); -void puts(char *str); -void putDec(int num); -void putDecu(u32_t num); -void putOct(u32_t number); - -#endif - diff --git a/kernel/display/vesafb.c b/kernel/display/vesafb.c deleted file mode 100644 index 568df69..0000000 --- a/kernel/display/vesafb.c +++ /dev/null @@ -1,111 +0,0 @@ -// vesafb.c -// Author: Josh Holtrop -// Date: 03/19/05 -// Modified: 03/19/05 - -#include "display/display.h" -#include "display/vesafb.h" -#include "lang/lang.h" -#include "hos_defines.h" // BIOS_CHAR_MAP - -u16_t *vmem16 = (u16_t *) VESAFB_VID_ADDR; -u32_t *vmem32 = (u32_t *) VESAFB_VID_ADDR; -int vesafb_bpp; -int vesafb_multiplier; -int vesafb_width; // pixels -int vesafb_height; -int vesafb_xres; // characters -int vesafb_yres; -int vesafb_cursor; // -1 to hide, 0+ for cursor position - -int vesafb_init(int width, int height, int bpp) -{ - switch(vesafb_bpp = bpp) - { - case 15: case 16: - vesafb_multiplier = 2; - break; - case 24: - vesafb_multiplier = 3; - break; - case 32: - vesafb_multiplier = 4; - break; - } - vesafb_width = width; - vesafb_height = height; - vesafb_xres = (width >> 3) & 0xFFF8; // columns divisible by 8 - vesafb_yres = height >> 3; - return vesafb_cursor = 0; -} - -void vesafb_clear() -{ - memset(vmem32, 0, vesafb_width * vesafb_height * vesafb_multiplier); - vesafb_update_cursor(0); -} - -void vesafb_update_cursor(int position) -{ - vesafb_draw_cursor(vesafb_cursor, 0); - vesafb_draw_cursor(vesafb_cursor = position, 1); -} - -void vesafb_draw_cursor(int position, int onoff) -{ - int x = (position % vesafb_xres) << 3; - int y = ( (position / vesafb_xres) << 3 ) + 7; - int i; - for (i = 0; i < 7; i++) - vesafb_pset(x + i, y, onoff); -} - -void vesafb_pset(int x, int y, int onoff) -{ - switch (vesafb_bpp) - { - case 15: case 16: - *(vmem16 + vesafb_width*y + x) = (onoff ? 0xFFFF : 0); - break; - case 24: - *((u32_t *)(((u32_t)vmem32) + 3*vesafb_width*y + 3*x)) = (onoff ? 0x00FFFFFF : 0); - break; - case 32: - *(vmem32 + vesafb_width*y + x) = (onoff ? 0x00FFFFFF : 0); - break; - } -} - -int vesafb_getWidth() -{ - return vesafb_xres; -} - -int vesafb_getHeight() -{ - return vesafb_yres; -} - -void vesafb_draw_char(int position, u16_t chr) -{ - int x = (position % vesafb_xres) << 3; - int y = (position / vesafb_xres) << 3; - int xi, yi; - u8_t *charMap = (u8_t *) ( BIOS_CHAR_MAP + ((chr & 0xFF) << 3) ); - for (yi = 0; yi < 7; yi++) - { - for (xi = 0; xi < 7; xi++) - vesafb_pset(x + xi, y + yi, (*charMap & (0x80 >> xi))); - charMap++; - } -} - -int vesafb_draw(u16_t *buffer, int buff_len, int cursor_position) -{ - int i; - for (i = 0; i < buff_len; i++) - vesafb_draw_char(i, *buffer++); - vesafb_update_cursor(cursor_position); - return 0; -} - diff --git a/kernel/display/vesafb.h b/kernel/display/vesafb.h deleted file mode 100644 index 3967949..0000000 --- a/kernel/display/vesafb.h +++ /dev/null @@ -1,25 +0,0 @@ -// vesafb.h -// Author: Josh Holtrop -// Date: 03/19/05 -// Modified: 03/19/05 - -#ifndef __HOS_VESAFB__ -#define __HOS_VESAFB__ __HOS_VESAFB__ - -#include "hos_defines.h" - -#define VESAFB_VID_ADDR 0xF0000000 - -int vesafb_init(int width, int height, int bpp); -void vesafb_clear(); -void vesafb_update_cursor(int position); -void vesafb_draw_cursor(int position, int onoff); -void vesafb_pset(int x, int y, int onoff); -int vesafb_getWidth(); -int vesafb_getHeight(); -void vesafb_draw_char(int position, u16_t chr); -int vesafb_draw(u16_t *buffer, int buff_len, int cursor_position); - -#endif - - diff --git a/kernel/fs/FileSystem.cpp b/kernel/fs/FileSystem.cpp deleted file mode 100644 index df1ddbc..0000000 --- a/kernel/fs/FileSystem.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// FileSystem.cpp -// Virtual file system subsystem for HOS -// Author: Josh Holtrop -// Date: 06/21/05 -// Modified: 06/21/05 - -#include "vfs.h" -#include "FileSystem.h" - -FileSystem::FileSystem() {} -FileSystem::~FileSystem() {} -u32_t FileSystem::totalBlocks() {return 0;} -u32_t FileSystem::freeBlocks() {return 0;} -u32_t FileSystem::totalInodes() {return 0;} -u32_t FileSystem::freeInodes() {return 0;} -u32_t FileSystem::getRootInodeNumber() {return 0;} - -OpenDirectory *FileSystem::openDirectory(u32_t inum, int mode) {return NULL;} -OpenFile *FileSystem::openFile(u32_t inum, int mode) {return NULL;} -int FileSystem::stat(u32_t inum, vfs_stat_t *buf) {return -1;} -int FileSystem::link_deref(u32_t inum, char *buf) {return -1;} diff --git a/kernel/fs/FileSystem.h b/kernel/fs/FileSystem.h deleted file mode 100644 index 3ff010f..0000000 --- a/kernel/fs/FileSystem.h +++ /dev/null @@ -1,35 +0,0 @@ -// FileSystem.h -// Virtual file system subsystem for HOS -// Author: Josh Holtrop -// Date: 06/21/05 -// Modified: 06/21/05 - -#ifndef __HOS_FILESYSTEM__ -#define __HOS_FILESYSTEM__ __HOS_FILESYSTEM__ - -#include "hos_defines.h" -#include "vfs.h" -#include "OpenDirectory.h" -#include "OpenFile.h" - -class FileSystem -{ -public: - FileSystem(); - virtual ~FileSystem(); - - virtual u32_t totalBlocks(); /* 512 byte blocks */ - virtual u32_t freeBlocks(); - - virtual u32_t totalInodes(); - virtual u32_t freeInodes(); - - virtual u32_t getRootInodeNumber(); - - virtual OpenDirectory *openDirectory(u32_t inum, int mode); - virtual OpenFile *openFile(u32_t inum, int mode); - virtual int stat(u32_t inum, vfs_stat_t *buf); - virtual int link_deref(u32_t inum, char *buf); -}; - -#endif diff --git a/kernel/fs/OpenDirectory.cpp b/kernel/fs/OpenDirectory.cpp deleted file mode 100644 index 0b207fb..0000000 --- a/kernel/fs/OpenDirectory.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// OpenDirectory.cpp -// Author: Josh Holtrop -// Date: 12/19/05 - -#include "vfs.h" -#include "OpenDirectory.h" -#include "lang/string.h" - -OpenDirectory::OpenDirectory() {} -OpenDirectory::~OpenDirectory() {} -int OpenDirectory::seek(int pos, int mode) { return -1; } -int OpenDirectory::read(vfs_dir_entry_t *ent) { return -1; } -int OpenDirectory::create(char *name, int mode, u32_t permissions, u32_t dev) - { return -1; } -int OpenDirectory::unlink(char *name) { return -1; } diff --git a/kernel/fs/OpenDirectory.h b/kernel/fs/OpenDirectory.h deleted file mode 100644 index b1fbda3..0000000 --- a/kernel/fs/OpenDirectory.h +++ /dev/null @@ -1,23 +0,0 @@ -// OpenDirectory.h -// Author: Josh Holtrop -// Date: 12/19/05 - -#ifndef __HOS_OPENDIRECTORY_H__ -#define __HOS_OPENDIRECTORY_H__ __HOS_OPENDIRECTORY_H__ - -#include "vfs.h" -#include "lang/string.h" - -class OpenDirectory -{ -public: - OpenDirectory(); - virtual ~OpenDirectory(); - virtual int seek(int pos, int mode); - virtual int read(vfs_dir_entry_t *ent); - virtual int create(char *name, int mode, u32_t permissions, u32_t dev); - virtual int unlink(char *name); -}; - -#endif - diff --git a/kernel/fs/OpenFile.cpp b/kernel/fs/OpenFile.cpp deleted file mode 100644 index 6975a92..0000000 --- a/kernel/fs/OpenFile.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// OpenFile.cpp -// Author: Josh Holtrop -// Date: 12/19/05 - -#include "OpenFile.h" - -OpenFile::OpenFile() {} -OpenFile::~OpenFile() {} -int OpenFile::seek(int pos, int mode) { return -1; } -int OpenFile::read() { return -1; } -int OpenFile::read(void *buf, u32_t num) { return -1; } -int OpenFile::write(int chr) { return -1; } -int OpenFile::write(void *ptr, u32_t num) { return -1; } diff --git a/kernel/fs/OpenFile.h b/kernel/fs/OpenFile.h deleted file mode 100644 index 7e152b2..0000000 --- a/kernel/fs/OpenFile.h +++ /dev/null @@ -1,23 +0,0 @@ -// OpenFile.h -// Author: Josh Holtrop -// Date: 12/19/05 - -#ifndef __HOS_OPENFILE_H__ -#define __HOS_OPENFILE_H__ __HOS_OPENFILE_H__ - -#include "hos_defines.h" - -class OpenFile -{ -public: - OpenFile(); - virtual ~OpenFile(); - virtual int seek(int pos, int mode); - virtual int read(); - virtual int read(void *buf, u32_t num); - virtual int write(int chr); - virtual int write(void *ptr, u32_t num); -}; - -#endif - diff --git a/kernel/fs/VFSMount.cpp b/kernel/fs/VFSMount.cpp deleted file mode 100644 index 54297d0..0000000 --- a/kernel/fs/VFSMount.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// VFSMount.cpp -// Virtual file system subsystem for HOS -// Author: Josh Holtrop -// Date: 06/21/05 -// Modified: 06/21/05 - -extern "C" { -#include "display/kout.h" -} - -#include "vfs.h" -#include "VFSMount.h" -#include "hos_defines.h" -#include "devices.h" -#include "lang/string.h" - -VFSMount::VFSMount(device_t dev, string fsType, FileSystem *fs, - string mountPoint, - inode_num_t mountInode, inode_num_t thisInode) -{ - myDev = dev; - myFSType = fsType; - myFS = fs; - myMountPoint = mountPoint; - myMountInode = mountInode; - myThisInode = thisInode; -} - -VFSMount::~VFSMount() -{ - if (umount_safe()) - kprintf("Filesystem uncleanly mounted from %s\n", myMountPoint.data()); - delete myFS; -} - -int VFSMount::umount_safe() -{ - return 0; -} diff --git a/kernel/fs/VFSMount.h b/kernel/fs/VFSMount.h deleted file mode 100644 index 869c0a7..0000000 --- a/kernel/fs/VFSMount.h +++ /dev/null @@ -1,31 +0,0 @@ -// VFSMount.h -// Virtual file system subsystem for HOS -// Author: Josh Holtrop -// Date: 06/21/05 -// Modified: 06/21/05 - -#ifndef __HOS_VFSMOUNT__ -#define __HOS_VFSMOUNT__ __HOS_VFSMOUNT__ - -#include "lang/string.h" -#include "devices.h" -#include "FileSystem.h" - -class VFSMount -{ -public: - device_t myDev; - string myFSType; - FileSystem *myFS; - string myMountPoint; - inode_num_t myMountInode; - inode_num_t myThisInode; - - VFSMount(device_t dev, string fsType, FileSystem *fs, - string mountPoint, - inode_num_t mountInode, inode_num_t thisInode); - ~VFSMount(); - int umount_safe(); -}; - -#endif diff --git a/kernel/fs/ext2/Ext2BlockCache.cpp b/kernel/fs/ext2/Ext2BlockCache.cpp deleted file mode 100644 index 89b64e2..0000000 --- a/kernel/fs/ext2/Ext2BlockCache.cpp +++ /dev/null @@ -1,143 +0,0 @@ -// Ext2BlockCache.cpp -// Author: Josh Holtrop -// Date: 12/29/05 -// Modified: 12/29/05 - -#include "fs/vfs.h" -#include "Ext2BlockCache.h" - -Ext2BlockCache::Ext2BlockCache(Ext2fs *fs, u32_t inum, ext2_inode_t *inode) -{ - myFS = fs; - myInum = inum; - myInodeDirty = 0; - myInode = inode; - myBlockSize = 1024 << fs->getSuper()->s_log_block_size; - for (int i = 0; i < 3; i++) - { - myCache[i] = new u8_t[myBlockSize]; - myCacheAddress[i] = 0; - myCacheDirty[i] = 0; - } -} - -Ext2BlockCache::~Ext2BlockCache() -{ - for (int i = 0; i < 3; i++) - { - if (myCacheDirty[i]) - myFS->writeBlock(myCacheAddress[i], myCache[i]); - delete[] myCache[i]; - } - if (myInodeDirty) - myFS->writeInode(myInum, myInode); -} - -int Ext2BlockCache::readBlock(u32_t blockNum, void *buf) -{ - u32_t fsblock = getFSBlock(blockNum, 0); - if (fsblock == 0) - return -1; - return myFS->readBlock(fsblock, buf); -} - -int Ext2BlockCache::writeBlock(u32_t blockNum, void *buf) -{ - u32_t fsblock = getFSBlock(blockNum, 1); - if (fsblock == 0) - return -1; - return myFS->writeBlock(fsblock, buf); -} - -void Ext2BlockCache::setCache(u32_t level, u32_t fsblock) -{ - if (myCacheAddress[level] == fsblock) - return; - if (myCacheDirty[level]) - myFS->writeBlock(myCacheAddress[level], myCache[level]); - myCacheAddress[level] = fsblock; - myCacheDirty[level] = 0; - myFS->readBlock(fsblock, myCache[level]); -} - -u32_t Ext2BlockCache::getFSBlock(u32_t blockNum, int create) -{ - if (blockNum < 12) /* direct pointer */ - { - if (create && myInode->i_block[blockNum] == 0) - { - myInode->i_block[blockNum] = myFS->allocBlock(); - myInodeDirty = 1; - } - return myInode->i_block[blockNum]; - } - blockNum -= 12; - if (blockNum < myBlockSize) /* i_block[12] */ - { - if (create && myInode->i_block[12] == 0) - { - myInode->i_block[12] = myFS->allocBlock(); - myInodeDirty = 1; - } - setCache(0, myInode->i_block[12]); - /* blockNum indexes cache 0 */ - if (create && myCache[0][blockNum] == 0) - { - myCache[0][blockNum] = myFS->allocBlock(); - myCacheDirty[0] = 1; - } - return myCache[0][blockNum]; - } - blockNum -= myBlockSize; - if (blockNum < (myBlockSize * myBlockSize)) /* i_block[13] */ - { - if (create && myInode->i_block[13] == 0) - { - myInode->i_block[13] = myFS->allocBlock(); - myInodeDirty = 1; - } - setCache(0, myInode->i_block[13]); - /* blockNum / myBlockSize indexes cache 0 */ - if (create && myCache[0][blockNum / myBlockSize] == 0) - { - myCache[0][blockNum / myBlockSize] = myFS->allocBlock(); - myCacheDirty[0] = 1; - } - setCache(1, myCache[0][blockNum / myBlockSize]); - /* blockNum % myBlockSize indexes cache 1 */ - if (create && myCache[1][blockNum % myBlockSize] == 0) - { - myCache[1][blockNum % myBlockSize] = myFS->allocBlock(); - myCacheDirty[1] = 1; - } - return myCache[1][blockNum % myBlockSize]; - } - blockNum -= (myBlockSize * myBlockSize); /* i_block[14] */ - if (create && myInode->i_block[14] == 0) - { - myInode->i_block[14] = myFS->allocBlock(); - myInodeDirty = 1; - } - setCache(0, myInode->i_block[14]); - /* blockNum / (myBlockSize^2) indexes cache 0 */ - if (create && myCache[0][blockNum / (myBlockSize * myBlockSize)] == 0) - { - myCache[0][blockNum / (myBlockSize * myBlockSize)] = myFS->allocBlock(); - myCacheDirty[0] = 1; - } - setCache(1, myCache[0][blockNum / (myBlockSize * myBlockSize)]); - /* blockNum / myBlockSize indexes cache 1 */ - if (create && myCache[1][blockNum / myBlockSize] == 0) - { - myCache[1][blockNum / myBlockSize] = myFS->allocBlock(); - myCacheDirty[1] = 1; - } - setCache(2, myCache[1][blockNum / myBlockSize]); - /* blockNum % myBlockSize indexes cache 2 */ - if (create && myCache[2][blockNum % myBlockSize] == 0) - { - myCache[2][blockNum % myBlockSize] = myFS->allocBlock(); - myCacheDirty[2] = 1; - } - return myCache[2][blockNum % myBlockSize]; -} diff --git a/kernel/fs/ext2/Ext2BlockCache.h b/kernel/fs/ext2/Ext2BlockCache.h deleted file mode 100644 index bdf9b15..0000000 --- a/kernel/fs/ext2/Ext2BlockCache.h +++ /dev/null @@ -1,34 +0,0 @@ -// Ext2BlockCache.h -// Author: Josh Holtrop -// Date: 12/29/05 -// Modified: 12/29/05 - -#ifndef __HOS_EXT2BLOCKCACHE_H__ -#define __HOS_EXT2BLOCKCACHE_H__ __HOS_EXT2BLOCKCACHE_H__ - -#include "fs/vfs.h" -#include "ext2.h" - -class Ext2BlockCache -{ -protected: - Ext2fs *myFS; - u32_t myInum; - ext2_inode_t *myInode; - u32_t myBlockSize; - u8_t *myCache[3]; - u8_t myCacheAddress[3]; - u8_t myCacheDirty[3]; - u32_t myInodeDirty; - - void setCache(u32_t level, u32_t fsblock); - u32_t getFSBlock(u32_t block, int create); - -public: - Ext2BlockCache(Ext2fs *fs, u32_t inum, ext2_inode_t *inode); - ~Ext2BlockCache(); - int readBlock(u32_t blockNum, void *buf); - int writeBlock(u32_t blockNum, void *buf); -}; - -#endif diff --git a/kernel/fs/ext2/Ext2OpenDirectory.cpp b/kernel/fs/ext2/Ext2OpenDirectory.cpp deleted file mode 100644 index c83c21c..0000000 --- a/kernel/fs/ext2/Ext2OpenDirectory.cpp +++ /dev/null @@ -1,238 +0,0 @@ -// Ext2OpenDirectory.cpp -// Author: Josh Holtrop -// Date: 12/26/05 -// Modified: 12/26/05 - -extern "C" { -#include "lang/lang.h" -} - -#include "fs/vfs.h" -#include "Ext2OpenDirectory.h" -#include "Ext2OpenFile.h" -#include "ext2.h" - -Ext2OpenDirectory::Ext2OpenDirectory(Ext2fs *fs, u32_t inum, int mode) -{ - myPosition = 0; - myFS = fs; - myInum = inum; - myMode = mode; - myCache = new Ext2BlockCache(fs, inum, &myInode); - fs->readInode(inum, &myInode); - u32_t size = myInode.i_size; - u32_t logBlockSize = fs->getSuper()->s_log_block_size; - myBlockSize = 1024 << logBlockSize; - if (size % myBlockSize) - size += myBlockSize - (size % myBlockSize); - myBlocks = size >> (10 + logBlockSize); - myBuffer = new u8_t[size]; - if ((mode & VFS_MODE_RW_MASK) == VFS_MODE_READ) - readDirectory(); -} - -/* destroy an open ext2 directory object */ -Ext2OpenDirectory::~Ext2OpenDirectory() -{ - delete myCache; - delete[] myBuffer; -} - -void Ext2OpenDirectory::readDirectory() -{ - /* read in the entire directory */ - for (u32_t i = 0; i < myBlocks; i++) - myCache->readBlock(i, myBuffer + i * myBlockSize); -} - -/* seek absolute or relative, only positive direction */ -int Ext2OpenDirectory::seek(int pos, int mode) -{ - if (mode == SEEK_ABSOLUTE) - myPosition = 0; - if (pos > 0) - { - while (myPosition < myInode.i_size) - { - ext2_dir_entry_t *de = - (ext2_dir_entry_t *) (myBuffer + myPosition); - myPosition += de->length; - pos--; - if (pos < 1) - return 0; - } - return -1; - } - return -2; -} - -/* read a directory entry from the directory */ -int Ext2OpenDirectory::read(vfs_dir_entry_t *ent) -{ - if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_READ) - return -1; - if (myPosition >= myInode.i_size) - return EOF; - ext2_dir_entry_t *de = (ext2_dir_entry_t *) (myBuffer + myPosition); - ent->inum = de->inode; - memcpy(ent->name, de->name, de->name_length); - ent->name[de->name_length] = 0; - myPosition += de->length; - return 0; -} - -int Ext2OpenDirectory::create(char *name, int mode, u32_t permissions, u32_t dev) -{ - if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_WRITE) - return -1; - readDirectory(); - myPosition = 0; - u32_t name_length = strlen(name); - while (myPosition < myInode.i_size) - { - ext2_dir_entry_t *de = - (ext2_dir_entry_t *) (myBuffer + myPosition); - if (name_length == de->name_length && !strncmp(name, de->name, name_length)) - return -2; /* entry already exists */ - myPosition += de->length; - } - u32_t newInode = myFS->allocInode(); - if (newInode == 0) - return -3; /* no free inodes! */ - /* initialize the inode */ - ext2_inode_t in; - memset(&in, 0, sizeof(ext2_inode_t)); - u32_t ext2_mode; - switch(mode) - { - case VFS_FT_DIR: ext2_mode = EXT2_I_MODE_DIR; break; - case VFS_FT_CHAR: ext2_mode = EXT2_I_MODE_CHAR; - in.i_block[0] = dev; break; - case VFS_FT_BLOCK: ext2_mode = EXT2_I_MODE_BLOCK; - in.i_block[0] = dev; break; - case VFS_FT_FIFO: ext2_mode = EXT2_I_MODE_FIFO; break; - case VFS_FT_SOCK: ext2_mode = EXT2_I_MODE_SOCK; break; - case VFS_FT_SYMLINK: ext2_mode = EXT2_I_MODE_SYM; break; - case VFS_FT_FILE: - default: ext2_mode = EXT2_I_MODE_FILE; break; - } - in.i_mode = ext2_mode | (permissions & EXT2_I_MODE_ATTR_MASK); - in.i_links_count = 1; - myFS->writeInode(newInode, &in); - if (mode == VFS_FT_DIR) - { - if (myFS->getSuper()->s_free_blocks_count < 3) - return -4; /* out of space on device */ - if (myFS->initializeDirectory(newInode, myInum)) - return -5; /* error initializing directory */ - myInode.i_links_count++; - myFS->writeInode(myInum, &myInode); - } - u32_t entryLength = name_length + 8; - if (entryLength & 0x3) - entryLength = (entryLength + 4) & 0xFFFFFFFC; /* multiple of 4 bytes */ - myPosition = 0; - for (;;) - { - ext2_dir_entry_t *de = - (ext2_dir_entry_t *) (myBuffer + myPosition); - u32_t thisEntryLength = de->name_length + 8; - if (thisEntryLength & 0x3) - thisEntryLength = (thisEntryLength + 4) & 0xFFFFFFFC; - if (de->length - thisEntryLength >= entryLength) - { - /* There is room in this entry for the new one */ - u32_t newLength = de->length - thisEntryLength; - de->length = thisEntryLength; - u32_t firstPosition = myPosition; - myPosition += de->length; - de = (ext2_dir_entry_t *) (myBuffer + myPosition); - de->length = newLength; - de->name_length = name_length; - de->inode = newInode; - memcpy(de->name, name, name_length); - writeInclusiveRange(firstPosition, - myPosition + entryLength - 1); - return 0; - } - if (myPosition + de->length >= myInode.i_size) - { - if (myFS->getSuper()->s_free_blocks_count < 2) - { - myFS->freeInode(newInode); - return -4; /* out of space on device */ - } - /* This is the last entry, we need to add a block */ - myBlocks++; - u8_t *newBuffer = new u8_t[myBlockSize * myBlocks]; - memcpy(newBuffer, myBuffer, myBlockSize * (myBlocks - 1)); - delete[] myBuffer; - myBuffer = newBuffer; - de = (ext2_dir_entry_t *) (myBuffer + myPosition); - u32_t thisEntryLength = de->name_length + 8; - if (thisEntryLength & 0x3) - thisEntryLength = (thisEntryLength + 4) & 0xFFFFFFFC; - u32_t leftovers = de->length - thisEntryLength; - de->length -= leftovers; - u32_t firstPosition = myPosition; - myPosition += thisEntryLength; - de = (ext2_dir_entry_t *) (myBuffer + myPosition); - de->length = myBlockSize + leftovers; - de->name_length = name_length; - de->inode = newInode; - memcpy(de->name, name, name_length); - writeInclusiveRange(firstPosition, - myPosition + myBlockSize + leftovers - 1); - myInode.i_size += myBlockSize; - myFS->writeInode(myInum, &myInode); - return 0; - } - myPosition += de->length; - } - -} - -void Ext2OpenDirectory::writeInclusiveRange(u32_t first, u32_t last) -{ - u32_t firstBlock = first / myBlockSize; - u32_t lastBlock = last / myBlockSize; - for (u32_t i = firstBlock; i <= lastBlock; i++) - myCache->writeBlock(i, myBuffer + i * myBlockSize); -} - -int Ext2OpenDirectory::unlink(char *name) -{ - if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_WRITE) - return -1; - readDirectory(); - myPosition = 0; - u32_t lastPosition = 0; - u32_t name_length = strlen(name); - while (myPosition < myInode.i_size) - { - ext2_dir_entry_t *de = - (ext2_dir_entry_t *) (myBuffer + myPosition); - if (name_length == de->name_length && !strncmp(name, de->name, name_length)) - { - ext2_inode_t inode; - myFS->readInode(de->inode, &inode); - if ((inode.i_mode & EXT2_I_MODE_TYPE_MASK) == EXT2_I_MODE_DIR) - { - if (myFS->attemptRemoveDir(de->inode)) - return -3; /* can't unlink non-empty directory */ - } - /* found entry to unlink - add the space to entry at lastPosition */ - myFS->unlink(de->inode); - ext2_dir_entry_t *lde = - (ext2_dir_entry_t *) (myBuffer + lastPosition); - lde->length += de->length; - writeInclusiveRange(lastPosition, lastPosition + 8); - return 0; - } - lastPosition = myPosition; - myPosition += de->length; - } - return -2; /* entry not found */ -} - diff --git a/kernel/fs/ext2/Ext2OpenDirectory.h b/kernel/fs/ext2/Ext2OpenDirectory.h deleted file mode 100644 index 29ccadd..0000000 --- a/kernel/fs/ext2/Ext2OpenDirectory.h +++ /dev/null @@ -1,37 +0,0 @@ -// Ext2OpenDirectory.h -// Author: Josh Holtrop -// Date: 12/26/05 -// Modified: 12/26/05 - -#ifndef __HOS_EXT2OPENDIRECTORY__ -#define __HOS_EXT2OPENDIRECTORY__ __HOS_EXT2OPENDIRECTORY__ - -#include "ext2.h" -#include "Ext2BlockCache.h" - -class Ext2OpenDirectory : public OpenDirectory -{ -private: - u32_t myPosition; - Ext2fs *myFS; - int myMode; - u32_t myInum; - u8_t *myBuffer; - u32_t myBlocks; - u32_t myBlockSize; - Ext2BlockCache *myCache; - ext2_inode_t myInode; - - void readDirectory(); - void writeInclusiveRange(u32_t first, u32_t last); - -public: - Ext2OpenDirectory(Ext2fs *fs, u32_t inum, int mode); - ~Ext2OpenDirectory(); - int seek(int pos, int mode); - int read(vfs_dir_entry_t *ent); - int create(char *name, int mode, u32_t permissions, u32_t dev); - int unlink(char *name); -}; - -#endif diff --git a/kernel/fs/ext2/Ext2OpenFile.cpp b/kernel/fs/ext2/Ext2OpenFile.cpp deleted file mode 100644 index fd34cf1..0000000 --- a/kernel/fs/ext2/Ext2OpenFile.cpp +++ /dev/null @@ -1,228 +0,0 @@ -// Ext2OpenFile.cpp -// Author: Josh Holtrop -// Date: 12/26/05 -// Modified: 12/26/05 - -#include "Ext2OpenFile.h" - -extern "C" { -#include "lang/lang.h" -#include "functions.h" -} - -lock_t Ext2OpenFileListLock; -vector *Ext2OpenFileList = NULL; - -/* make an Ext2OpenFile object - * maintain vector of open files for notifying when one is truncated - */ -Ext2OpenFile::Ext2OpenFile(Ext2fs *fs, u32_t inum, int mode) -{ - myMode = mode; - myFS = fs; - myInum = inum; - myBeenTruncated = 0; - myPosition = 0; - myBlockSize = 1024 << fs->getSuper()->s_log_block_size; - myBlockCache = new u8_t[myBlockSize]; - myBlockCacheBlock = 0; - myBlockCacheStatus = 0; /* 0: invalid; 1: valid; 2: dirty */ - fs->readInode(inum, &myInode); - myCache = new Ext2BlockCache(fs, inum, &myInode); - lockit(&Ext2OpenFileListLock); - if ((mode & VFS_MODE_RW_MASK) == VFS_MODE_WRITE) - { - if ((mode & VFS_MODE_WRITE_MASK) == VFS_MODE_TRUNCATE) - { - /* file opened for write/truncate - * tell any open files that it's been truncated, then - * tell ext2 filesystem to free its blocks - */ - u32_t size = Ext2OpenFileList->size(); - for (u32_t i = 0; i < size; i++) - { - if ((*Ext2OpenFileList)[i].inode == inum) - (*Ext2OpenFileList)[i].ofile->notifyTruncated(); - } - fs->truncateInode(inum); - fs->readInode(inum, &myInode); /* re-read inode */ - } - else - myPosition = myInode.i_size; - } - if (Ext2OpenFileList == NULL) - Ext2OpenFileList = new vector(); - /* add ourselves to the list */ - Ext2OpenFileHandle thisHandle = {inum, this}; - Ext2OpenFileList->add(thisHandle); - unlock(&Ext2OpenFileListLock); -} - -/* destroy an Ext2OpenFile object */ -Ext2OpenFile::~Ext2OpenFile() -{ - /* remove ourselves from the open file list */ - lockit(&Ext2OpenFileListLock); - u32_t size = Ext2OpenFileList->size(); - for (u32_t i = 0; i < size; i++) - { - if ((*Ext2OpenFileList)[i].ofile == this) - { - Ext2OpenFileList->remove(i); - break; - } - } - unlock(&Ext2OpenFileListLock); - - /* write back any open caches if in write mode */ - if ( !myBeenTruncated && ((myMode & VFS_MODE_RW_MASK) == VFS_MODE_WRITE) ) - { - if (myBlockCacheStatus == 2) - myCache->writeBlock(myBlockCacheBlock, myBlockCache); - myFS->writeInode(myInum, &myInode); - } - /* free the memory we used */ - delete myCache; - delete[] myBlockCache; -} - -/* seek to a certain position in the file (only for reading) */ -int Ext2OpenFile::seek(int pos, int mode) -{ - if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_READ) - return -1; - if (mode == SEEK_ABSOLUTE) - { - if (pos < 0) - return -2; - if ((u32_t)pos >= myInode.i_size) - return -3; - myPosition = pos; - return 0; - } - else if (mode == SEEK_RELATIVE) - { - if (myPosition + pos < 0) - return -2; - if (myPosition + pos >= myInode.i_size) - return -3; - myPosition += pos; - return 0; - } - else if (mode == SEEK_END) - { - if (myInode.i_size + pos < 0) - return -2; - if (myInode.i_size + pos >= myInode.i_size) - return -3; - myPosition = myInode.i_size + pos; - return 0; - } - return -4; -} - -/* read a byte from the current file position, return error code/EOF */ -int Ext2OpenFile::read() -{ - if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_READ) - return -1; - if (myBeenTruncated || myPosition >= myInode.i_size) - return EOF; - u32_t theBlock = myPosition / myBlockSize; - updateCache(theBlock); - return myBlockCache[myPosition++ % myBlockSize]; -} - -/* read num bytes from the current file position, put in buf - * return: number of bytes read (>=0) or error code (<0) - */ -int Ext2OpenFile::read(void *buf, u32_t num) -{ - if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_READ) - return -1; - if (myBeenTruncated || myPosition >= myInode.i_size) - return EOF; - if (myPosition + num > myInode.i_size) - num = myInode.i_size - myPosition; - u32_t bytesRead = 0; - u32_t bytesIntoFirstBlock = myPosition % myBlockSize; - if (bytesIntoFirstBlock) - { - updateCache(myPosition / myBlockSize); - bytesRead = min(myBlockSize - bytesIntoFirstBlock, num); - memcpy(buf, myBlockCache + bytesIntoFirstBlock, bytesRead); - myPosition += bytesRead; - } - while (bytesRead < num) - { - updateCache(myPosition / myBlockSize); - u32_t bytesToRead = min(num - bytesRead, myBlockSize); - memcpy((u8_t *)buf + bytesRead, myBlockCache, bytesToRead); - bytesRead += bytesToRead; - myPosition += bytesToRead; - } - return bytesRead; -} - -/* write a byte to the current file position */ -int Ext2OpenFile::write(int chr) -{ - if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_WRITE) - return -1; - if (myBeenTruncated) - return EOF; - u32_t theBlock = myPosition / myBlockSize; - updateCache(theBlock); - myBlockCache[myPosition++ % myBlockSize] = chr; - myBlockCacheStatus = 2; - myInode.i_size++; - return 0; -} - -/* write num bytes from buf to the current file position - * return: number of bytes written (>=0) or error code (<0) - */ -int Ext2OpenFile::write(void *buf, u32_t num) -{ - if (myBeenTruncated) - return -1; - if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_WRITE) - return -2; - u32_t bytesIntoFirstBlock = myPosition % myBlockSize; - u32_t bytesWritten = 0; - if (bytesIntoFirstBlock) - { - updateCache(myPosition / myBlockSize); - bytesWritten = min(myBlockSize - bytesIntoFirstBlock, num); - memcpy(myBlockCache + bytesIntoFirstBlock, buf, bytesWritten); - myBlockCacheStatus = 2; - myPosition += bytesWritten; - } - while (bytesWritten < num) - { - updateCache(myPosition / myBlockSize); - u32_t bytesToWrite = min(num - bytesWritten, myBlockSize); - memcpy(myBlockCache, (u8_t *)buf + bytesWritten, bytesToWrite); - myBlockCacheStatus = 2; - bytesWritten += bytesToWrite; - myPosition += bytesToWrite; - } - myInode.i_size += bytesWritten; - return bytesWritten; -} - -void Ext2OpenFile::updateCache(u32_t blockNum) -{ - if (myBlockCacheStatus && myBlockCacheBlock == blockNum) - return; - if (myBlockCacheStatus == 2) - myCache->writeBlock(myBlockCacheBlock, myBlockCache); - myCache->readBlock(blockNum, myBlockCache); - myBlockCacheStatus = 1; - myBlockCacheBlock = blockNum; -} - -void Ext2OpenFile::notifyTruncated() -{ - myBeenTruncated = 1; -} diff --git a/kernel/fs/ext2/Ext2OpenFile.h b/kernel/fs/ext2/Ext2OpenFile.h deleted file mode 100644 index fbaf26b..0000000 --- a/kernel/fs/ext2/Ext2OpenFile.h +++ /dev/null @@ -1,47 +0,0 @@ -// Ext2OpenFile.h -// Author: Josh Holtrop -// Date: 12/26/05 -// Modified: 12/26/05 - -#ifndef __HOS_EXT2OPENFILE__ -#define __HOS_EXT2OPENFILE__ __HOS_EXT2OPENFILE__ - -#include "ext2.h" -#include "fs/OpenFile.h" -#include "Ext2BlockCache.h" - -class Ext2OpenFile : public OpenFile -{ -protected: - Ext2fs *myFS; - u32_t myInum; - int myMode; - int myBeenTruncated; /* set true when the file truncated */ - u32_t myPosition; - u32_t myBlockSize; - Ext2BlockCache *myCache; - ext2_inode_t myInode; - u8_t *myBlockCache; - u32_t myBlockCacheBlock; - int myBlockCacheStatus; /* 0: invalid; 1: valid; 2: dirty */ - - void updateCache(u32_t blockNum); - -public: - Ext2OpenFile(Ext2fs *fs, u32_t inum, int mode); - ~Ext2OpenFile(); - int seek(int pos, int mode); - int read(); - int read(void *buf, u32_t num); - int write(int chr); - int write(void *buf, u32_t num); - void notifyTruncated(); -}; - -typedef struct -{ - u32_t inode; - Ext2OpenFile *ofile; -} Ext2OpenFileHandle; - -#endif diff --git a/kernel/fs/ext2/ext2.cpp b/kernel/fs/ext2/ext2.cpp deleted file mode 100644 index 2bad74a..0000000 --- a/kernel/fs/ext2/ext2.cpp +++ /dev/null @@ -1,599 +0,0 @@ -// ext2.cpp -// ext2 filesystem driver for HOS -// Author: Josh Holtrop -// Date: 05/10/05 -// Modified: 05/10/05 - -/* example ext2 filesystem block group structure containing superblock and group descriptors: - * block offset description #blocks - * ------------ ----------- ------- - * 0 superblock 1 - * 1 group descriptors gd_blocks = ceil(ceil[s_blocks_count / s_blocks_per_group] / (1024 >> [5 - s_log_block_size])) - * gd_blocks+1 block bitmap block 1 - * gd_blocks+2 inode bitmap block 1 - * gd_blocks+3 inode table itblocks = ceil[s_inodes_per_group / (1024 >> [7 - s_log_block_size])] - * gd_blocks+3+itblocks data blocks s_blocks_per_group - gd_blocks - itblocks - 3 - */ - - -extern "C" { -#include "display/kout.h" -#include "mm/vmm.h" -#include "lang/lang.h" -} - -#include "ext2.h" -#include "Ext2OpenDirectory.h" -#include "Ext2OpenFile.h" - -/* initialize the ext2 filesystem driver */ -int ext2_init() -{ - vfs_register("ext2", ext2__mount_func); - return 0; -} - -/* a function to mount an ext2 filesystem and return a pointer to it */ -FileSystem *ext2__mount_func(device_t dev) -{ - ext2_super_block_t *super = - (ext2_super_block_t *) New(ext2_super_block_t); - if ( (block_read(DEV_MAJOR(dev), DEV_MINOR(dev), 2, 2, super) < 1024) - || (super->s_magic != EXT2_MAGIC) ) - { - kfree(super); - return NULL; - } - Ext2fs *fs = new Ext2fs(super, dev); - kfree(super); - return fs; -} - -/* constructor for an actual ext2 filesystem object */ -Ext2fs::Ext2fs(ext2_super_block_t *super, device_t dev) -{ - myDevice = dev; - memcpy(&mySuper, super, sizeof(ext2_super_block_t)); - mySuperDirty = 0; - myNumGroups = /* ceil[blocks_count / blocks_per_group] */ - (mySuper.s_blocks_count + mySuper.s_blocks_per_group - 1) - / mySuper.s_blocks_per_group; - myGroupDescriptorsPerBlock = 1024 >> (5 - mySuper.s_log_block_size); - myGroupDescriptorBlocks = /* ceil[num_groups / groupDescriptorsPerBlock] */ - (myNumGroups + myGroupDescriptorsPerBlock - 1) - / myGroupDescriptorsPerBlock; - myInodesPerBlock = 1024 >> (7 - mySuper.s_log_block_size); - myInodeTableBlocks = /* ceil[inodes_per_group / inodePerBlock] */ - (mySuper.s_inodes_per_group + myInodesPerBlock - 1) - / myInodesPerBlock; - - /* test/debug code */ -/* kprintf("free blocks: %u\n", mySuper.s_free_blocks_count); - OpenDirectory *od = openDirectory(2, VFS_MODE_WRITE); - kprintf("TEST: %d\n", od->unlink("link")); - kprintf("TEST: %d\n", od->create("test", VFS_FT_FILE, 0640, 0)); - kprintf("TEST: %d\n", od->create("Block File baby", VFS_FT_BLOCK, 0666, 5 << 8 | 3)); - kprintf("TEST: %d\n", od->unlink("bin")); - kprintf("TEST: %d\n", od->create("Character-File", VFS_FT_CHAR, 0644, 130 << 8 | 42)); - kprintf("free blocks: %u\n", mySuper.s_free_blocks_count); - kprintf("TEST: %d\n", od->create("a directory", VFS_FT_DIR, 0755, 0)); - kprintf("free blocks: %u\n", mySuper.s_free_blocks_count); - delete od; -*/ -} - -/* this destructor destroys an ext2 filesystem that was mounted */ -Ext2fs::~Ext2fs() -{ - if (mySuperDirty) - block_write(DEV_MAJOR(myDevice), DEV_MINOR(myDevice), 2, 2, &mySuper); -} - -/* return the total number of 512-blocks on the filesystem */ -u32_t Ext2fs::totalBlocks() -{ - return mySuper.s_blocks_count << (mySuper.s_log_block_size + 1); -} - -/* return the number of free 512-blocks on the filesystem */ -u32_t Ext2fs::freeBlocks() -{ - return mySuper.s_free_blocks_count << (mySuper.s_log_block_size + 1); -} - -/* return the total number of inodes on the filesystem */ -u32_t Ext2fs::totalInodes() -{ - return mySuper.s_inodes_count; -} - -/* return the free number of inodes on the filesystem */ -u32_t Ext2fs::freeInodes() -{ - return mySuper.s_free_inodes_count; -} - -/* ext2 filesystems always have a root-directory inode number of 2 */ -u32_t Ext2fs::getRootInodeNumber() -{ - return 2; -} - -/* open a directory */ -OpenDirectory *Ext2fs::openDirectory(u32_t inum, int mode) -{ - ext2_inode_t inode; - readInode(inum, &inode); - if ((inode.i_mode & EXT2_I_MODE_TYPE_MASK) == EXT2_I_MODE_DIR) - return new Ext2OpenDirectory(this, inum, mode); - return NULL; -} - -/* open a file */ -OpenFile *Ext2fs::openFile(u32_t inum, int mode) -{ - ext2_inode_t inode; - readInode(inum, &inode); - if ((inode.i_mode & EXT2_I_MODE_TYPE_MASK) == EXT2_I_MODE_FILE) - return new Ext2OpenFile(this, inum, mode); - return NULL; -} - -/* stat an inode */ -int Ext2fs::stat(u32_t inum, vfs_stat_t *buf) -{ - ext2_inode_t inode; - if (readInode(inum, &inode)) - return -1; - buf->dev = 0; - switch(inode.i_mode & EXT2_I_MODE_TYPE_MASK) - { - case EXT2_I_MODE_FIFO: buf->type = VFS_FT_FIFO; break; - case EXT2_I_MODE_CHAR: buf->type = VFS_FT_CHAR; - buf->dev = inode.i_block[0]; break; - case EXT2_I_MODE_DIR: buf->type = VFS_FT_DIR; break; - case EXT2_I_MODE_BLOCK: buf->type = VFS_FT_BLOCK; - buf->dev = inode.i_block[0]; break; - case EXT2_I_MODE_FILE: buf->type = VFS_FT_FILE; break; - case EXT2_I_MODE_SYM: buf->type = VFS_FT_SYMLINK; break; - case EXT2_I_MODE_SOCK: buf->type = VFS_FT_SOCK; break; - default: buf->type = VFS_FT_UNKNOWN; - } - buf->size = inode.i_size; - buf->inode = inum; - buf->permissions = inode.i_mode & EXT2_I_MODE_ATTR_MASK; - buf->uid = inode.i_uid; - buf->gid = inode.i_gid; - buf->atime = inode.i_atime; - buf->mtime = inode.i_mtime; - buf->ctime = inode.i_ctime; - buf->links = inode.i_links_count; - return 0; -} - -/* dereference a symbolink link */ -int Ext2fs::link_deref(u32_t inum, char *buf) -{ - ext2_inode_t inode; - if (readInode(inum, &inode)) - return -1; /* Couldn't read inode */ - if ((inode.i_mode & EXT2_I_MODE_TYPE_MASK) != EXT2_I_MODE_SYM) - return -2; - if (inode.i_size > VFS_MAX_PATH_LENGTH) - return -3; - if (inode.i_size < 61) - { - memcpy(buf, inode.i_block, inode.i_size); - buf[inode.i_size] = 0; - return 0; - } - char *block = new char[1024 << mySuper.s_log_block_size]; - readBlock(inode.i_block[0], block); - memcpy(buf, block, inode.i_size); - buf[inode.i_size] = 0; - delete[] block; - return 0; -} - - -/*************************** internal functions ***************************/ - -/* read an inode from the disk into memory */ -int Ext2fs::readInode(u32_t inum, ext2_inode_t *buf) -{ - if (inodeStatus(inum) != 1) - return -1; - inum--; /* turn inode number into a 0-based index */ - u32_t group = inum / mySuper.s_inodes_per_group; - u32_t index = inum % mySuper.s_inodes_per_group; - ext2_group_desc_t group_desc; - readGroupDescriptor(group, &group_desc); - ext2_inode_t *inode_block = new ext2_inode_t[8 << mySuper.s_log_block_size]; - readBlock(group_desc.bg_inode_table + - (index >> (3 + mySuper.s_log_block_size)), inode_block); - u32_t inode_block_index = index % (8 << mySuper.s_log_block_size); - memcpy(buf, inode_block + inode_block_index, sizeof(ext2_inode_t)); - delete[] inode_block; - return 0; -} - -/* write an inode from memory onto the disk */ -int Ext2fs::writeInode(u32_t inum, ext2_inode_t *buf) -{ - if (inodeStatus(inum) != 1) - return -1; - inum--; /* turn inode number into a 0-based index */ - u32_t group = inum / mySuper.s_inodes_per_group; - u32_t index = inum % mySuper.s_inodes_per_group; - ext2_group_desc_t group_desc; - readGroupDescriptor(group, &group_desc); - ext2_inode_t *inode_block = new ext2_inode_t[8 << mySuper.s_log_block_size]; - u32_t block_num = group_desc.bg_inode_table + - (index >> (3 + mySuper.s_log_block_size)); - readBlock(block_num, inode_block); - u32_t inode_block_index = index % (8 << mySuper.s_log_block_size); - memcpy(inode_block + inode_block_index, buf, sizeof(ext2_inode_t)); - writeBlock(block_num, inode_block); - delete[] inode_block; - return 0; -} - -/* read the group descriptor for a given group number */ -int Ext2fs::readGroupDescriptor(u32_t group, ext2_group_desc_t *buf) -{ - if (group >= myNumGroups) - return -1; - ext2_group_desc_t *gd_block = - new ext2_group_desc_t[myGroupDescriptorsPerBlock]; - readBlock(mySuper.s_first_data_block + 1 + - (group / myGroupDescriptorsPerBlock), gd_block); - memcpy(buf, gd_block + (group % myGroupDescriptorsPerBlock), - sizeof(ext2_group_desc_t)); - delete[] gd_block; - return 0; -} - -/* write the group descriptor for a given group number */ -int Ext2fs::writeGroupDescriptor(u32_t group, ext2_group_desc_t *buf) -{ - if (group >= myNumGroups) - return -1; - ext2_group_desc_t *gd_block = - new ext2_group_desc_t[myGroupDescriptorsPerBlock]; - u32_t block_num = mySuper.s_first_data_block + 1 + - (group / myGroupDescriptorsPerBlock); - readBlock(block_num, gd_block); - memcpy(gd_block + (group % myGroupDescriptorsPerBlock), buf, - sizeof(ext2_group_desc_t)); - writeBlock(block_num, gd_block); - delete[] gd_block; - return 0; -} - -/* read a data block from the block device */ -int Ext2fs::readBlock(u32_t blockNum, void *buf) -{ - return block_read(DEV_MAJOR(myDevice), DEV_MINOR(myDevice), - blockNum << (mySuper.s_log_block_size + 1), - 2 << mySuper.s_log_block_size, - buf); -} - -/* write a data block to the block device */ -int Ext2fs::writeBlock(u32_t blockNum, void *buf) -{ - return block_write(DEV_MAJOR(myDevice), DEV_MINOR(myDevice), - blockNum << (mySuper.s_log_block_size + 1), - 2 << mySuper.s_log_block_size, - buf); -} - -/* check the status of an inode (1-based inode number) - * -1: invalid inode number - * 0: free inode - * 1: allocated (used) inode - */ -int Ext2fs::inodeStatus(u32_t inum) -{ - if (inum < 1 || inum > mySuper.s_inodes_count) - return -1; /* invalid inode number */ - inum--; /* turn inode number into a 0-based index */ - u32_t group = inum / mySuper.s_inodes_per_group; - u32_t index = inum % mySuper.s_inodes_per_group; - ext2_group_desc_t group_desc; - readGroupDescriptor(group, &group_desc); - u8_t *bitmap_block = new u8_t[1024 << mySuper.s_log_block_size]; - readBlock(group_desc.bg_inode_bitmap + - (index >> (13 + mySuper.s_log_block_size)), bitmap_block); - u32_t bitmap_index = index % (8192 << mySuper.s_log_block_size); - int inode_status = (bitmap_block[bitmap_index >> 3] >> (bitmap_index & 0x7)) & 1; - delete[] bitmap_block; - return inode_status; -} - -/* check the status of a block - * -1: invalid block number - * 0: free block - * 1: allocated (used) block - */ -int Ext2fs::blockStatus(u32_t bnum) -{ - if (bnum < mySuper.s_first_data_block) - return 1; - if (bnum >= mySuper.s_blocks_count) - return -1; /* invalid inode number */ - bnum -= mySuper.s_first_data_block; - u32_t group = bnum / mySuper.s_blocks_per_group; - u32_t index = bnum % mySuper.s_blocks_per_group; - ext2_group_desc_t group_desc; - readGroupDescriptor(group, &group_desc); - u8_t *bitmap_block = new u8_t[1024 << mySuper.s_log_block_size]; - readBlock(group_desc.bg_block_bitmap + - (index >> (13 + mySuper.s_log_block_size)), bitmap_block); - u32_t bitmap_index = index % (8192 << mySuper.s_log_block_size); - int block_status = (bitmap_block[bitmap_index >> 3] >> (bitmap_index & 0x7)) & 1; - delete[] bitmap_block; - return block_status; -} - -/* allocate an inode, return number (0 on failure) */ -u32_t Ext2fs::allocInode() -{ - ext2_group_desc_t gd; - for (unsigned int bg = 0; bg < myNumGroups; bg++) - { - readGroupDescriptor(bg, &gd); - if (gd.bg_free_inodes_count) - { - u32_t index = allocFromBitmap(gd.bg_inode_bitmap, - mySuper.s_inodes_per_group); - if (index == 0xFFFFFFFF) - return 0; - gd.bg_free_inodes_count--; - writeGroupDescriptor(bg, &gd); - mySuper.s_free_inodes_count--; - mySuperDirty = 1; - return (bg * mySuper.s_inodes_per_group) + index + 1; - } - } - return 0; -} - -/* allocate a block, return number (0 on failure) */ -u32_t Ext2fs::allocBlock() -{ - ext2_group_desc_t gd; - for (unsigned int bg = 0; bg < myNumGroups; bg++) - { - readGroupDescriptor(bg, &gd); - if (gd.bg_free_blocks_count) - { - u32_t index = allocFromBitmap(gd.bg_block_bitmap, - mySuper.s_blocks_per_group); - if (index == 0xFFFFFFFF) - return 0; - gd.bg_free_blocks_count--; - writeGroupDescriptor(bg, &gd); - mySuper.s_free_blocks_count--; - mySuperDirty = 1; - return (bg * mySuper.s_blocks_per_group) + index + - mySuper.s_first_data_block; - } - } - return 0; -} - -/* free an inode, return error code */ -int Ext2fs::freeInode(u32_t inum) -{ - if (inum < 11 || inum > mySuper.s_inodes_count) - return -1; - if (inodeStatus(inum) != 1) - return -2; - inum--; /* now 0-based */ - ext2_group_desc_t gd; - u32_t group_num = inum / mySuper.s_inodes_per_group; - readGroupDescriptor(group_num, &gd); - freeFromBitmap(gd.bg_inode_bitmap, inum % mySuper.s_inodes_per_group); - gd.bg_free_inodes_count++; - mySuper.s_free_inodes_count++; - mySuperDirty = 1; - writeGroupDescriptor(group_num, &gd); - return 0; -} - -/* free a block, return error code */ -int Ext2fs::freeBlock(u32_t bnum) -{ - if (bnum < mySuper.s_first_data_block || bnum >= mySuper.s_blocks_count) - return -1; - if (blockStatus(bnum) != 1) - return -2; - bnum -= mySuper.s_first_data_block; /* now 0-based */ - ext2_group_desc_t gd; - u32_t group_num = bnum / mySuper.s_blocks_per_group; - readGroupDescriptor(group_num, &gd); - freeFromBitmap(gd.bg_block_bitmap, bnum % mySuper.s_blocks_per_group); - gd.bg_free_blocks_count++; - mySuper.s_free_blocks_count++; - mySuperDirty = 1; - writeGroupDescriptor(group_num, &gd); - return 0; -} - -/* allocate a node from a bitmap, return the index, 0xFFFFFFFF on failure */ -u32_t Ext2fs::allocFromBitmap(u32_t blockNum, u32_t maxBits) -{ - u8_t *block = new u8_t[1024 << mySuper.s_log_block_size]; - u8_t *blockPtr = block; - u32_t maxBytes = (maxBits + 7) >> 3; - readBlock(blockNum, block); - for (u32_t idx = 0; idx < maxBytes; idx++) - { - if (*blockPtr != 0xFF) - { - for (u32_t bit = 0; bit < 8; bit++) - { - if ( !((*blockPtr) & (1 << bit)) ) - { - u32_t nodeIndex = (idx << 3) + bit; - if (nodeIndex < maxBits) - { - *blockPtr |= (1 << bit); - writeBlock(blockNum, block); - return nodeIndex; - } - return 0xFFFFFFFF; - } - } - break; - } - blockPtr++; - } - delete[] block; - return 0xFFFFFFFF; -} - -/* free a node from a bitmap */ -void Ext2fs::freeFromBitmap(u32_t blockNum, u32_t node) -{ - u8_t *block = new u8_t[1024 << mySuper.s_log_block_size]; - readBlock(blockNum, block); - u8_t *blockPtr = block + (node >> 3); - *blockPtr &= ((1 << (node & 0x7)) ^ 0xFF); - writeBlock(blockNum, block); - delete[] block; -} - -/* unlink an inode: - * decrement i_links_count - * if it is zero, free the inode - * if not, write the inode back - */ -void Ext2fs::unlink(u32_t inum) -{ - ext2_inode_t inode; - readInode(inum, &inode); - inode.i_links_count--; - if (inode.i_links_count) - { - writeInode(inum, &inode); - return; - } - truncateInode(inum); - freeInode(inum); -} - -int Ext2fs::attemptRemoveDir(u32_t inum) -{ - vfs_dir_entry_t dentry, dentry2; - OpenDirectory *od = openDirectory(inum, VFS_MODE_READ); - if (od->read(&dentry)) - { - delete od; - return -1; - } - if (od->read(&dentry2)) - { - delete od; - return -1; - } - if (!od->read(&dentry)) - { - delete od; - return -1; - } - delete od; - unlink(dentry.inum); - unlink(dentry2.inum); - return 0; -} - -void Ext2fs::truncateInode(u32_t inum) -{ - ext2_inode_t inode; - readInode(inum, &inode); - if ( ((inode.i_mode & EXT2_I_MODE_TYPE_MASK) != EXT2_I_MODE_DIR) && - ((inode.i_mode & EXT2_I_MODE_TYPE_MASK) != EXT2_I_MODE_FILE) ) - return; - for (int i = 0; i < 12; i++) - if (inode.i_block[i]) - freeBlock(inode.i_block[i]); - u32_t entriesPerBlock = 256 << mySuper.s_log_block_size; - u32_t *block = new u32_t[entriesPerBlock]; - if (inode.i_block[12]) - { - readBlock(inode.i_block[12], block); - for (u32_t i = 0; i < entriesPerBlock; i++) - if (block[i]) - freeBlock(block[i]); - freeBlock(inode.i_block[12]); - } - if (inode.i_block[13]) - { - readBlock(inode.i_block[13], block); - u32_t *block2 = new u32_t[entriesPerBlock]; - for (u32_t i = 0; i < entriesPerBlock; i++) - if (block[i]) - { - readBlock(block[i], block2); - for (u32_t j = 0; j < entriesPerBlock; j++) - if (block2[j]) - freeBlock(block2[j]); - freeBlock(block[i]); - } - delete[] block2; - freeBlock(inode.i_block[13]); - } - if (inode.i_block[14]) - { - readBlock(inode.i_block[14], block); - u32_t *block2 = new u32_t[entriesPerBlock]; - u32_t *block3 = new u32_t[entriesPerBlock]; - for (u32_t i = 0; i < entriesPerBlock; i++) - if (block[i]) - { - readBlock(block[i], block2); - for (u32_t j = 0; j < entriesPerBlock; j++) - if (block2[j]) - { - readBlock(block2[j], block3); - for (u32_t k = 0; k < entriesPerBlock; k++) - if (block3[k]) - freeBlock(block3[k]); - freeBlock(block2[j]); - } - freeBlock(block[i]); - } - delete[] block2; - delete[] block3; - freeBlock(inode.i_block[14]); - } - delete[] block; - for (int i = 0; i < 15; i++) - inode.i_block[i] = 0; - inode.i_size = 0; - inode.i_blocks = 0; - writeInode(inum, &inode); -} - -int Ext2fs::initializeDirectory(u32_t inum, u32_t parent) -{ - ext2_inode_t inode; - readInode(inum, &inode); - if ( !(inode.i_block[0] = allocBlock()) ) - return -1; - u8_t *buffer = new u8_t[1024 << mySuper.s_log_block_size]; - ext2_dir_entry_t *de = (ext2_dir_entry_t *) buffer; - de->name_length = 1; - de->length = 12; - de->inode = inum; - memcpy(de->name, ".", 1); - de = (ext2_dir_entry_t *) (buffer + 12); - de->name_length = 2; - de->length = (1024 << mySuper.s_log_block_size) - 12; - de->inode = parent; - memcpy(de->name, "..", 2); - delete[] buffer; - return 0; -} diff --git a/kernel/fs/ext2/ext2.h b/kernel/fs/ext2/ext2.h deleted file mode 100644 index b93d856..0000000 --- a/kernel/fs/ext2/ext2.h +++ /dev/null @@ -1,204 +0,0 @@ -// ext2.h -// ext2 filesystem driver for HOS -// Author: Josh Holtrop -// Date: 05/10/05 -// Modified: 05/23/05 - -#ifndef __HOS_EXT2_H__ -#define __HOS_EXT2_H__ __HOS_EXT2_H__ - -#define EXT2_MAGIC 0xEF53 -#define EXT2_NAME_LEN 255 - -#define EXT2_I_MODE_ATTR_MASK 0x0FFF -#define EXT2_I_MODE_OX 0x0001 -#define EXT2_I_MODE_OW 0x0002 -#define EXT2_I_MODE_OR 0x0004 -#define EXT2_I_MODE_GX 0x0008 -#define EXT2_I_MODE_GW 0x0010 -#define EXT2_I_MODE_GR 0x0020 -#define EXT2_I_MODE_UX 0x0040 -#define EXT2_I_MODE_UW 0x0080 -#define EXT2_I_MODE_UR 0x0100 -#define EXT2_I_MODE_STICKY 0x0200 -#define EXT2_I_MODE_SGID 0x0400 -#define EXT2_I_MODE_SUID 0x0800 - -#define EXT2_I_MODE_TYPE_MASK 0xF000 -#define EXT2_I_MODE_FIFO 0x1000 -#define EXT2_I_MODE_CHAR 0x2000 -#define EXT2_I_MODE_DIR 0x4000 -#define EXT2_I_MODE_BLOCK 0x6000 -#define EXT2_I_MODE_FILE 0x8000 -#define EXT2_I_MODE_SYM 0xA000 -#define EXT2_I_MODE_SOCK 0xC000 - -#define EXT2_I_FLAGS_SEC_DEL 0x01 -#define EXT2_I_FLAGS_UNDELETE 0x02 -#define EXT2_I_FLAGS_COMPRESS 0x04 -#define EXT2_I_FLAGS_SYNC 0x08 -#define EXT2_I_FLAGS_IMMUTABLE 0x10 -#define EXT2_I_FLAGS_APPEND 0x20 -#define EXT2_I_FLAGS_NODUMP 0x40 - -/* ext2 standard inode numbers */ -#define EXT2_INODE_BAD_BLOCKS 1 -#define EXT2_INODE_ROOT 2 -#define EXT2_INODE_ACL_INDEX 3 -#define EXT2_INODE_ACL_DATA 4 -#define EXT2_INODE_BOOT_LOADER 5 -#define EXT2_INODE_UNDELETE_DIR 6 -#define EXT2_INODE_AVAIL 11 - -/* The directory entry file type field values */ -#define EXT2_FT_UNKNOWN 0 -#define EXT2_FT_FILE 1 -#define EXT2_FT_DIR 2 -#define EXT2_FT_CHAR 3 -#define EXT2_FT_BLOCK 4 -#define EXT2_FT_FIFO 5 -#define EXT2_FT_SOCK 6 -#define EXT2_FT_SYMLINK 7 -#define EXT2_FT_MAX 8 - -#include "fs/vfs.h" - -typedef struct -{ - u32_t s_inodes_count; /* Inodes count */ - u32_t s_blocks_count; /* Blocks count */ - u32_t s_r_blocks_count; /* Reserved blocks count */ - u32_t s_free_blocks_count; /* Free blocks count */ - u32_t s_free_inodes_count; /* Free inodes count */ - u32_t s_first_data_block; /* First Data Block */ - u32_t s_log_block_size; /* Block size: 0->1024, 1->2048, 2->4096 */ - int s_log_frag_size; /* Fragment size */ - u32_t s_blocks_per_group; /* # Blocks per group */ - u32_t s_frags_per_group; /* # Fragments per group */ - u32_t s_inodes_per_group; /* # Inodes per group */ - u32_t s_mtime; /* Mount time */ - u32_t s_wtime; /* Write time */ - u16_t s_mnt_count; /* Mount count */ - short s_max_mnt_count; /* Maximal mount count */ - u16_t s_magic; /* Magic signature */ - u16_t s_state; /* File system state */ - u16_t s_errors; /* Behaviour when detecting errors */ - u16_t s_minor_rev_level; /* minor revision level */ - u32_t s_lastcheck; /* time of last check */ - u32_t s_checkinterval; /* max. time between checks */ - u32_t s_creator_os; /* OS */ - u32_t s_rev_level; /* Revision level */ - u16_t s_def_resuid; /* Default uid for reserved blocks */ - u16_t s_def_resgid; /* Default gid for reserved blocks */ - - u32_t s_reserved[235]; -} ext2_super_block_t; - -typedef struct -{ - u32_t bg_block_bitmap; // Blocks bitmap block - u32_t bg_inode_bitmap; // Inode bitmap block - u32_t bg_inode_table; // Inode table block - u16_t bg_free_blocks_count; // Free blocks count - u16_t bg_free_inodes_count; // Free Inodes count - u16_t bg_used_dirs_count; // Directories count - u16_t bg_pad1; - u32_t bg_reserved[3]; -} ext2_group_desc_t; - -typedef struct -{ - u16_t i_mode; // File mode - u16_t i_uid; // Owner UID - u32_t i_size; // Size in bytes - u32_t i_atime; // Access time - u32_t i_ctime; // Creation time - u32_t i_mtime; // Modification time - u32_t i_dtime; // Deletion time - u16_t i_gid; // Group ID - u16_t i_links_count; // Links count - u32_t i_blocks; // Disk Blocks count (512) - u32_t i_flags; // File flags - u32_t i_reserved1; - u32_t i_block[15]; // Pointers to blocks (12 direct, single, double, triple indirect) - u32_t i_version; // File version (for NFS) - u32_t i_file_acl; // File ACL - u32_t i_dir_acl; // Directory ACL - u32_t i_faddr; // Fragment address - u8_t i_frag; // Fragment number - u8_t i_fsize; // Fragment size - u16_t i_pad1; - u32_t i_reserved2[2]; -} ext2_inode_t; - -typedef struct -{ - u32_t inode; // inode number - u16_t length; // directory entry length - u8_t name_length; // name length - u8_t file_type; // File type (used???) - char name[EXT2_NAME_LEN]; -} ext2_dir_entry_t; - -#ifdef _HOS_CPP_ - -int ext2_init(); -FileSystem *ext2__mount_func(device_t dev); - -class Ext2fs : public FileSystem -{ -protected: -/* my data members */ - device_t myDevice; - int mySuperDirty; - ext2_super_block_t mySuper; - u32_t myNumGroups; - u32_t myGroupDescriptorBlocks; - u32_t myInodeTableBlocks; - u32_t myGroupDescriptorsPerBlock; - u32_t myInodesPerBlock; - -/* my functions */ - int readGroupDescriptor(u32_t group, ext2_group_desc_t *buf); - int writeGroupDescriptor(u32_t group, ext2_group_desc_t *buf); - int inodeStatus(u32_t inum); - int blockStatus(u32_t bnum); - u32_t allocFromBitmap(u32_t blockNum, u32_t max); - void freeFromBitmap(u32_t blockNum, u32_t node); - -public: - Ext2fs(ext2_super_block_t *super, device_t dev); - ~Ext2fs(); - u32_t totalBlocks(); - u32_t freeBlocks(); - u32_t totalInodes(); - u32_t freeInodes(); - u32_t getRootInodeNumber(); - OpenDirectory *openDirectory(u32_t inum, int mode); - OpenFile *openFile(u32_t inum, int mode); - int stat(u32_t inum, vfs_stat_t *buf); - int readBlock(u32_t blockNum, void *buf); - int writeBlock(u32_t blockNum, void *buf); - int link_deref(u32_t inum, char *buf); - int readInode(u32_t inum, ext2_inode_t *buf); - int writeInode(u32_t inum, ext2_inode_t *buf); - u32_t allocInode(); - u32_t allocBlock(); - int freeInode(u32_t inum); - int freeBlock(u32_t bnum); - void unlink(u32_t inum); - int attemptRemoveDir(u32_t inum); - void truncateInode(u32_t inum); - int initializeDirectory(u32_t inum, u32_t parent); - - /* inlined functions */ - inline u32_t numGroups() { return myNumGroups; } - inline u32_t groupDescriptorBlocks() { return myGroupDescriptorBlocks; } - inline u32_t inodeTableBlocks() { return myInodeTableBlocks; } - inline ext2_super_block_t *getSuper() { return &mySuper; } -}; - -#endif - -#endif - diff --git a/kernel/fs/ext2/ext2_old.c b/kernel/fs/ext2/ext2_old.c deleted file mode 100644 index b94b25f..0000000 --- a/kernel/fs/ext2/ext2_old.c +++ /dev/null @@ -1,762 +0,0 @@ -// ext2.c -// Author: Josh Holtrop -// Date: 08/22/04 -// Modified: 12/24/04 - -#include "hos_defines.h" -#include "fs/devices.h" -#include "display/kout.h" -#include "ext2.h" -#include "mm/vmm.h" -#include "fs/vfs.h" -#include "lang/lang.h" -#include "functions.h" - -/* Turning an inode number into a (group, inode_index) pair: - * group = (inode - 1) / s_inodes_per_group - * index = (inode - 1) % s_inodes_per_group - */ - -vfs_fs_t ext2_driver = {ext2_mount_super, ext2_umount_super, ext2_stat, - ext2__get_root_dir_inode, ext2__link_deref, - ext2__free_inodes, ext2__total_inodes, - ext2__free_blocks, ext2__total_blocks, - ext2_alloc_inode, ext2_free_inode, ext2_alloc_block, ext2_free_block, - ext2__open_dir, ext2__read_dir, ext2__close_dir, - ext2__open_file, ext2__read_file, ext2__close_file, - ext2__open_block_file, ext2__read_block_file, ext2__block_file_seek, ext2__close_block_file}; - -// initialize the filesystem driver -int ext2_init(int fsID) -{ - vfs_fs_t *fs; - if (( fs = New(vfs_fs_t) )) // give the VFS our FS structure - { - *fs = ext2_driver; - vfs_register_fs(fsID, fs); - return 0; - } - return -1; -} - - -// lookup a file name in a directory and store the directory entry for it -int ext2_dir_lookup(vfs_mount_t *mount, u32_t dir_inode, char *fileName, ext2_dir_entry_t *direntry) -{ - ext2_open_dir_t *dir = ext2_open_dir(mount, dir_inode); - if (!dir) - return -1; // bad directory inode number - ext2_dir_entry_t dentry; - while (!ext2_dir_read_entry(mount, dir, &dentry)) - { - char *dentryName = kcalloc(1, dentry.name_length + 1); - memcpy(dentryName, dentry.name, dentry.name_length); - int res = strcmp(fileName, dentryName); - kfree(dentryName); - if (!res) - { - *direntry = dentry; - ext2_close_dir(mount, dir); - return 0; - } - } - ext2_close_dir(mount, dir); - return -2; -} - -// open a directory by inode number for reading -ext2_open_dir_t *ext2_open_dir(vfs_mount_t *mount, u32_t inode_number) -{ - ext2_open_dir_t *open_dir = New(ext2_open_dir_t); - ext2_open_inode_t *open_inode = ext2_open_inode(mount, inode_number); - if (!open_inode) - { - kfree(open_dir); - return NULL; - } - if ((open_inode->inode.i_mode & EXT2_I_MODE_TYPE_MASK) != EXT2_I_MODE_DIR) - { - ext2_close_inode(mount, open_inode); - kfree(open_dir); - return NULL; - } - open_dir->open_inode = open_inode; - open_dir->position = 0; - return open_dir; -} - -int ext2_dir_read_entry(vfs_mount_t *mount, ext2_open_dir_t *open_dir, ext2_dir_entry_t *dentry) -{ - ext2_super_block_t *super = mount->super; - if (open_dir->position >= open_dir->open_inode->inode.i_size) - return -1; // EOF - u32_t dir_block = open_dir->position >> (10 + super->s_log_block_size); - char *block = kmalloc(2048 << super->s_log_block_size); - ext2_inode_seek(mount, open_dir->open_inode, dir_block); - if (ext2_read_inode_block(mount, open_dir->open_inode, block)) - ext2_read_inode_block(mount, open_dir->open_inode, block + (1024 << super->s_log_block_size)); - ext2_dir_entry_t *dir_entry = (ext2_dir_entry_t *)(block + open_dir->position % (1024 << super->s_log_block_size)); - if (!dir_entry->inode) - { - kfree(block); - return -2; // EOF - } - memcpy(dentry, dir_entry, min(dir_entry->length, sizeof(ext2_dir_entry_t))); - open_dir->position += dir_entry->length; - kfree(block); - return 0; -} - -int ext2_close_dir(vfs_mount_t *mount, ext2_open_dir_t *open_dir) -{ - ext2_close_inode(mount, open_dir->open_inode); - kfree(open_dir); - return 0; -} - - -// open an inode for reading -ext2_open_inode_t *ext2_open_inode(vfs_mount_t *mount, u32_t inode_number) -{ - ext2_open_inode_t *open_inode = New(ext2_open_inode_t); - if ( ext2_read_inode(mount, inode_number, &(open_inode->inode)) ) - { - kfree(open_inode); - return NULL; - } - open_inode->block = 0; - open_inode->block_pointers = NULL; - open_inode->block_pointers_start = 0; - mount->refs++; - return open_inode; -} - - -// seek to a certain block of an open inode -int ext2_inode_seek(vfs_mount_t *mount, ext2_open_inode_t *open_inode, u32_t block_number) -{ - ext2_super_block_t *super = mount->super; - if (open_inode->inode.i_size <= (block_number << (10 + super->s_log_block_size))) - return -1; // at or past EOF - open_inode->block = block_number; - return 0; -} - -// returns number of bytes read -int ext2_read_inode_block(vfs_mount_t *mount, ext2_open_inode_t *open_inode, void *block) -{ - ext2_super_block_t *super = mount->super; - if (open_inode->inode.i_size <= (open_inode->block << (10 + super->s_log_block_size))) - return 0; // at or past EOF - u32_t leftover_bytes = open_inode->inode.i_size - (open_inode->block << (10 + super->s_log_block_size)); - u32_t block_number = ext2_block_number(mount, open_inode); - block_read(mount->major, mount->minor, ext2_FSToDiskBlock(block_number, super), - 2 << super->s_log_block_size, block); - open_inode->block++; - return min(leftover_bytes, 1024 << super->s_log_block_size); -} - - -// close an open inode -int ext2_close_inode(vfs_mount_t *mount, ext2_open_inode_t *open_inode) -{ - mount->refs--; - if (open_inode->block_pointers) - kfree(open_inode->block_pointers); // free the block pointers cache - kfree(open_inode); - return 0; -} - - -// check the status of an inode (1-based inode number) -// -1: invalid inode number -// 0: free inode -// 1: allocated inode -int ext2_inode_status(vfs_mount_t *mount, u32_t inode_number) -{ - ext2_super_block_t *super = mount->super; - if (inode_number < 1 || inode_number > super->s_inodes_count) // inode number invalid - return -1; - inode_number--; // turn inode_number into a 0-based index - u32_t group = inode_number / super->s_inodes_per_group; - u32_t index = inode_number % super->s_inodes_per_group; - u32_t inode_bitmap_block = ext2_get_group_desc(mount, group).bg_inode_bitmap + (index >> (13 + super->s_log_block_size)); - u32_t bitmap_index = index % (8192 << super->s_log_block_size); - u8_t *inode_bitmap = kmalloc(1024 << super->s_log_block_size); - block_read(mount->major, mount->minor, - ext2_FSToDiskBlock(inode_bitmap_block, super), 2 << super->s_log_block_size, inode_bitmap); - int inode_status = (inode_bitmap[bitmap_index >> 3] >> (bitmap_index & 0x7)) & 1; - kfree(inode_bitmap); - return inode_status; -} - - -// check the status of a block -// -1: invalid block number -// 0: free block -// 1: allocated block -int ext2_block_status(vfs_mount_t *mount, u32_t block_number) -{ - ext2_super_block_t *super = mount->super; - if (block_number < super->s_first_data_block || block_number > super->s_blocks_count) // block number invalid - return -1; - block_number -= super->s_first_data_block; - u32_t group = block_number / super->s_blocks_per_group; - u32_t index = block_number % super->s_blocks_per_group; - u32_t block_bitmap_block = ext2_get_group_desc(mount, group).bg_block_bitmap + (index >> (13 + super->s_log_block_size)); - u32_t bitmap_index = index % (8192 << super->s_log_block_size); - u8_t *block_bitmap = kmalloc(1024 << super->s_log_block_size); - block_read(mount->major, mount->minor, - ext2_FSToDiskBlock(block_bitmap_block, super), 2 << super->s_log_block_size, block_bitmap); - int block_status = (block_bitmap[bitmap_index >> 3] >> (bitmap_index & 0x7)) & 1; - kfree(block_bitmap); - return block_status; -} - - -// transform open_inode->block (a relative block number) to an absolute block number for the filesystem -u32_t ext2_block_number(vfs_mount_t *mount, ext2_open_inode_t *open_inode) -{ - if (open_inode->block < 12) - return open_inode->inode.i_block[open_inode->block]; - ext2_super_block_t *super = mount->super; - int pointersPerBlock = 256 << super->s_log_block_size; - if (open_inode->block_pointers && // there is a block pointers cache block allocated - (open_inode->block >= open_inode->block_pointers_start) && // and the block number is in it - (open_inode->block < (open_inode->block_pointers_start + pointersPerBlock))) - return open_inode->block_pointers[open_inode->block - open_inode->block_pointers_start]; - u32_t rel_block = open_inode->block - 12; - if (!open_inode->block_pointers) - open_inode->block_pointers = kmalloc(pointersPerBlock << 2); - if (rel_block < pointersPerBlock) // indirect block in i_block[12] - { - block_read(mount->major, mount->minor, ext2_FSToDiskBlock(open_inode->inode.i_block[12], super), - 2 << super->s_log_block_size, open_inode->block_pointers); - open_inode->block_pointers_start = 12; - return open_inode->block_pointers[rel_block]; - } - rel_block -= pointersPerBlock; - if (rel_block < (pointersPerBlock * pointersPerBlock)) // double-indirect block in i_block[13] - { - block_read(mount->major, mount->minor, ext2_FSToDiskBlock(open_inode->inode.i_block[13], super), - 2 << super->s_log_block_size, open_inode->block_pointers); - u32_t real_block = open_inode->block_pointers[rel_block / pointersPerBlock]; - block_read(mount->major, mount->minor, ext2_FSToDiskBlock(real_block, super), - 2 << super->s_log_block_size, open_inode->block_pointers); - open_inode->block_pointers_start = 12 + pointersPerBlock + rel_block - (rel_block % pointersPerBlock); - return open_inode->block_pointers[rel_block % pointersPerBlock]; - } - // this code shouldn't run unless we are dealing with a 65+mb file ... - rel_block -= pointersPerBlock * pointersPerBlock; - block_read(mount->major, mount->minor, ext2_FSToDiskBlock(open_inode->inode.i_block[14], super), - 2 << super->s_log_block_size, open_inode->block_pointers); - u32_t index_1 = rel_block / (pointersPerBlock * pointersPerBlock); - u32_t leftover_1 = rel_block % (pointersPerBlock * pointersPerBlock); - u32_t block_1 = open_inode->block_pointers[index_1]; - block_read(mount->major, mount->minor, ext2_FSToDiskBlock(block_1, super), - 2 << super->s_log_block_size, open_inode->block_pointers); - u32_t index_2 = leftover_1 / pointersPerBlock; - u32_t leftover_2 = leftover_1 % pointersPerBlock; - u32_t block_2 = open_inode->block_pointers[index_2]; - block_read(mount->major, mount->minor, ext2_FSToDiskBlock(block_2, super), - 2 << super->s_log_block_size, open_inode->block_pointers); - open_inode->block_pointers_start = 12 + (pointersPerBlock + 1) * pointersPerBlock + rel_block - (rel_block % pointersPerBlock); - return open_inode->block_pointers[leftover_2]; -} - - -// read the inode structure from the device -int ext2_read_inode(vfs_mount_t *mount, u32_t inode, ext2_inode_t *dat) -{ - if (ext2_inode_status(mount, inode) != 1) - return -1; // free or invalid inode number - ext2_super_block_t *super = mount->super; - inode--; // turn inode into a 0-based index - u32_t group = inode / super->s_inodes_per_group; - u32_t index = inode % super->s_inodes_per_group; - u32_t inodeAddr = (ext2_get_group_desc(mount, group).bg_inode_table << - (10 + super->s_log_block_size)) + (index << 7); - void *block = kmalloc(512); - block_read(mount->major, mount->minor, inodeAddr >> 9, 1, block); - memcpy(dat, (block + (inodeAddr & 0x1FF)), sizeof(ext2_inode_t)); - kfree(block); - return 0; -} - -// write an inode structure to the device -int ext2_write_inode(vfs_mount_t *mount, u32_t inode, ext2_inode_t *dat) -{ - if (ext2_inode_status(mount, inode) != 1) - return -1; // free or invalid inode number - ext2_super_block_t *super = mount->super; - inode--; // turn inode into a 0-based index - u32_t group = inode / super->s_inodes_per_group; - u32_t index = inode % super->s_inodes_per_group; - u32_t inodeAddr = (ext2_get_group_desc(mount, group).bg_inode_table << - (10 + super->s_log_block_size)) + (index << 7); - void *block = kmalloc(512); - block_read(mount->major, mount->minor, inodeAddr >> 9, 1, block); - memcpy( (block + (inodeAddr & 0x1FF)), dat, sizeof(ext2_inode_t)); - block_write(mount->major, mount->minor, inodeAddr >> 9, 1, block); - kfree(block); - return 0; -} - -// read the group descriptor structure from the device and return it -ext2_group_desc_t ext2_get_group_desc(vfs_mount_t *mount, u32_t group) -{ - ext2_super_block_t *super = mount->super; - u32_t groupDescAddr = ((1 + super->s_first_data_block) << (10 + super->s_log_block_size)) + (group << 5); - void *block = kmalloc(512); - block_read(mount->major, mount->minor, groupDescAddr >> 9, 1, block); - ext2_group_desc_t gd = *(ext2_group_desc_t *)(block + (groupDescAddr & 0x1FF)); - kfree(block); - return gd; -} - -// write the group descriptor structure to the device -void ext2_write_group_desc(vfs_mount_t *mount, u32_t group_num, ext2_group_desc_t *gd) -{ - ext2_super_block_t *super = mount->super; - u32_t groupDescAddr = ((1 + super->s_first_data_block) << (10 + super->s_log_block_size)) + (group_num << 5); - void *block = kmalloc(512); - block_read(mount->major, mount->minor, groupDescAddr >> 9, 1, block); - memcpy( (block + (groupDescAddr & 0x1FF)), gd, sizeof(ext2_group_desc_t) ); - block_write(mount->major, mount->minor, groupDescAddr >> 9, 1, block); - kfree(block); -} - -// allocate an inode and return its number -u32_t ext2_alloc_inode(vfs_mount_t *mount) -{ - ext2_super_block_t *super = mount->super; - if (!super->s_free_inodes_count) - return 0; // no free inodes - int bg, bg_max = ext2_num_block_groups(super); - for (bg = 0; bg < bg_max; bg++) - { - ext2_group_desc_t group_desc = ext2_get_group_desc(mount, bg); - if (group_desc.bg_free_inodes_count) - { - u32_t node = ext2_reserve_node(mount, group_desc.bg_inode_bitmap, super->s_inodes_per_group); - group_desc.bg_free_inodes_count--; - ext2_write_group_desc(mount, bg, &group_desc); - super->s_free_inodes_count--; - return bg * super->s_inodes_per_group + node + 1; - } - } - return 0; -} - -int ext2_free_inode(vfs_mount_t *mount, u32_t inode_number) -{ - ext2_super_block_t *super = mount->super; - if (inode_number < 11 || inode_number > super->s_inodes_count) - return -1; // invalid inode number - if (ext2_inode_status(mount, inode_number) != 1) - return -2; // inode not allocated - inode_number--; // now a 0-based inode number - int bg = inode_number / super->s_inodes_per_group; - ext2_group_desc_t group_desc = ext2_get_group_desc(mount, bg); - ext2_free_node(mount, group_desc.bg_inode_bitmap, inode_number % super->s_inodes_per_group); - group_desc.bg_free_inodes_count++; - ext2_write_group_desc(mount, bg, &group_desc); - super->s_free_inodes_count++; - return 0; -} - -// allocate a block and return its number -u32_t ext2_alloc_block(vfs_mount_t *mount) -{ - ext2_super_block_t *super = mount->super; - if (!super->s_free_blocks_count) - return 0; // no free blocks - int bg, bg_max = ext2_num_block_groups(super); - for (bg = 0; bg < bg_max; bg++) - { - ext2_group_desc_t group_desc = ext2_get_group_desc(mount, bg); - if (group_desc.bg_free_blocks_count) - { - u32_t node = ext2_reserve_node(mount, group_desc.bg_block_bitmap, super->s_blocks_per_group); - group_desc.bg_free_blocks_count--; - ext2_write_group_desc(mount, bg, &group_desc); - super->s_free_blocks_count--; - return bg * super->s_blocks_per_group + node + super->s_first_data_block; - } - } - return 0; -} - -int ext2_free_block(vfs_mount_t *mount, u32_t block_number) -{ - ext2_super_block_t *super = mount->super; - if (block_number < super->s_first_data_block || block_number > (super->s_blocks_count + super->s_first_data_block - 1)) - return -1; // invalid block number - if (ext2_block_status(mount, block_number) != 1) - return -2; // block not allocated - block_number -= super->s_first_data_block; // now a 0-based block number - int bg = block_number / super->s_blocks_per_group; - ext2_group_desc_t group_desc = ext2_get_group_desc(mount, bg); - ext2_free_node(mount, group_desc.bg_block_bitmap, block_number % super->s_blocks_per_group); - group_desc.bg_free_blocks_count++; - ext2_write_group_desc(mount, bg, &group_desc); - super->s_free_blocks_count++; - return 0; -} - -int ext2_resize_inode(vfs_mount_t *mount, u32_t inode_number, u32_t new_size) -{ - ext2_inode_t inode; - if ( ext2_read_inode(mount, inode_number, &inode) ) - return -1; - ext2_super_block_t *super = mount->super; - int current_blocks = (inode.i_size + (1024 << super->s_log_block_size) - 1) >> (10 + super->s_log_block_size); - int new_blocks = (new_size + (1024 << super->s_log_block_size) - 1) >> (10 + super->s_log_block_size); - if ( new_blocks == current_blocks ) - return 0; - - // TODO: resize - u32_t block_size = 1024 << super->s_log_block_size; - u32_t pointers_per_block = block_size >> 2; - u32_t *pointer_cache1 = kmalloc(3 * block_size); - u32_t *pointer_cache2 = pointer_cache1 + pointers_per_block; - u32_t *pointer_cache3 = pointer_cache2 + pointers_per_block; - u32_t c1_start, c2_start, c3_start; - c1_start = c2_start = c3_start = 0; - while (new_blocks < current_blocks) // delete, decrease current_blocks - { - current_blocks--; - // now delete block number current_blocks - - } - - while (current_blocks < new_blocks) // add, increase current_blocks - { - } -} - -// reserve a node of a inode or block bitmap and mark its entry allocated -u32_t ext2_reserve_node(vfs_mount_t *mount, u32_t bitmap_block_num, u32_t bitmap_size) -{ - ext2_super_block_t *super = mount->super; - u32_t *bitmap = kmalloc(1024 << super->s_log_block_size); - int block, max_block = (bitmap_size - 1) / (8192 << super->s_log_block_size) + 1; - for (block = 0; block < max_block; block++) - { - block_read(mount->major, mount->minor, ext2_FSToDiskBlock(bitmap_block_num + block, super), - 2 << super->s_log_block_size, bitmap); - int num, num_max = 256 << super->s_log_block_size; - u32_t *block_pointer = bitmap; - int done = 0; - for (num = 0; num < num_max && !done; num++) - { - if (*block_pointer != 0xFFFFFFFF) - { - done = 1; - int bit; - for (bit = 0; bit < 32; bit++) - { - if (!(*block_pointer & (1 << bit))) - { - u32_t node_number = (block * 8192 << super->s_log_block_size) + (num << 5) + bit; - if (node_number < bitmap_size) - { - // found a node, mark it allocated, write the bitmap, return - *block_pointer |= (1 << bit); - block_write(mount->major, mount->minor, - ext2_FSToDiskBlock(bitmap_block_num + block, super), - 2 << super->s_log_block_size, bitmap); - kfree(bitmap); - return node_number; - } - kfree(bitmap); - return 0; - } - } - } - block_pointer++; - } - } - kfree(bitmap); - return 0; -} - -int ext2_free_node(vfs_mount_t *mount, u32_t bitmap_block_num, u32_t node_number) -{ - ext2_super_block_t *super = mount->super; - u32_t block_num = node_number >> (13 + super->s_log_block_size); - byte *block = kmalloc(1024 << super->s_log_block_size); - block_read(mount->major, mount->minor, ext2_FSToDiskBlock(bitmap_block_num + block_num, super), - 2 << super->s_log_block_size, block); - u32_t node_bit_offset = node_number % (8192 << super->s_log_block_size); - u32_t node_byte_offset = node_bit_offset >> 3; - block[node_byte_offset] &= (0xFF ^ (1 << (node_bit_offset & 0x7))); - block_write(mount->major, mount->minor, ext2_FSToDiskBlock(bitmap_block_num + block_num, super), - 2 << super->s_log_block_size, block); - kfree(block); - return 0; -} - -// return how many block groups are on the filesystem -int ext2_num_block_groups(ext2_super_block_t *super) -{ - return (super->s_inodes_count / super->s_inodes_per_group) + 1; -} - -void ext2_write_super(vfs_mount_t *mount) -{ - block_write(mount->major, mount->minor, 2, 2, mount->super); -} - - -/***************** VFS INTERFACE FUNCTIONS *******************/ - - -// mount the superblock of the filesystem and return a pointer to it, if valid -void *ext2_mount_super(major_t major, minor_t minor) -{ - ext2_super_block_t *super = kmalloc(1024); - block_read(major, minor, 2, 2, super); - if (super->s_magic != EXT2_MAGIC) // not an ext2 filesystem - { - kfree(super); - return NULL; - } - return super; -} - - -// called when we are unmounting this filesystem mount -int ext2_umount_super(vfs_mount_t *mount) -{ - ext2_write_super(mount); - return kfree(mount->super); // free memory that the superblock was taking -} - - -// stat a file, return a structure of info about it -int ext2_stat(vfs_mount_t *mount, u32_t inode_number, vfs_stat_t *stat) -{ - if (ext2_inode_status(mount, inode_number) != 1) - return -1; - ext2_inode_t *inode = New(ext2_inode_t); - if ( ext2_read_inode(mount, inode_number, inode) ) - { - kfree(inode); - return -2; - } - - stat->dev = 0; - switch(inode->i_mode & EXT2_I_MODE_TYPE_MASK) - { - case EXT2_I_MODE_FIFO: stat->type = VFS_FT_FIFO; break; - case EXT2_I_MODE_CHAR: stat->type = VFS_FT_CHAR; stat->dev = inode->i_block[0]; break; - case EXT2_I_MODE_DIR: stat->type = VFS_FT_DIR; break; - case EXT2_I_MODE_BLOCK: stat->type = VFS_FT_BLOCK; stat->dev = inode->i_block[0]; break; - case EXT2_I_MODE_FILE: stat->type = VFS_FT_FILE; break; - case EXT2_I_MODE_SYM: stat->type = VFS_FT_SYMLINK; break; - case EXT2_I_MODE_SOCK: stat->type = VFS_FT_SOCK; break; - default: stat->type = VFS_FT_UNKNOWN; break; - } - stat->size = inode->i_size; - stat->inode = inode_number; - stat->permissions = inode->i_mode & EXT2_I_MODE_ATTR_MASK; - stat->uid = inode->i_uid; - stat->gid = inode->i_gid; - stat->atime = inode->i_atime; - stat->mtime = inode->i_mtime; - stat->ctime = inode->i_ctime; - stat->links = inode->i_links_count; - kfree(inode); - return 0; -} - -// what is the inode of the root directory? -u32_t ext2__get_root_dir_inode(vfs_mount_t *mount) -{ - return 2; -} - - -// VFS interface function to dereference a symbolic link -int ext2__link_deref(vfs_mount_t *mount, u32_t link_inode, char *link) -{ - ext2_inode_t inode; - if (ext2_read_inode(mount, link_inode, &inode)) - return -1; - if ( (inode.i_mode & EXT2_I_MODE_TYPE_MASK) != EXT2_I_MODE_SYM ) - return -2; - if (!inode.i_size) - return -4; - if (inode.i_size < 61) - { - memcpy(link, inode.i_block, inode.i_size); - link[inode.i_size] = 0; - return 0; - } - else - { - ext2_open_inode_t *open_inode; - if (!(open_inode = ext2_open_inode(mount, link_inode))) - return -3; - ext2_super_block_t *super = mount->super; - void *buffer = kmalloc(1024 << super->s_log_block_size); - memset(link, 0, 4096); - int copied = 0; - while (copied < 4096) - { - int bytes_read = ext2_read_inode_block(mount, open_inode, buffer); - if (bytes_read == 0) - break; - memcpy(link + copied, buffer, bytes_read); - copied += bytes_read; - } - ext2_close_inode(mount, open_inode); - kfree(buffer); - return 0; - } -} - -// VFS interface function to return the number of free inodes -int ext2__free_inodes(vfs_mount_t *mount) -{ - ext2_super_block_t *super = mount->super; - return super->s_free_inodes_count; -} - -// VFS interface function to return the total number of inodes -int ext2__total_inodes(vfs_mount_t *mount) -{ - ext2_super_block_t *super = mount->super; - return super->s_inodes_count; -} - -// VFS interface function to return the number of free 512-byte blocks -int ext2__free_blocks(vfs_mount_t *mount) -{ - ext2_super_block_t *super = mount->super; - return super->s_free_blocks_count << (1 + super->s_log_block_size); -} - -// VFS interface function to return the total number of 512-byte blocks -int ext2__total_blocks(vfs_mount_t *mount) -{ - ext2_super_block_t *super = mount->super; - return super->s_blocks_count << (1 + super->s_log_block_size); -} - -// VFS interface function to open a directory -int ext2__open_dir(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *dir) -{ - if (ext2_inode_status(mount, inode_number) != 1) - return -1; - ext2_open_dir_t *open_dir = ext2_open_dir(mount, inode_number); - if (!open_dir) - return -2; - dir->fs_data = open_dir; - return 0; -} - -// VFS interface function to read a directory entry from an open directory -int ext2__read_dir(vfs_mount_t *mount, vfs_open_file_t *dir, vfs_dir_entry_t *dentry) -{ - ext2_dir_entry_t t_dentry; - int status = ext2_dir_read_entry(mount, dir->fs_data, &t_dentry); - if (status) - return status; - memcpy(dentry->name, t_dentry.name, t_dentry.name_length); - dentry->name[t_dentry.name_length] = 0; - dentry->inode_number = t_dentry.inode; - return 0; -} - -// VFS interface function to close an open directory -int ext2__close_dir(vfs_mount_t *mount, vfs_open_file_t *dir) -{ - return ext2_close_dir(mount, dir->fs_data); -} - - -// VFS interface function to open a file for reading a byte at a time -int ext2__open_file(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *open_file) -{ - if (ext2_inode_status(mount, inode_number) != 1) - return -1; - return 0; -} - -// VFS interface function to read a byte from an open file -int ext2__read_file(vfs_mount_t *mount, vfs_open_file_t *open_file) -{ - return 0; -} - -// VFS interface function to close a byte-file -int ext2__close_file(vfs_mount_t *mount, vfs_open_file_t *open_file) -{ - return 0; -} - - -// VFS interface function to open a file for reading 512-byte blocks at a time -int ext2__open_block_file(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *open_file) -{ - if (ext2_inode_status(mount, inode_number) != 1) - return -1; - ext2_open_inode_t *open_inode = ext2_open_inode(mount, inode_number); - if (!open_inode) - return -2; - if ((open_inode->inode.i_mode & EXT2_I_MODE_TYPE_MASK) != EXT2_I_MODE_FILE) - { - ext2_close_inode(mount, open_inode); - return -3; - } - ext2__open_block_file_t *open_block_file = New(ext2__open_block_file_t); - open_block_file->open_inode = open_inode; - open_block_file->block = 0; - open_file->fs_data = open_block_file; - return 0; -} - -// VFS interface function to read a block from an open block file -// returns the number of bytes read -int ext2__read_block_file(vfs_mount_t *mount, vfs_open_file_t *open_file, void *buffer) -{ - ext2_super_block_t *super = mount->super; - ext2__open_block_file_t *open_block_file = open_file->fs_data; - if (ext2_inode_seek(mount, open_block_file->open_inode, ext2_diskToFSBlock(open_block_file->block, super))) - return 0; // EOF - u8_t *block = kmalloc(1024 << super->s_log_block_size); - u32_t file_position_read = (1024 << super->s_log_block_size) * open_block_file->open_inode->block; - u32_t file_position_want = open_block_file->block << 9; - u32_t data_offset = file_position_want - file_position_read; - int bytes_read = ext2_read_inode_block(mount, open_block_file->open_inode, block); - if (bytes_read <= data_offset) - { - kfree(block); - return 0; // EOF - } - memcpy(buffer, block + data_offset, min(512, bytes_read - data_offset)); - kfree(block); - open_block_file->block++; - return min(512, bytes_read - data_offset); -} - -// VFS interface function to seek to a certain block number of an open block file -int ext2__block_file_seek(vfs_mount_t *mount, vfs_open_file_t *open_file, u32_t block_number) -{ - ext2__open_block_file_t *open_block_file = open_file->fs_data; - return ext2_inode_seek(mount, open_block_file->open_inode, ext2_FSToDiskBlock(block_number, mount->super)); -} - -// VFS interface function to close an open block file -int ext2__close_block_file(vfs_mount_t *mount, vfs_open_file_t *open_file) -{ - ext2__open_block_file_t *open_block_file = open_file->fs_data; - ext2_close_inode(mount, open_block_file->open_inode); - kfree(open_block_file); - return 0; -} - - - diff --git a/kernel/fs/ext2/ext2_old.h b/kernel/fs/ext2/ext2_old.h deleted file mode 100644 index f51249d..0000000 --- a/kernel/fs/ext2/ext2_old.h +++ /dev/null @@ -1,241 +0,0 @@ -// ext2.h -// Author: Josh Holtrop -// Date: 08/22/04 -// Modified: 12/24/04 - -#ifndef __HOS_EXT2_H__ -#define __HOS_EXT2_H__ __HOS_EXT2_H__ - -#include "hos_defines.h" -#include "fs/devices.h" -#include "fs/vfs.h" - -#define EXT2_MAGIC 0xEF53 -#define EXT2_NAME_LEN 255 - -#define EXT2_I_MODE_ATTR_MASK 0x0FFF -#define EXT2_I_MODE_OX 0x0001 -#define EXT2_I_MODE_OW 0x0002 -#define EXT2_I_MODE_OR 0x0004 -#define EXT2_I_MODE_GX 0x0008 -#define EXT2_I_MODE_GW 0x0010 -#define EXT2_I_MODE_GR 0x0020 -#define EXT2_I_MODE_UX 0x0040 -#define EXT2_I_MODE_UW 0x0080 -#define EXT2_I_MODE_UR 0x0100 -#define EXT2_I_MODE_STICKY 0x0200 -#define EXT2_I_MODE_SGID 0x0400 -#define EXT2_I_MODE_SUID 0x0800 - -#define EXT2_I_MODE_TYPE_MASK 0xF000 -#define EXT2_I_MODE_FIFO 0x1000 -#define EXT2_I_MODE_CHAR 0x2000 -#define EXT2_I_MODE_DIR 0x4000 -#define EXT2_I_MODE_BLOCK 0x6000 -#define EXT2_I_MODE_FILE 0x8000 -#define EXT2_I_MODE_SYM 0xA000 -#define EXT2_I_MODE_SOCK 0xC000 - -#define EXT2_I_FLAGS_SEC_DEL 0x01 -#define EXT2_I_FLAGS_UNDELETE 0x02 -#define EXT2_I_FLAGS_COMPRESS 0x04 -#define EXT2_I_FLAGS_SYNC 0x08 -#define EXT2_I_FLAGS_IMMUTABLE 0x10 -#define EXT2_I_FLAGS_APPEND 0x20 -#define EXT2_I_FLAGS_NODUMP 0x40 - -#define EXT2_INODE_BAD_BLOCKS 1 -#define EXT2_INODE_ROOT 2 -#define EXT2_INODE_ACL_INDEX 3 -#define EXT2_INODE_ACL_DATA 4 -#define EXT2_INODE_BOOT_LOADER 5 -#define EXT2_INODE_UNDELETE_DIR 6 -#define EXT2_INODE_AVAIL 11 - -#define EXT2_FT_UNKNOWN 0 -#define EXT2_FT_FILE 1 -#define EXT2_FT_DIR 2 -#define EXT2_FT_CHAR 3 -#define EXT2_FT_BLOCK 4 -#define EXT2_FT_FIFO 5 -#define EXT2_FT_SOCK 6 -#define EXT2_FT_SYMLINK 7 -#define EXT2_FT_MAX 8 - -typedef struct -{ - u32_t s_inodes_count; /* Inodes count */ - u32_t s_blocks_count; /* Blocks count */ - u32_t s_r_blocks_count; /* Reserved blocks count */ - u32_t s_free_blocks_count; /* Free blocks count */ - u32_t s_free_inodes_count; /* Free inodes count */ - u32_t s_first_data_block; /* First Data Block */ - u32_t s_log_block_size; /* Block size: 0->1024, 1->2048, 2->4096 */ - int s_log_frag_size; /* Fragment size */ - u32_t s_blocks_per_group; /* # Blocks per group */ - u32_t s_frags_per_group; /* # Fragments per group */ - u32_t s_inodes_per_group; /* # Inodes per group */ - u32_t s_mtime; /* Mount time */ - u32_t s_wtime; /* Write time */ - u16_t s_mnt_count; /* Mount count */ - short s_max_mnt_count; /* Maximal mount count */ - u16_t s_magic; /* Magic signature */ - u16_t s_state; /* File system state */ - u16_t s_errors; /* Behaviour when detecting errors */ - u16_t s_minor_rev_level; /* minor revision level */ - u32_t s_lastcheck; /* time of last check */ - u32_t s_checkinterval; /* max. time between checks */ - u32_t s_creator_os; /* OS */ - u32_t s_rev_level; /* Revision level */ - u16_t s_def_resuid; /* Default uid for reserved blocks */ - u16_t s_def_resgid; /* Default gid for reserved blocks */ - - u32_t s_reserved[235]; -} ext2_super_block_t; - -typedef struct -{ - u32_t bg_block_bitmap; // Blocks bitmap block - u32_t bg_inode_bitmap; // Inode bitmap block - u32_t bg_inode_table; // Inode table block - u16_t bg_free_blocks_count; // Free blocks count - u16_t bg_free_inodes_count; // Free Inodes count - u16_t bg_used_dirs_count; // Directories count - u16_t bg_pad1; - u32_t bg_reserved[3]; -} ext2_group_desc_t; - -typedef struct -{ - u16_t i_mode; // File mode - u16_t i_uid; // Owner UID - u32_t i_size; // Size in bytes - u32_t i_atime; // Access time - u32_t i_ctime; // Creation time - u32_t i_mtime; // Modification time - u32_t i_dtime; // Deletion time - u16_t i_gid; // Group ID - u16_t i_links_count; // Links count - u32_t i_blocks; // Blocks count - u32_t i_flags; // File flags - u32_t i_reserved1; - u32_t i_block[15]; // Pointers to blocks (12 direct, single, double, triple indirect) - u32_t i_version; // File version (for NFS) - u32_t i_file_acl; // File ACL - u32_t i_dir_acl; // Directory ACL - u32_t i_faddr; // Fragment address - u8_t i_frag; // Fragment number - u8_t i_fsize; // Fragment size - u16_t i_pad1; - u32_t i_reserved2[2]; -} ext2_inode_t; - -typedef struct -{ - u32_t inode; // inode number - u16_t length; // directory entry length - u8_t name_length; // name length - u8_t file_type; // File type - char name[EXT2_NAME_LEN]; -} ext2_dir_entry_t; - -typedef struct -{ - ext2_inode_t inode; - u32_t block; - u32_t *block_pointers; - u32_t block_pointers_start; -} ext2_open_inode_t; - -typedef struct -{ - ext2_open_inode_t *open_inode; - u32_t position; -} ext2_open_dir_t; - -typedef struct -{ - ext2_open_inode_t *open_inode; - u32_t position; - u32_t buffer_start; - u32_t buffer_bytes; - u8_t *buffer; -} ext2__open_file_t; - -typedef struct -{ - ext2_open_inode_t *open_inode; - u32_t block; -} ext2__open_block_file_t; - -static inline u32_t ext2_diskToFSBlock(u32_t block, ext2_super_block_t *super) -{ - // convert # of disk blocks to # of filesystem blocks - return block >> (super->s_log_block_size + 1); -} - -static inline u32_t ext2_FSToDiskBlock(u32_t block, ext2_super_block_t *super) -{ - // convert # of filesystem blocks to # of disk blocks - return block << (super->s_log_block_size + 1); -} - - -int ext2_init(int fsID); -int ext2_read_inode(vfs_mount_t *mount, u32_t inode, ext2_inode_t *dat); -int ext2_write_inode(vfs_mount_t *mount, u32_t inode, ext2_inode_t *dat); -ext2_group_desc_t ext2_get_group_desc(vfs_mount_t *mount, u32_t group); -void ext2_write_group_desc(vfs_mount_t *mount, u32_t group_num, ext2_group_desc_t *gd); -ext2_open_inode_t *ext2_open_inode(vfs_mount_t *mount, u32_t inode_number); -int ext2_close_inode(vfs_mount_t *mount, ext2_open_inode_t *open_inode); -int ext2_read_inode_block(vfs_mount_t *mount, ext2_open_inode_t *open_inode, void *block); -u32_t ext2_block_number(vfs_mount_t *mount, ext2_open_inode_t *open_inode); -int ext2_inode_seek(vfs_mount_t *mount, ext2_open_inode_t *open_inode, u32_t block_number); - -int ext2_inode_status(vfs_mount_t *mount, u32_t inode_number); -int ext2_block_status(vfs_mount_t *mount, u32_t block_number); - -u32_t ext2_alloc_inode(vfs_mount_t *mount); -int ext2_free_inode(vfs_mount_t *mount, u32_t inode_number); -u32_t ext2_alloc_block(vfs_mount_t *mount); -int ext2_free_block(vfs_mount_t *mount, u32_t block_number); - -u32_t ext2_reserve_node(vfs_mount_t *mount, u32_t bitmap_block_num, u32_t bitmap_size); -int ext2_free_node(vfs_mount_t *mount, u32_t bitmap_block_num, u32_t node_number); -int ext2_num_block_groups(ext2_super_block_t *super); -void ext2_write_super(vfs_mount_t *mount); - -int ext2_resize_inode(vfs_mount_t *mount, u32_t inode_number, u32_t new_size); - -ext2_open_dir_t *ext2_open_dir(vfs_mount_t *mount, u32_t inode_number); -int ext2_dir_read_entry(vfs_mount_t *mount, ext2_open_dir_t *open_dir, ext2_dir_entry_t *dentry); -int ext2_close_dir(vfs_mount_t *mount, ext2_open_dir_t *open_dir); -int ext2_dir_lookup(vfs_mount_t *mount, u32_t dir_inode, char *fileName, ext2_dir_entry_t *direntry); - - -void *ext2_mount_super(major_t major, minor_t minor); -int ext2_umount_super(vfs_mount_t *mount); -int ext2_stat(vfs_mount_t *mount, u32_t inode_number, vfs_stat_t *stat); -u32_t ext2__get_root_dir_inode(vfs_mount_t *mount); -int ext2__link_deref(vfs_mount_t *mount, u32_t link_inode, char *link); -int ext2__free_inodes(vfs_mount_t *mount); -int ext2__total_inodes(vfs_mount_t *mount); -int ext2__free_blocks(vfs_mount_t *mount); -int ext2__total_blocks(vfs_mount_t *mount); - - -int ext2__open_dir(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *dir); -int ext2__read_dir(vfs_mount_t *mount, vfs_open_file_t *dir, vfs_dir_entry_t *dentry); -int ext2__close_dir(vfs_mount_t *mount, vfs_open_file_t *dir); - -int ext2__open_file(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *open_file); -int ext2__read_file(vfs_mount_t *mount, vfs_open_file_t *open_file); -int ext2__close_file(vfs_mount_t *mount, vfs_open_file_t *open_file); - -int ext2__open_block_file(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *open_file); -int ext2__read_block_file(vfs_mount_t *mount, vfs_open_file_t *open_file, void *buffer); -int ext2__block_file_seek(vfs_mount_t *mount, vfs_open_file_t *open_file, u32_t block_number); -int ext2__close_block_file(vfs_mount_t *mount, vfs_open_file_t *open_file); - -#endif - diff --git a/kernel/fs/ext2/ext2_working.c b/kernel/fs/ext2/ext2_working.c deleted file mode 100644 index 474d538..0000000 --- a/kernel/fs/ext2/ext2_working.c +++ /dev/null @@ -1,332 +0,0 @@ - - -// lookup a file name in a directory and store the directory entry for it -int ext2_dir_lookup(vfs_mount_t *mount, u32_t dir_inode, char *fileName, ext2_dir_entry_t *direntry) -{ - ext2_open_dir_t *dir = ext2_open_dir(mount, dir_inode); - if (!dir) - return -1; // bad directory inode number - ext2_dir_entry_t dentry; - while (!ext2_dir_read_entry(mount, dir, &dentry)) - { - char *dentryName = kcalloc(1, dentry.name_length + 1); - memcpy(dentryName, dentry.name, dentry.name_length); - int res = strcmp(fileName, dentryName); - kfree(dentryName); - if (!res) - { - *direntry = dentry; - ext2_close_dir(mount, dir); - return 0; - } - } - ext2_close_dir(mount, dir); - return -2; -} - -// open a directory by inode number for reading -ext2_open_dir_t *ext2_open_dir(vfs_mount_t *mount, u32_t inode_number) -{ - ext2_open_dir_t *open_dir = New(ext2_open_dir_t); - ext2_open_inode_t *open_inode = ext2_open_inode(mount, inode_number); - if (!open_inode) - { - kfree(open_dir); - return NULL; - } - if ((open_inode->inode.i_mode & EXT2_I_MODE_TYPE_MASK) != EXT2_I_MODE_DIR) - { - ext2_close_inode(mount, open_inode); - kfree(open_dir); - return NULL; - } - open_dir->open_inode = open_inode; - open_dir->position = 0; - return open_dir; -} - -int ext2_dir_read_entry(vfs_mount_t *mount, ext2_open_dir_t *open_dir, ext2_dir_entry_t *dentry) -{ - ext2_super_block_t *super = mount->super; - if (open_dir->position >= open_dir->open_inode->inode.i_size) - return -1; // EOF - u32_t dir_block = open_dir->position >> (10 + super->s_log_block_size); - char *block = kmalloc(2048 << super->s_log_block_size); - ext2_inode_seek(mount, open_dir->open_inode, dir_block); - if (ext2_read_inode_block(mount, open_dir->open_inode, block)) - ext2_read_inode_block(mount, open_dir->open_inode, block + (1024 << super->s_log_block_size)); - ext2_dir_entry_t *dir_entry = (ext2_dir_entry_t *)(block + open_dir->position % (1024 << super->s_log_block_size)); - if (!dir_entry->inode) - { - kfree(block); - return -2; // EOF - } - memcpy(dentry, dir_entry, min(dir_entry->length, sizeof(ext2_dir_entry_t))); - open_dir->position += dir_entry->length; - kfree(block); - return 0; -} - -int ext2_close_dir(vfs_mount_t *mount, ext2_open_dir_t *open_dir) -{ - ext2_close_inode(mount, open_dir->open_inode); - kfree(open_dir); - return 0; -} - - -// open an inode for reading -ext2_open_inode_t *ext2_open_inode(vfs_mount_t *mount, u32_t inode_number) -{ - ext2_open_inode_t *open_inode = New(ext2_open_inode_t); - if ( ext2_read_inode(mount, inode_number, &(open_inode->inode)) ) - { - kfree(open_inode); - return NULL; - } - open_inode->block = 0; - open_inode->block_pointers = NULL; - open_inode->block_pointers_start = 0; - mount->refs++; - return open_inode; -} - - -// seek to a certain block of an open inode -int ext2_inode_seek(vfs_mount_t *mount, ext2_open_inode_t *open_inode, u32_t block_number) -{ - ext2_super_block_t *super = mount->super; - if (open_inode->inode.i_size <= (block_number << (10 + super->s_log_block_size))) - return -1; // at or past EOF - open_inode->block = block_number; - return 0; -} - -// returns number of bytes read -int ext2_read_inode_block(vfs_mount_t *mount, ext2_open_inode_t *open_inode, void *block) -{ - ext2_super_block_t *super = mount->super; - if (open_inode->inode.i_size <= (open_inode->block << (10 + super->s_log_block_size))) - return 0; // at or past EOF - u32_t leftover_bytes = open_inode->inode.i_size - (open_inode->block << (10 + super->s_log_block_size)); - u32_t block_number = ext2_block_number(mount, open_inode); - block_read(mount->major, mount->minor, ext2_FSToDiskBlock(block_number, super), - 2 << super->s_log_block_size, block); - open_inode->block++; - return min(leftover_bytes, 1024 << super->s_log_block_size); -} - - -// close an open inode -int ext2_close_inode(vfs_mount_t *mount, ext2_open_inode_t *open_inode) -{ - mount->refs--; - if (open_inode->block_pointers) - kfree(open_inode->block_pointers); // free the block pointers cache - kfree(open_inode); - return 0; -} - - -// transform open_inode->block (a relative block number) to an absolute block number for the filesystem -u32_t ext2_block_number(vfs_mount_t *mount, ext2_open_inode_t *open_inode) -{ - if (open_inode->block < 12) - return open_inode->inode.i_block[open_inode->block]; - ext2_super_block_t *super = mount->super; - int pointersPerBlock = 256 << super->s_log_block_size; - if (open_inode->block_pointers && // there is a block pointers cache block allocated - (open_inode->block >= open_inode->block_pointers_start) && // and the block number is in it - (open_inode->block < (open_inode->block_pointers_start + pointersPerBlock))) - return open_inode->block_pointers[open_inode->block - open_inode->block_pointers_start]; - u32_t rel_block = open_inode->block - 12; - if (!open_inode->block_pointers) - open_inode->block_pointers = kmalloc(pointersPerBlock << 2); - if (rel_block < pointersPerBlock) // indirect block in i_block[12] - { - block_read(mount->major, mount->minor, ext2_FSToDiskBlock(open_inode->inode.i_block[12], super), - 2 << super->s_log_block_size, open_inode->block_pointers); - open_inode->block_pointers_start = 12; - return open_inode->block_pointers[rel_block]; - } - rel_block -= pointersPerBlock; - if (rel_block < (pointersPerBlock * pointersPerBlock)) // double-indirect block in i_block[13] - { - block_read(mount->major, mount->minor, ext2_FSToDiskBlock(open_inode->inode.i_block[13], super), - 2 << super->s_log_block_size, open_inode->block_pointers); - u32_t real_block = open_inode->block_pointers[rel_block / pointersPerBlock]; - block_read(mount->major, mount->minor, ext2_FSToDiskBlock(real_block, super), - 2 << super->s_log_block_size, open_inode->block_pointers); - open_inode->block_pointers_start = 12 + pointersPerBlock + rel_block - (rel_block % pointersPerBlock); - return open_inode->block_pointers[rel_block % pointersPerBlock]; - } - // this code shouldn't run unless we are dealing with a 65+mb file ... - rel_block -= pointersPerBlock * pointersPerBlock; - block_read(mount->major, mount->minor, ext2_FSToDiskBlock(open_inode->inode.i_block[14], super), - 2 << super->s_log_block_size, open_inode->block_pointers); - u32_t index_1 = rel_block / (pointersPerBlock * pointersPerBlock); - u32_t leftover_1 = rel_block % (pointersPerBlock * pointersPerBlock); - u32_t block_1 = open_inode->block_pointers[index_1]; - block_read(mount->major, mount->minor, ext2_FSToDiskBlock(block_1, super), - 2 << super->s_log_block_size, open_inode->block_pointers); - u32_t index_2 = leftover_1 / pointersPerBlock; - u32_t leftover_2 = leftover_1 % pointersPerBlock; - u32_t block_2 = open_inode->block_pointers[index_2]; - block_read(mount->major, mount->minor, ext2_FSToDiskBlock(block_2, super), - 2 << super->s_log_block_size, open_inode->block_pointers); - open_inode->block_pointers_start = 12 + (pointersPerBlock + 1) * pointersPerBlock + rel_block - (rel_block % pointersPerBlock); - return open_inode->block_pointers[leftover_2]; -} - - -int ext2_resize_inode(vfs_mount_t *mount, u32_t inode_number, u32_t new_size) -{ - ext2_inode_t inode; - if ( ext2_read_inode(mount, inode_number, &inode) ) - return -1; - ext2_super_block_t *super = mount->super; - int current_blocks = (inode.i_size + (1024 << super->s_log_block_size) - 1) >> (10 + super->s_log_block_size); - int new_blocks = (new_size + (1024 << super->s_log_block_size) - 1) >> (10 + super->s_log_block_size); - if ( new_blocks == current_blocks ) - return 0; - - // TODO: resize - u32_t block_size = 1024 << super->s_log_block_size; - u32_t pointers_per_block = block_size >> 2; - u32_t *pointer_cache1 = kmalloc(3 * block_size); - u32_t *pointer_cache2 = pointer_cache1 + pointers_per_block; - u32_t *pointer_cache3 = pointer_cache2 + pointers_per_block; - u32_t c1_start, c2_start, c3_start; - c1_start = c2_start = c3_start = 0; - while (new_blocks < current_blocks) // delete, decrease current_blocks - { - current_blocks--; - // now delete block number current_blocks - - } - - while (current_blocks < new_blocks) // add, increase current_blocks - { - } -} - - -/***************** VFS INTERFACE FUNCTIONS *******************/ - - - -// VFS interface function to open a directory -int ext2__open_dir(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *dir) -{ - if (ext2_inode_status(mount, inode_number) != 1) - return -1; - ext2_open_dir_t *open_dir = ext2_open_dir(mount, inode_number); - if (!open_dir) - return -2; - dir->fs_data = open_dir; - return 0; -} - -// VFS interface function to read a directory entry from an open directory -int ext2__read_dir(vfs_mount_t *mount, vfs_open_file_t *dir, vfs_dir_entry_t *dentry) -{ - ext2_dir_entry_t t_dentry; - int status = ext2_dir_read_entry(mount, dir->fs_data, &t_dentry); - if (status) - return status; - memcpy(dentry->name, t_dentry.name, t_dentry.name_length); - dentry->name[t_dentry.name_length] = 0; - dentry->inode_number = t_dentry.inode; - return 0; -} - -// VFS interface function to close an open directory -int ext2__close_dir(vfs_mount_t *mount, vfs_open_file_t *dir) -{ - return ext2_close_dir(mount, dir->fs_data); -} - - -// VFS interface function to open a file for reading a byte at a time -int ext2__open_file(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *open_file) -{ - if (ext2_inode_status(mount, inode_number) != 1) - return -1; - return 0; -} - -// VFS interface function to read a byte from an open file -int ext2__read_file(vfs_mount_t *mount, vfs_open_file_t *open_file) -{ - return 0; -} - -// VFS interface function to close a byte-file -int ext2__close_file(vfs_mount_t *mount, vfs_open_file_t *open_file) -{ - return 0; -} - - -// VFS interface function to open a file for reading 512-byte blocks at a time -int ext2__open_block_file(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *open_file) -{ - if (ext2_inode_status(mount, inode_number) != 1) - return -1; - ext2_open_inode_t *open_inode = ext2_open_inode(mount, inode_number); - if (!open_inode) - return -2; - if ((open_inode->inode.i_mode & EXT2_I_MODE_TYPE_MASK) != EXT2_I_MODE_FILE) - { - ext2_close_inode(mount, open_inode); - return -3; - } - ext2__open_block_file_t *open_block_file = New(ext2__open_block_file_t); - open_block_file->open_inode = open_inode; - open_block_file->block = 0; - open_file->fs_data = open_block_file; - return 0; -} - -// VFS interface function to read a block from an open block file -// returns the number of bytes read -int ext2__read_block_file(vfs_mount_t *mount, vfs_open_file_t *open_file, void *buffer) -{ - ext2_super_block_t *super = mount->super; - ext2__open_block_file_t *open_block_file = open_file->fs_data; - if (ext2_inode_seek(mount, open_block_file->open_inode, ext2_diskToFSBlock(open_block_file->block, super))) - return 0; // EOF - u8_t *block = kmalloc(1024 << super->s_log_block_size); - u32_t file_position_read = (1024 << super->s_log_block_size) * open_block_file->open_inode->block; - u32_t file_position_want = open_block_file->block << 9; - u32_t data_offset = file_position_want - file_position_read; - int bytes_read = ext2_read_inode_block(mount, open_block_file->open_inode, block); - if (bytes_read <= data_offset) - { - kfree(block); - return 0; // EOF - } - memcpy(buffer, block + data_offset, min(512, bytes_read - data_offset)); - kfree(block); - open_block_file->block++; - return min(512, bytes_read - data_offset); -} - -// VFS interface function to seek to a certain block number of an open block file -int ext2__block_file_seek(vfs_mount_t *mount, vfs_open_file_t *open_file, u32_t block_number) -{ - ext2__open_block_file_t *open_block_file = open_file->fs_data; - return ext2_inode_seek(mount, open_block_file->open_inode, ext2_FSToDiskBlock(block_number, mount->super)); -} - -// VFS interface function to close an open block file -int ext2__close_block_file(vfs_mount_t *mount, vfs_open_file_t *open_file) -{ - ext2__open_block_file_t *open_block_file = open_file->fs_data; - ext2_close_inode(mount, open_block_file->open_inode); - kfree(open_block_file); - return 0; -} - - - diff --git a/kernel/fs/ext2/ext2_working.h b/kernel/fs/ext2/ext2_working.h deleted file mode 100644 index f51249d..0000000 --- a/kernel/fs/ext2/ext2_working.h +++ /dev/null @@ -1,241 +0,0 @@ -// ext2.h -// Author: Josh Holtrop -// Date: 08/22/04 -// Modified: 12/24/04 - -#ifndef __HOS_EXT2_H__ -#define __HOS_EXT2_H__ __HOS_EXT2_H__ - -#include "hos_defines.h" -#include "fs/devices.h" -#include "fs/vfs.h" - -#define EXT2_MAGIC 0xEF53 -#define EXT2_NAME_LEN 255 - -#define EXT2_I_MODE_ATTR_MASK 0x0FFF -#define EXT2_I_MODE_OX 0x0001 -#define EXT2_I_MODE_OW 0x0002 -#define EXT2_I_MODE_OR 0x0004 -#define EXT2_I_MODE_GX 0x0008 -#define EXT2_I_MODE_GW 0x0010 -#define EXT2_I_MODE_GR 0x0020 -#define EXT2_I_MODE_UX 0x0040 -#define EXT2_I_MODE_UW 0x0080 -#define EXT2_I_MODE_UR 0x0100 -#define EXT2_I_MODE_STICKY 0x0200 -#define EXT2_I_MODE_SGID 0x0400 -#define EXT2_I_MODE_SUID 0x0800 - -#define EXT2_I_MODE_TYPE_MASK 0xF000 -#define EXT2_I_MODE_FIFO 0x1000 -#define EXT2_I_MODE_CHAR 0x2000 -#define EXT2_I_MODE_DIR 0x4000 -#define EXT2_I_MODE_BLOCK 0x6000 -#define EXT2_I_MODE_FILE 0x8000 -#define EXT2_I_MODE_SYM 0xA000 -#define EXT2_I_MODE_SOCK 0xC000 - -#define EXT2_I_FLAGS_SEC_DEL 0x01 -#define EXT2_I_FLAGS_UNDELETE 0x02 -#define EXT2_I_FLAGS_COMPRESS 0x04 -#define EXT2_I_FLAGS_SYNC 0x08 -#define EXT2_I_FLAGS_IMMUTABLE 0x10 -#define EXT2_I_FLAGS_APPEND 0x20 -#define EXT2_I_FLAGS_NODUMP 0x40 - -#define EXT2_INODE_BAD_BLOCKS 1 -#define EXT2_INODE_ROOT 2 -#define EXT2_INODE_ACL_INDEX 3 -#define EXT2_INODE_ACL_DATA 4 -#define EXT2_INODE_BOOT_LOADER 5 -#define EXT2_INODE_UNDELETE_DIR 6 -#define EXT2_INODE_AVAIL 11 - -#define EXT2_FT_UNKNOWN 0 -#define EXT2_FT_FILE 1 -#define EXT2_FT_DIR 2 -#define EXT2_FT_CHAR 3 -#define EXT2_FT_BLOCK 4 -#define EXT2_FT_FIFO 5 -#define EXT2_FT_SOCK 6 -#define EXT2_FT_SYMLINK 7 -#define EXT2_FT_MAX 8 - -typedef struct -{ - u32_t s_inodes_count; /* Inodes count */ - u32_t s_blocks_count; /* Blocks count */ - u32_t s_r_blocks_count; /* Reserved blocks count */ - u32_t s_free_blocks_count; /* Free blocks count */ - u32_t s_free_inodes_count; /* Free inodes count */ - u32_t s_first_data_block; /* First Data Block */ - u32_t s_log_block_size; /* Block size: 0->1024, 1->2048, 2->4096 */ - int s_log_frag_size; /* Fragment size */ - u32_t s_blocks_per_group; /* # Blocks per group */ - u32_t s_frags_per_group; /* # Fragments per group */ - u32_t s_inodes_per_group; /* # Inodes per group */ - u32_t s_mtime; /* Mount time */ - u32_t s_wtime; /* Write time */ - u16_t s_mnt_count; /* Mount count */ - short s_max_mnt_count; /* Maximal mount count */ - u16_t s_magic; /* Magic signature */ - u16_t s_state; /* File system state */ - u16_t s_errors; /* Behaviour when detecting errors */ - u16_t s_minor_rev_level; /* minor revision level */ - u32_t s_lastcheck; /* time of last check */ - u32_t s_checkinterval; /* max. time between checks */ - u32_t s_creator_os; /* OS */ - u32_t s_rev_level; /* Revision level */ - u16_t s_def_resuid; /* Default uid for reserved blocks */ - u16_t s_def_resgid; /* Default gid for reserved blocks */ - - u32_t s_reserved[235]; -} ext2_super_block_t; - -typedef struct -{ - u32_t bg_block_bitmap; // Blocks bitmap block - u32_t bg_inode_bitmap; // Inode bitmap block - u32_t bg_inode_table; // Inode table block - u16_t bg_free_blocks_count; // Free blocks count - u16_t bg_free_inodes_count; // Free Inodes count - u16_t bg_used_dirs_count; // Directories count - u16_t bg_pad1; - u32_t bg_reserved[3]; -} ext2_group_desc_t; - -typedef struct -{ - u16_t i_mode; // File mode - u16_t i_uid; // Owner UID - u32_t i_size; // Size in bytes - u32_t i_atime; // Access time - u32_t i_ctime; // Creation time - u32_t i_mtime; // Modification time - u32_t i_dtime; // Deletion time - u16_t i_gid; // Group ID - u16_t i_links_count; // Links count - u32_t i_blocks; // Blocks count - u32_t i_flags; // File flags - u32_t i_reserved1; - u32_t i_block[15]; // Pointers to blocks (12 direct, single, double, triple indirect) - u32_t i_version; // File version (for NFS) - u32_t i_file_acl; // File ACL - u32_t i_dir_acl; // Directory ACL - u32_t i_faddr; // Fragment address - u8_t i_frag; // Fragment number - u8_t i_fsize; // Fragment size - u16_t i_pad1; - u32_t i_reserved2[2]; -} ext2_inode_t; - -typedef struct -{ - u32_t inode; // inode number - u16_t length; // directory entry length - u8_t name_length; // name length - u8_t file_type; // File type - char name[EXT2_NAME_LEN]; -} ext2_dir_entry_t; - -typedef struct -{ - ext2_inode_t inode; - u32_t block; - u32_t *block_pointers; - u32_t block_pointers_start; -} ext2_open_inode_t; - -typedef struct -{ - ext2_open_inode_t *open_inode; - u32_t position; -} ext2_open_dir_t; - -typedef struct -{ - ext2_open_inode_t *open_inode; - u32_t position; - u32_t buffer_start; - u32_t buffer_bytes; - u8_t *buffer; -} ext2__open_file_t; - -typedef struct -{ - ext2_open_inode_t *open_inode; - u32_t block; -} ext2__open_block_file_t; - -static inline u32_t ext2_diskToFSBlock(u32_t block, ext2_super_block_t *super) -{ - // convert # of disk blocks to # of filesystem blocks - return block >> (super->s_log_block_size + 1); -} - -static inline u32_t ext2_FSToDiskBlock(u32_t block, ext2_super_block_t *super) -{ - // convert # of filesystem blocks to # of disk blocks - return block << (super->s_log_block_size + 1); -} - - -int ext2_init(int fsID); -int ext2_read_inode(vfs_mount_t *mount, u32_t inode, ext2_inode_t *dat); -int ext2_write_inode(vfs_mount_t *mount, u32_t inode, ext2_inode_t *dat); -ext2_group_desc_t ext2_get_group_desc(vfs_mount_t *mount, u32_t group); -void ext2_write_group_desc(vfs_mount_t *mount, u32_t group_num, ext2_group_desc_t *gd); -ext2_open_inode_t *ext2_open_inode(vfs_mount_t *mount, u32_t inode_number); -int ext2_close_inode(vfs_mount_t *mount, ext2_open_inode_t *open_inode); -int ext2_read_inode_block(vfs_mount_t *mount, ext2_open_inode_t *open_inode, void *block); -u32_t ext2_block_number(vfs_mount_t *mount, ext2_open_inode_t *open_inode); -int ext2_inode_seek(vfs_mount_t *mount, ext2_open_inode_t *open_inode, u32_t block_number); - -int ext2_inode_status(vfs_mount_t *mount, u32_t inode_number); -int ext2_block_status(vfs_mount_t *mount, u32_t block_number); - -u32_t ext2_alloc_inode(vfs_mount_t *mount); -int ext2_free_inode(vfs_mount_t *mount, u32_t inode_number); -u32_t ext2_alloc_block(vfs_mount_t *mount); -int ext2_free_block(vfs_mount_t *mount, u32_t block_number); - -u32_t ext2_reserve_node(vfs_mount_t *mount, u32_t bitmap_block_num, u32_t bitmap_size); -int ext2_free_node(vfs_mount_t *mount, u32_t bitmap_block_num, u32_t node_number); -int ext2_num_block_groups(ext2_super_block_t *super); -void ext2_write_super(vfs_mount_t *mount); - -int ext2_resize_inode(vfs_mount_t *mount, u32_t inode_number, u32_t new_size); - -ext2_open_dir_t *ext2_open_dir(vfs_mount_t *mount, u32_t inode_number); -int ext2_dir_read_entry(vfs_mount_t *mount, ext2_open_dir_t *open_dir, ext2_dir_entry_t *dentry); -int ext2_close_dir(vfs_mount_t *mount, ext2_open_dir_t *open_dir); -int ext2_dir_lookup(vfs_mount_t *mount, u32_t dir_inode, char *fileName, ext2_dir_entry_t *direntry); - - -void *ext2_mount_super(major_t major, minor_t minor); -int ext2_umount_super(vfs_mount_t *mount); -int ext2_stat(vfs_mount_t *mount, u32_t inode_number, vfs_stat_t *stat); -u32_t ext2__get_root_dir_inode(vfs_mount_t *mount); -int ext2__link_deref(vfs_mount_t *mount, u32_t link_inode, char *link); -int ext2__free_inodes(vfs_mount_t *mount); -int ext2__total_inodes(vfs_mount_t *mount); -int ext2__free_blocks(vfs_mount_t *mount); -int ext2__total_blocks(vfs_mount_t *mount); - - -int ext2__open_dir(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *dir); -int ext2__read_dir(vfs_mount_t *mount, vfs_open_file_t *dir, vfs_dir_entry_t *dentry); -int ext2__close_dir(vfs_mount_t *mount, vfs_open_file_t *dir); - -int ext2__open_file(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *open_file); -int ext2__read_file(vfs_mount_t *mount, vfs_open_file_t *open_file); -int ext2__close_file(vfs_mount_t *mount, vfs_open_file_t *open_file); - -int ext2__open_block_file(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *open_file); -int ext2__read_block_file(vfs_mount_t *mount, vfs_open_file_t *open_file, void *buffer); -int ext2__block_file_seek(vfs_mount_t *mount, vfs_open_file_t *open_file, u32_t block_number); -int ext2__close_block_file(vfs_mount_t *mount, vfs_open_file_t *open_file); - -#endif - diff --git a/kernel/fs/sysfs/sysfs.cpp b/kernel/fs/sysfs/sysfs.cpp deleted file mode 100644 index 3ff960e..0000000 --- a/kernel/fs/sysfs/sysfs.cpp +++ /dev/null @@ -1,42 +0,0 @@ -// sysfs.cpp -// sysfs filesystem driver for HOS -// Author: Josh Holtrop -// Date: 06/27/05 -// Modified: 06/27/05 - -extern "C" { -#include "display/kout.h" -} - -#include "fs/vfs.h" -#include "sysfs.h" -#include "sysfs_entry.h" - -int sysfs_init() -{ - vfs_register("sysfs", sysfs__mount_func); - return 0; -} - -FileSystem *sysfs__mount_func(device_t dev) -{ - if (dev) - kprintf("sysfs: warning: device parameter ignored\n"); - return new Sysfs(); -} - -Sysfs::Sysfs() -{ - myEntries.add(Sysfs_Entry(SYSFS_FILE, "timer", SYSFS_TIMER)); - -} - -Sysfs::~Sysfs() -{ - -} - -u32_t Sysfs::getRootInodeNumber() -{ - return 2; -} diff --git a/kernel/fs/sysfs/sysfs.h b/kernel/fs/sysfs/sysfs.h deleted file mode 100644 index 71ac6ce..0000000 --- a/kernel/fs/sysfs/sysfs.h +++ /dev/null @@ -1,37 +0,0 @@ -// sysfs.h -// sysfs filesystem driver for HOS -// Author: Josh Holtrop -// Date: 06/27/05 -// Modified: 06/27/05 - -#ifndef __HOS_SYSFS_H__ -#define __HOS_SYSFS_H__ __HOS_SYSFS_H__ - -#define SYSFS_TIMER 1 - -#ifdef _HOS_CPP_ - -#include "fs/FileSystem.h" -#include "fs/vfs.h" -#include "lang/vector.h" -#include "lang/string.h" -#include "sysfs_entry.h" - -int sysfs_init(); -FileSystem *sysfs__mount_func(device_t dev); - -class Sysfs : public FileSystem -{ -protected: - vector myEntries; - -public: - Sysfs(); - ~Sysfs(); - u32_t getRootInodeNumber(); -}; - -#endif - -#endif - diff --git a/kernel/fs/sysfs/sysfs_entry.cpp b/kernel/fs/sysfs/sysfs_entry.cpp deleted file mode 100644 index 780b0f4..0000000 --- a/kernel/fs/sysfs/sysfs_entry.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// sysfs_entry.cpp -// sysfs filesystem driver for HOS -// Author: Josh Holtrop -// Date: 06/27/05 -// Modified: 06/27/05 - -#include "sysfs_entry.h" -#include "lang/string.h" - -Sysfs_Entry::Sysfs_Entry(int type, string name, int id) -{ - myType = type; - myName = name; - myID = id; -} - -Sysfs_Entry::~Sysfs_Entry() -{ -} - diff --git a/kernel/fs/sysfs/sysfs_entry.h b/kernel/fs/sysfs/sysfs_entry.h deleted file mode 100644 index 59ec427..0000000 --- a/kernel/fs/sysfs/sysfs_entry.h +++ /dev/null @@ -1,30 +0,0 @@ -// sysfs_entry.h -// sysfs filesystem driver for HOS -// Author: Josh Holtrop -// Date: 06/27/05 -// Modified: 06/27/05 - -#ifndef __HOS_SYSFS_ENTRY_H__ -#define __HOS_SYSFS_ENTRY_H__ __HOS_SYSFS_ENTRY_H__ - -#include "lang/vector.h" -#include "lang/string.h" - -#define SYSFS_DIR 1 -#define SYSFS_FILE 2 - -class Sysfs_Entry -{ -protected: - int myType; - string myName; - int myID; - vector myChildren; - -public: - Sysfs_Entry(int type, string name, int id); - ~Sysfs_Entry(); -}; - -#endif - diff --git a/kernel/fs/vfs.cpp b/kernel/fs/vfs.cpp deleted file mode 100644 index 8467845..0000000 --- a/kernel/fs/vfs.cpp +++ /dev/null @@ -1,413 +0,0 @@ -// vfs.cpp -// Virtual file system subsystem for HOS -// Author: Josh Holtrop -// Date: 05/10/05 -// Modified: 12/26/05 - -extern "C" { -#include "hos_defines.h" -#include "display/kout.h" -#include "functions.h" -#include "lang/lang.h" -} - -#include "vfs.h" -#include "fs/FileSystem.h" -#include "fs/VFSMount.h" -#include "fs/ext2/ext2.h" -#include "lang/vector.h" -#include "lang/string.h" -#include "devices.h" - - -/* Internal module function prototypes */ -FileSystem *vfs_attempt_mount(device_t device, char *fsType); -mount_func_t vfs_get_mount_func(const string & fsName); -inode_num_t vfs_get_inode(const string & path); -inode_num_t vfs_get_dir_inode(const string & path); -inode_num_t vfs_get_inode_rel(const string & path, inode_num_t start_dir); -inode_num_t vfs_get_dir_entry_inode(inode_num_t dir, const string & fname); -int vfs_stat_inode(inode_num_t inum, vfs_stat_t *statptr); -int vfs_link_deref_inode(inode_num_t inum, char *link); -VFSMount *vfs_get_mount(u32_t mt_id); -vector vfs_split_dirs(const string & path); -OpenDirectory *vfs_open_directory_inode(inode_num_t inum, int mode); -OpenFile *vfs_open_file_inode(inode_num_t inum, int mode); -void vfs_close_directory_real(OpenDirectory *o); -void vfs_close_file_real(OpenFile *o); -inode_num_t vfs_get_real_inode(inode_num_t inum); - -/* Global module data members */ -vector *mountPoints; -vector *fses; - -u32_t mount_id = 0; - -/* initialize the VFS module */ -int vfs_init() -{ - mountPoints = new vector; - fses = new vector; - ext2_init(); - return 0; -} - -/* register a filesystem driver to the VFS module */ -int vfs_register(char *fs, mount_func_t mount_func) -{ - string fsName(fs); - if (vfs_get_mount_func(fsName)) - return -1; - FSHandle fsh = {fsName, mount_func}; - fses->add(fsh); - return 0; -} - -/* mount a device with a filesystem to a mount point */ -int vfs_mount(device_t device, char *fsType, char *mountPoint) -{ - string mountPt(mountPoint); - string fsName(fsType); - /* Bad filesystem type */ - if (!vfs_get_mount_func(fsName)) - { - kprintf("vfs_mount: %s: unrecognized filesystem\n", fsType); - return -501; - } - if (mountPt == "/") - { - if (mountPoints->size()) - { - kprintf("/ must be the first filesystem mounted!\n"); - return -1; - } - FileSystem *fs = vfs_attempt_mount(device, fsType); - /* Couldn't mount root */ - if (fs == NULL) - return -2; - mountPoints->add(new VFSMount(device, fsName, fs, mountPt, 0, fs->getRootInodeNumber())); - mount_id++; - return 0; - } - inode_num_t mtInode = vfs_get_inode(mountPt); - /* Invalid mount point */ - if (mtInode == 0) - return -3; - FileSystem *fs = vfs_attempt_mount(device, fsType); - /* Couldn't mount */ - if (fs == NULL) - return -2; - inode_num_t thisInode = (((u64_t)(mount_id++)) << 32) | fs->getRootInodeNumber(); - mountPoints->add(new VFSMount(device, fsName, fs, mountPt, mtInode, thisInode)); - return 0; -} - -/* get mount information about the mount point */ -int vfs_get_mount_info(unsigned int mountNum, vfs_mount_info_t *infoptr) -{ - if (mountNum >= mountPoints->size()) - return -1; - VFSMount *mt = (*mountPoints)[mountNum]; - strcpy(infoptr->fs, mt->myFSType.data()); - strcpy(infoptr->mountPoint, mt->myMountPoint.data()); - infoptr->totalBlocks = mt->myFS->totalBlocks(); - infoptr->freeBlocks = mt->myFS->freeBlocks(); - infoptr->totalInodes = mt->myFS->totalInodes(); - infoptr->freeInodes = mt->myFS->freeInodes(); - return 0; -} - -/* unmount a device */ -int vfs_umount(device_t dev) -{ - unsigned int max = mountPoints->size(); - for (unsigned int i = 0; i < max; i++) - { - if ((*mountPoints)[i]->myDev == dev) - { - if ((*mountPoints)[i]->umount_safe()) - return -502; - delete (*mountPoints)[i]; - mountPoints->remove(i); - return 0; - } - } - return -501; -} - -/* stat a filename */ -int vfs_stat(char *name, vfs_stat_t *buff) -{ - string sname = string(name); - inode_num_t inum; - if ((inum = vfs_get_inode(sname)) == 0ULL) - return -502; - return vfs_stat_inode(inum, buff); -} - -/* dereference a symbolic link */ -int vfs_link_deref(char *name, char *buff) -{ - string sname = string(name); - inode_num_t inum; - if ((inum = vfs_get_inode(sname)) == 0ULL) - return -502; - return vfs_link_deref_inode(inum, buff); -} - -void *vfs_open_dir(char *name) -{ - string sname(name); - inode_num_t inum = vfs_get_inode(sname); - return (void *) vfs_open_directory_inode(inum, VFS_MODE_READ); -} - -void *vfs_open_file(char *name, int mode) -{ - string sname(name); - inode_num_t inum = vfs_get_inode(sname); - return (void *) vfs_open_file_inode(inum, mode); -} - -void vfs_close_dir(void *o) -{ - vfs_close_directory_real((OpenDirectory *) o); -} - -void vfs_close_file(void *o) -{ - vfs_close_file_real((OpenFile *) o); -} - -int vfs_read_dir(void *o, vfs_dir_entry_t *dirent) -{ - OpenDirectory *odir = (OpenDirectory *) o; - return odir->read(dirent); -} - -int vfs_seek_dir(void *o, int pos, int mode) -{ - OpenDirectory *odir = (OpenDirectory *) o; - return odir->seek(pos, mode); -} - -int vfs_read_file(void *o) -{ - OpenFile *ofile = (OpenFile *) o; - return ofile->read(); -} - -int vfs_read_file_block(void *o, void *buf, u32_t num) -{ - OpenFile *ofile = (OpenFile *) o; - return ofile->read(buf, num); -} - -int vfs_write_file(void *o, int chr) -{ - OpenFile *ofile = (OpenFile *) o; - return ofile->write(chr); -} - -int vfs_write_file_block(void *o, void *buf, u32_t num) -{ - OpenFile *ofile = (OpenFile *) o; - return ofile->write(buf, num); -} - -int vfs_seek_file(void *o, int pos, int mode) -{ - OpenFile *ofile = (OpenFile *) o; - return ofile->seek(pos, mode); -} - - - - - -/**************************** Internal functions ****************************/ -/* "attempt" a mount */ -FileSystem *vfs_attempt_mount(device_t device, char *fsType) -{ - mount_func_t mount_func; - if (( mount_func = vfs_get_mount_func(string(fsType)) )) - return mount_func(device); - else - return NULL; -} - -/* Trace a file name to make an inode */ -inode_num_t vfs_get_inode(const string & path) -{ - return vfs_get_inode_rel(path, 0ULL); -} - -/* Just get the inode of the directory containing the file */ -inode_num_t vfs_get_dir_inode(const string & path) -{ - vector paths = vfs_split_dirs(path); - string dirPath(""); - for (unsigned int i = 0; i < paths.size()-1; i++) - { - dirPath += "/"; - dirPath += paths[i]; - } - return vfs_get_inode_rel(dirPath, 0ULL); -} - -/* Trace file name to inode starting from this directory (recursive) */ -inode_num_t vfs_get_inode_rel(const string & path, inode_num_t start_dir) -{ - vector paths = vfs_split_dirs(path); - unsigned int paths_size = paths.size(); - inode_num_t currentInum = start_dir; - for (unsigned int i = 0; i < paths_size; i++) - { - currentInum = vfs_get_dir_entry_inode(currentInum, paths[i]); - if (currentInum == 0ULL) - return 0ULL; - currentInum = vfs_get_real_inode(currentInum); - } - return currentInum; -} - -/* return the inode of a directory entry in the directory pointed to by dir */ -inode_num_t vfs_get_dir_entry_inode(inode_num_t dir, const string & fname) -{ - OpenDirectory *odir = vfs_open_directory_inode(dir, VFS_MODE_READ); - if (odir == NULL) - return 0ULL; - vfs_dir_entry_t dir_ent; - inode_num_t inum = 0ULL; - while (vfs_read_dir(odir, &dir_ent) == 0) - { - if (strcmp(dir_ent.name, fname.data()) == 0) - { - inum = (dir & 0xFFFFFFFF00000000ULL) | dir_ent.inum; - break; - } - } - vfs_close_directory_real(odir); - return inum; -} - -/* Just split up a string into a vector of strings based on the path - * delimeter character ('/'). - */ -vector vfs_split_dirs(const string & path) -{ - char *sptr = new char[path.size() + 1]; - strcpy(sptr, path.data()); - char *bptr = sptr; - char *cptr = sptr; - vector parts; - while (*cptr) - { - if (*cptr == '/') - { - *cptr = 0; - string dir(bptr); - if (dir.size() > 0) - parts.add(dir); - bptr = cptr + 1; - } - cptr++; - } - string dir(bptr); - if (dir.size() > 0) - parts.add(dir); - delete sptr; - return parts; -} - -/* Return a pointer to the mount function for a certain file system type */ -mount_func_t vfs_get_mount_func(const string & fsName) -{ - unsigned int max = fses->size(); - for (unsigned int i = 0; i < max; i++) - { - if (fsName == (*fses)[i].name) - return (*fses)[i].mount_func; - } - return NULL; -} - -/* Return a pointer to a VFSMount by the "mount id" (upper 32 bits of inode) */ -VFSMount *vfs_get_mount(u32_t mt_id) -{ - int max = mountPoints->size(); - for (int i = 0; i < max; i++) - { - if (((*mountPoints)[i]->myThisInode >> 32) == mt_id) - return (*mountPoints)[i]; - } - return NULL; -} - -/* FS function: stat a inode, return error code */ -int vfs_stat_inode(inode_num_t inum, vfs_stat_t *statptr) -{ - inum = vfs_get_real_inode(inum); - VFSMount *mt = vfs_get_mount(inum >> 32); - if (mt == NULL) - return -501; - return mt->myFS->stat((u32_t)inum, statptr); -} - -/* FS function: dereference a link by inode number, return error code */ -int vfs_link_deref_inode(inode_num_t inum, char *link) -{ - inum = vfs_get_real_inode(inum); - VFSMount *mt = vfs_get_mount(inum >> 32); - if (mt == NULL) - return -501; - return mt->myFS->link_deref((u32_t)inum, link); -} - -/* FS function: open a directory based on the inode number */ -OpenDirectory *vfs_open_directory_inode(inode_num_t inum, int mode) -{ - inum = vfs_get_real_inode(inum); - VFSMount *mt = vfs_get_mount(inum >> 32); - if (mt == NULL) - return NULL; - return mt->myFS->openDirectory((u32_t)inum, mode); -} - -/* FS function: open a file based on the inode number */ -OpenFile *vfs_open_file_inode(inode_num_t inum, int mode) -{ - inum = vfs_get_real_inode(inum); - VFSMount *mt = vfs_get_mount(inum >> 32); - if (mt == NULL) - return NULL; - return mt->myFS->openFile((u32_t)inum, mode); -} - -/* FS function: close a directory */ -void vfs_close_directory_real(OpenDirectory *o) -{ - delete o; -} - -/* FS function: close a file */ -void vfs_close_file_real(OpenFile *o) -{ - delete o; -} - -/* return the "real" inode number based on the given one - * This function enables inode numbers for directories that have something - * mounted in them to be converted to the inode number for the root directory - * of that mounted filesystem - */ -inode_num_t vfs_get_real_inode(inode_num_t inum) -{ - unsigned int mounts = mountPoints->size(); - for (unsigned int i = 0; i < mounts; i++) - { - if ((*mountPoints)[i]->myMountInode == inum) - return (*mountPoints)[i]->myThisInode; - } - return inum; -} diff --git a/kernel/fs/vfs.h b/kernel/fs/vfs.h deleted file mode 100644 index 47de185..0000000 --- a/kernel/fs/vfs.h +++ /dev/null @@ -1,129 +0,0 @@ -// vfs.h -// Virtual file system subsystem for HOS -// Author: Josh Holtrop -// Date: 05/10/05 -// Modified: 12/26/05 - -#ifndef __HOS_VFS_H__ -#define __HOS_VFS_H__ __HOS_VFS_H__ - -#define VFS_FT_UNKNOWN 0 -#define VFS_FT_FILE 1 -#define VFS_FT_DIR 2 -#define VFS_FT_CHAR 3 -#define VFS_FT_BLOCK 4 -#define VFS_FT_FIFO 5 -#define VFS_FT_SOCK 6 -#define VFS_FT_SYMLINK 7 - -#define VFS_PERMS_OX 0x0001 -#define VFS_PERMS_OW 0x0002 -#define VFS_PERMS_OR 0x0004 -#define VFS_PERMS_GX 0x0008 -#define VFS_PERMS_GW 0x0010 -#define VFS_PERMS_GR 0x0020 -#define VFS_PERMS_UX 0x0040 -#define VFS_PERMS_UW 0x0080 -#define VFS_PERMS_UR 0x0100 -#define VFS_PERMS_STICKY 0x0200 -#define VFS_PERMS_SGID 0x0400 -#define VFS_PERMS_SUID 0x0800 - -#define EOF -256 - -#define VFS_MAX_FILENAME 255 -#define VFS_MAX_PATH_LENGTH 1024 - -#define SEEK_ABSOLUTE 0 -#define SEEK_RELATIVE 1 -#define SEEK_END 2 - -#define VFS_MODE_RW_MASK 0x1 -#define VFS_MODE_READ 0x0 -#define VFS_MODE_WRITE 0x1 -#define VFS_MODE_WRITE_MASK 0x2 -#define VFS_MODE_TRUNCATE 0x0 -#define VFS_MODE_APPEND 0x2 - -#include "hos_defines.h" -#include "devices.h" - - -typedef struct -{ - u16_t type; // file type, of VFS_FT_* - u32_t size; - u32_t inode; - u16_t permissions; - u16_t uid; - u16_t gid; - u32_t atime; - u32_t mtime; - u32_t ctime; - u16_t links; - u32_t dev; -} vfs_stat_t; - -typedef struct -{ - char name[VFS_MAX_FILENAME + 1]; - u32_t inum; -} vfs_dir_entry_t; - -typedef struct -{ - char fs[16]; - char mountPoint[256]; - u32_t totalBlocks; - u32_t freeBlocks; - u32_t totalInodes; - u32_t freeInodes; -} vfs_mount_info_t; - -typedef u64_t inode_num_t; - -#ifdef _HOS_CPP_ -extern "C" { -#endif - -int vfs_init(); -int vfs_mount(device_t device, char *fsType, char *mountPoint); -int vfs_umount(device_t dev); -int vfs_stat(char *name, vfs_stat_t *buff); -int vfs_link_deref(char *name, char *buff); -int vfs_get_mount_info(unsigned int mountNum, vfs_mount_info_t *infoptr); -void *vfs_open_dir(char *name); -void *vfs_open_file(char *name, int mode); -void vfs_close_dir(void *o); -void vfs_close_file(void *o); -int vfs_read_dir(void *o, vfs_dir_entry_t *dirent); -int vfs_seek_dir(void *o, int pos, int mode); -int vfs_read_file(void *o); -int vfs_read_file_block(void *o, void *buf, u32_t num); -int vfs_write_file(void *o, int chr); -int vfs_write_file_block(void *o, void *buf, u32_t num); -int vfs_seek_file(void *o, int pos, int mode); - - -#ifdef _HOS_CPP_ -} - -#include "lang/string.h" -#include "lang/vector.h" -#include "fs/FileSystem.h" -#include "fs/VFSMount.h" - -typedef FileSystem *(*mount_func_t)(device_t); - -typedef struct -{ - string name; - mount_func_t mount_func; -} FSHandle; - -int vfs_register(char *fs, mount_func_t mount_func); - -#endif - -#endif - diff --git a/kernel/fs/vfs_old.cpp b/kernel/fs/vfs_old.cpp deleted file mode 100644 index f36e601..0000000 --- a/kernel/fs/vfs_old.cpp +++ /dev/null @@ -1,432 +0,0 @@ -// vfs.cpp -// Author: Josh Holtrop -// Date: 08/22/04 -// Modified: 12/21/04 - -#define _HOS_CPP_ _HOS_CPP_ - -extern "C" -{ -#include "hos_defines.h" -#include "display/kout.h" -#include "fs/vfs.h" -#include "fs/ext2.h" -#include "kernel.h" -#include "mm/vmm.h" -#include "lang/lang.h" -} - - -vfs_fs_t *fses[VFS_MAX_FS]; // a vfs_fs structure for every filesystem we support -vfs_mount_t *mounts; - -// basic initialization routine, init all filesystem drivers -int vfs_init() -{ - k_check(ext2_init(FS_EXT2), "ext2_init() failed!"); - FileSystem fs; - FileSystem *ext2 = new Ext2(); - FileSystem *jfs = new JoshsFS(); - fs.out(); - ext2->out(); - jfs->out(); - return 0; -} - - -// called by a filesystem driver to let us know that it is ready to handle fs requests -int vfs_register_fs(int fsn, vfs_fs_t *fs) -{ - if (fsn < 0 || fsn >= VFS_MAX_FS || fses[fsn]) - { - kprintf("Invalid filesystem register: %d\n", fsn); - return -1; - } - fses[fsn] = fs; - return 0; -} - -// called to mount a block device with a certain filesystem to a part of our VFS Mount Tree -int vfs_mount(major_t maj, minor_t min, int fsType, char *mountPoint) -{ - if (fsType < 0 || fsType >= VFS_MAX_FS || !fses[fsType]) - return -1; // invalid filesystem type - if (!strcmp("/", mountPoint)) - { - if (mounts) - return -2; // root already mounted - void *super = fses[fsType]->mount_super(maj, min); - if (!super) - return -3; // didn't mount superblock - vfs_mount_t *mnt = (vfs_mount_t *) New(vfs_mount_t); - mnt->refs = 0; - mnt->fs = fsType; - mnt->major = maj; - mnt->minor = min; - mnt->super = super; - mnt->next = NULL; - mnt->prev = NULL; - mnt->mountPoint = (char *) kmalloc(2); - strcpy(mnt->mountPoint, mountPoint); - mnt->vfs_mount_inode = 0; // root not mounted on another fs - mnt->vfs_root_inode = ((vfs_inode_t)maj << 40) | ((vfs_inode_t)min << 32) | fses[fsType]->get_root_inode(mnt); - mnt->vfs_up_inode = mnt->vfs_root_inode; - mounts = mnt; - return 0; // successfully mounted root - } - if (mountPoint[0] != '/') - return -3; // mount point must be absolute - if (!mounts) - return -4; // no root dir yet - vfs_stat_t stat; - if (vfs_stat(mountPoint, &stat)) - return -5; // error statting - if (stat.type != VFS_FT_DIR) - return -6; // mountPoint not a directory - vfs_inode_t vfs_inode = vfs_get_inode_number(mountPoint); - vfs_inode_t updir = vfs_entry_lookup(vfs_inode, ".."); - if (!updir || (updir & 0x8000000000000000ULL)) - return -7; - void *super = fses[fsType]->mount_super(maj, min); - if (!super) - return -3; // didn't mount superblock - vfs_mount_t *mnt = (vfs_mount_t *) New(vfs_mount_t); - mnt->refs = 0; - mnt->super = super; - mnt->fs = fsType; - mnt->major = maj; - mnt->minor = min; - mnt->mountPoint = (char *) kmalloc(strlen(mountPoint) + 1); - strcpy(mnt->mountPoint, mountPoint); - mnt->vfs_mount_inode = vfs_inode; - mnt->vfs_up_inode = updir; - mnt->vfs_root_inode = ((vfs_inode_t)maj << 40) | ((vfs_inode_t)min << 32) | fses[fsType]->get_root_inode(mnt); - vfs_mount_t *mount = mounts; - while (mount->next) - mount = mount->next; - mount->next = mnt; // add mnt to end of mounts list - mnt->prev = mount; - mnt->next = NULL; - vfs_get_file_addr(updir).mount->refs++; - return -256; -} - -int vfs_umount(char *mountPoint) -{ - vfs_inode_t vfs_inode = vfs_get_inode_number(mountPoint); - if (!vfs_inode || (vfs_inode & 0x8000000000000000ULL)) - return -1; // invalid - vfs_mount_t *mnt = mounts; - while (mnt) - { - if (mnt->vfs_root_inode == vfs_inode) // found mount point to unmount - { - if (mnt->refs) - return -2; // open references to mount point; - if (mnt->prev) - mnt->prev->next = mnt->next; - if (mnt->next) - mnt->next->prev = mnt->prev; - if (mnt == mounts) - mounts = NULL; - kfree(mnt->mountPoint); - kfree(mnt); - return 0; - } - } - return -3; // invalid mount point -} - -vfs_inode_t vfs_get_inode_number(char *path) -{ - if (path[0] != '/') - return 0; - if (!mounts) - return 0; - return vfs_get_inode_number_rel(mounts->vfs_root_inode, path + 1); -} - -vfs_inode_t vfs_get_inode_number_rel(vfs_inode_t dir_inode, char *path) -{ - char *path_copy = (char *) kmalloc(strlen(path) + 1); - strcpy(path_copy, path); - int stanzas = str_split(path_copy, '/'); - char *lookup = path_copy; - vfs_inode_t vfs_inode = dir_inode; - for (; stanzas > 0; stanzas--) - { - vfs_inode_t vfs_inode_this_dir = vfs_inode; - vfs_inode = (strcmp("", lookup) ? vfs_entry_lookup(vfs_inode, lookup) : vfs_inode_this_dir); - vfs_stat_t stat; - if (vfs_stat_inode(vfs_inode, &stat)) - return 0x8000000000000002ULL; - if (stat.type == VFS_FT_SYMLINK) - { - char *link = (char *) kmalloc(4096); - vfs_link_deref(vfs_inode, link); - if (link[0] == '/') - vfs_inode = vfs_get_inode_number(link); - else - vfs_inode = vfs_get_inode_number_rel(vfs_inode_this_dir, link); - kfree(link); - } - if (!vfs_inode || (vfs_inode & 0x8000000000000000ULL)) - { - kfree(path_copy); - return 0; - } - lookup = str_advance(lookup); - } - kfree(path_copy); - return vfs_inode; -} - -// look for entry in dir_inode, return the vfs_inode for the entry -vfs_inode_t vfs_entry_lookup(vfs_inode_t dir_inode, char *entry) -{ - vfs_open_file_t *open_dir = vfs_open_dir_inode(dir_inode); - if (!open_dir) - return 0x8000000000000001ULL; - vfs_dir_entry_t dentry; - while (!vfs_read_dir(open_dir, &dentry)) - { - if (!strcmp(dentry.name, entry)) - { - vfs_close_dir(open_dir); - return vfs_real_inode((dir_inode & 0xFFFFFFFF00000000ULL) | dentry.inode_number); - } - } - vfs_close_dir(open_dir); - return 0x8000000000000002ULL; -} - -// return the "real" vfs inode number (inode of the root of -// a mounted filesystem instead of the inode of the folder -// that the filesystem is mounted to) -vfs_inode_t vfs_real_inode(vfs_inode_t vfs_inode) -{ - vfs_mount_t *mnt = mounts; - while (mnt) - { - if (mnt->vfs_mount_inode == vfs_inode) - return mnt->vfs_root_inode; - mnt = mnt->next; - } - return vfs_inode; -} - -// translage a vfs inode number into a mount pointer and relative -// inode for a mounted filesystem -vfs_file_addr_t vfs_get_file_addr(vfs_inode_t vfs_inode) -{ - vfs_inode = vfs_real_inode(vfs_inode); - vfs_file_addr_t addr = {mounts, vfs_inode & 0xFFFFFFFF}; - vfs_mount_t *mnt = mounts; - while (mnt) - { - if ( (mnt->vfs_root_inode & 0xFFFFFFFF00000000ULL) == (vfs_inode & 0xFFFFFFFF00000000ULL) ) - { - addr.mount = mnt; - return addr; - } - mnt = mnt->next; - } - return addr; -} - -int vfs_mount_count() -{ - vfs_mount_t *mnt = mounts; - int count = 0; - while (mnt) - { - count++; - mnt = mnt->next; - } - return count; -} - -vfs_mount_t *vfs_get_mount(int index) -{ - vfs_mount_t *mnt = mounts; - while (mnt && index) - { - mnt = mnt->next; - index--; - } - if (!index) - return mnt; - return NULL; -} - -int vfs_free_inodes(vfs_mount_t *mount) -{ - if (fses[mount->fs]->free_inodes) - return fses[mount->fs]->free_inodes(mount); - return -1; -} - -int vfs_total_inodes(vfs_mount_t *mount) -{ - if (fses[mount->fs]->total_inodes) - return fses[mount->fs]->total_inodes(mount); - return -1; -} - -int vfs_free_blocks(vfs_mount_t *mount) -{ - if (fses[mount->fs]->free_blocks) - return fses[mount->fs]->free_blocks(mount); - return -1; -} - -int vfs_total_blocks(vfs_mount_t *mount) -{ - if (fses[mount->fs]->total_blocks) - return fses[mount->fs]->total_blocks(mount); - return -1; -} - -vfs_inode_t vfs_alloc_inode(vfs_mount_t *mount) -{ - if (fses[mount->fs]->alloc_inode) - { - u32_t fs_inode = fses[mount->fs]->alloc_inode(mount); - if (!fs_inode) - return 0; - return (mount->vfs_root_inode & 0xFFFFFFFF00000000ULL) | fs_inode; - } - return 0; -} - -int vfs_free_inode(vfs_mount_t *mount, u32_t inode_number) -{ - if (fses[mount->fs]->free_inode) - return fses[mount->fs]->free_inode(mount, inode_number); - return -256; -} - -u32_t vfs_alloc_block(vfs_mount_t *mount) -{ - if (fses[mount->fs]->alloc_block) - return fses[mount->fs]->alloc_block(mount); - return 0; -} - -int vfs_free_block(vfs_mount_t *mount, u32_t block_number) -{ - if (fses[mount->fs]->free_block) - return fses[mount->fs]->free_block(mount, block_number); - return -256; -} - -int vfs_link_deref(vfs_inode_t vfs_inode, char *link) -{ - vfs_stat_t stat; - if (vfs_stat_inode(vfs_inode, &stat)) - return -1; - if (stat.type != VFS_FT_SYMLINK) - return -2; - vfs_file_addr_t addr = vfs_get_file_addr(vfs_inode); - if (fses[addr.mount->fs]->link_deref) - return fses[addr.mount->fs]->link_deref(addr.mount, addr.inode, link); - return -3; -} - -// stat a file, fills a vfs_stat_t structure with stat information and returns standard status -int vfs_stat(char *file, vfs_stat_t *stat) -{ - vfs_inode_t vfs_inode = vfs_get_inode_number(file); - if (!vfs_inode || (vfs_inode & 0x8000000000000000ULL)) - return -256; - return vfs_stat_inode(vfs_inode, stat); -} - -int vfs_stat_inode(vfs_inode_t vfs_inode, vfs_stat_t *stat) -{ - vfs_file_addr_t addr = vfs_get_file_addr(vfs_inode); - if (fses[addr.mount->fs]->stat) - return fses[addr.mount->fs]->stat(addr.mount, addr.inode, stat); - return -257; -} - -vfs_open_file_t *vfs_open_dir(char *path) -{ - vfs_inode_t vfs_inode = vfs_get_inode_number(path); - if (!vfs_inode || (vfs_inode & 0x8000000000000000ULL)) - return NULL; - return vfs_open_dir_inode(vfs_inode); -} - -vfs_open_file_t *vfs_open_dir_inode(vfs_inode_t vfs_inode) -{ - vfs_file_addr_t addr = vfs_get_file_addr(vfs_inode); - vfs_open_file_t *open_dir = (vfs_open_file_t *) New(vfs_open_file_t); - if (fses[addr.mount->fs]->open_dir && !(fses[addr.mount->fs]->open_dir(addr.mount, addr.inode, open_dir))) - { - open_dir->mount = addr.mount; - return open_dir; - } - kfree(open_dir); - return NULL; -} - -int vfs_read_dir(vfs_open_file_t *open_dir, vfs_dir_entry_t *dentry) -{ - return !(fses[open_dir->mount->fs]->read_dir && - !(fses[open_dir->mount->fs]->read_dir(open_dir->mount, open_dir, dentry))); -} - -int vfs_close_dir(vfs_open_file_t *open_dir) -{ - int status = 0; - if (fses[open_dir->mount->fs]->close_dir) - status = fses[open_dir->mount->fs]->close_dir(open_dir->mount, open_dir); - kfree(open_dir); - return status; -} - -vfs_open_file_t *vfs_open_block_file(char *path) -{ - vfs_inode_t vfs_inode = vfs_get_inode_number(path); - if (!vfs_inode || (vfs_inode & 0x8000000000000000ULL)) - return NULL; - return vfs_open_block_file_inode(vfs_inode); -} - -vfs_open_file_t *vfs_open_block_file_inode(vfs_inode_t vfs_inode) -{ - vfs_file_addr_t addr = vfs_get_file_addr(vfs_inode); - vfs_open_file_t *open_file = (vfs_open_file_t *) New(vfs_open_file_t); - if (fses[addr.mount->fs]->open_block_file && !(fses[addr.mount->fs]->open_block_file(addr.mount, addr.inode, open_file))) - { - open_file->mount = addr.mount; - return open_file; - } - kfree(open_file); - return NULL; -} - -int vfs_read_block_file(vfs_open_file_t *open_file, void *buffer) -{ - if (fses[open_file->mount->fs]->read_block_file) - return fses[open_file->mount->fs]->read_block_file(open_file->mount, open_file, buffer); - return 0; -} - -int vfs_block_file_seek(vfs_open_file_t *open_file, u32_t block_number) -{ - if (fses[open_file->mount->fs]->block_file_seek) - return fses[open_file->mount->fs]->block_file_seek(open_file->mount, open_file, block_number); - return -1; -} - -int vfs_close_block_file(vfs_open_file_t *open_file) -{ - int status = 0; - if (fses[open_file->mount->fs]->close_block_file) - status = fses[open_file->mount->fs]->close_block_file(open_file->mount, open_file); - kfree(open_file); - return status; -} - diff --git a/kernel/fs/vfs_old.h b/kernel/fs/vfs_old.h deleted file mode 100644 index c410aec..0000000 --- a/kernel/fs/vfs_old.h +++ /dev/null @@ -1,165 +0,0 @@ -// vfs.h -// Author: Josh Holtrop -// Date: 08/22/04 -// Modified: 12/21/04 - -#ifndef __HOS_VFS_H__ -#define __HOS_VFS_H__ __HOS_VFS_H__ - -#include "hos_defines.h" -#include "fs/devices.h" - -#define FS_EXT2 1 -#define VFS_MAX_FS 10 - -#define VFS_FT_UNKNOWN 0 -#define VFS_FT_FILE 1 -#define VFS_FT_DIR 2 -#define VFS_FT_CHAR 3 -#define VFS_FT_BLOCK 4 -#define VFS_FT_FIFO 5 -#define VFS_FT_SOCK 6 -#define VFS_FT_SYMLINK 7 - -#define VFS_PERMS_OX 0x0001 -#define VFS_PERMS_OW 0x0002 -#define VFS_PERMS_OR 0x0004 -#define VFS_PERMS_GX 0x0008 -#define VFS_PERMS_GW 0x0010 -#define VFS_PERMS_GR 0x0020 -#define VFS_PERMS_UX 0x0040 -#define VFS_PERMS_UW 0x0080 -#define VFS_PERMS_UR 0x0100 -#define VFS_PERMS_STICKY 0x0200 -#define VFS_PERMS_SGID 0x0400 -#define VFS_PERMS_SUID 0x0800 - -#define EOF 1000000 - -typedef u64_t vfs_inode_t; - -/* Structure to hold information about a mount point */ -typedef struct vfs_mount_s -{ - int refs; - void *super; - int fs; - major_t major; - minor_t minor; - char *mountPoint; - vfs_inode_t vfs_mount_inode; - vfs_inode_t vfs_up_inode; - vfs_inode_t vfs_root_inode; - struct vfs_mount_s *next; - struct vfs_mount_s *prev; -} vfs_mount_t; - -typedef struct -{ - u16_t type; // file type, of VFS_FILE_TYPE_* - u32_t size; - u32_t inode; - u16_t permissions; - u16_t uid; - u16_t gid; - u32_t atime; - u32_t mtime; - u32_t ctime; - u16_t links; - u32_t dev; -} vfs_stat_t; - -typedef struct -{ - vfs_mount_t *mount; - void *fs_data; -} vfs_open_file_t; - -typedef struct -{ - char name[257]; - u32_t inode_number; // relative inode number returned from fs -} vfs_dir_entry_t; - -typedef struct -{ - vfs_mount_t *mount; - u32_t inode; -} vfs_file_addr_t; - -/* Every filesystem must provide pointers to its respective functions in a structure like this */ -typedef struct -{ - void *(*mount_super)(major_t major, minor_t minor); - int (*umount_super)(vfs_mount_t *mount); - int (*stat)(vfs_mount_t *mount, u32_t inode_number, vfs_stat_t *stat); - u32_t (*get_root_inode)(vfs_mount_t *mount); - int (*link_deref)(vfs_mount_t *mount, u32_t inode_number, char *link); - int (*free_inodes)(vfs_mount_t *mount); - int (*total_inodes)(vfs_mount_t *mount); - int (*free_blocks)(vfs_mount_t *mount); - int (*total_blocks)(vfs_mount_t *mount); - - u32_t (*alloc_inode)(vfs_mount_t *mount); - int (*free_inode)(vfs_mount_t *mount, u32_t inode_number); - u32_t (*alloc_block)(vfs_mount_t *mount); - int (*free_block)(vfs_mount_t *mount, u32_t block_number); - - int (*open_dir)(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *dir); - int (*read_dir)(vfs_mount_t *mount, vfs_open_file_t *dir, vfs_dir_entry_t *dentry); - int (*close_dir)(vfs_mount_t *mount, vfs_open_file_t *dir); - - int (*open_file)(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *open_file); - int (*read_file)(vfs_mount_t *mount, vfs_open_file_t *open_file); - int (*close_file)(vfs_mount_t *mount, vfs_open_file_t *open_file); - - int (*open_block_file)(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *open_file); - int (*read_block_file)(vfs_mount_t *mount, vfs_open_file_t *open_file, void *buffer); - int (*block_file_seek)(vfs_mount_t *mount, vfs_open_file_t *open_file, u32_t block_number); - int (*close_block_file)(vfs_mount_t *mount, vfs_open_file_t *open_file); - -} vfs_fs_t; - - -int vfs_init(); -int vfs_mount(major_t maj, minor_t min, int fsType, char *mountPoint); -int vfs_umount(char *mountPoint); -int vfs_register_fs(int fsn, vfs_fs_t *fs); -int vfs_umount(char *mountPoint); -vfs_inode_t vfs_get_inode_number(char *path); -vfs_inode_t vfs_get_inode_number_rel(vfs_inode_t dir_inode, char *path); -vfs_inode_t vfs_real_inode(vfs_inode_t vfs_inode); -vfs_file_addr_t vfs_get_file_addr(vfs_inode_t vfs_inode); -vfs_inode_t vfs_entry_lookup(vfs_inode_t dir_inode, char *entry); - -int vfs_mount_count(); -vfs_mount_t *vfs_get_mount(int index); -int vfs_free_inodes(vfs_mount_t *mount); -int vfs_total_inodes(vfs_mount_t *mount); -int vfs_free_blocks(vfs_mount_t *mount); -int vfs_total_blocks(vfs_mount_t *mount); - -vfs_inode_t vfs_alloc_inode(vfs_mount_t *mount); -int vfs_free_inode(vfs_mount_t *mount, u32_t inode_number); -u32_t vfs_alloc_block(vfs_mount_t *mount); -int vfs_free_block(vfs_mount_t *mount, u32_t block_number); - - -int vfs_link_deref(vfs_inode_t vfs_inode, char *link); - -int vfs_stat(char *file, vfs_stat_t *stat); -int vfs_stat_inode(vfs_inode_t vfs_inode, vfs_stat_t *stat); - -vfs_open_file_t *vfs_open_dir(char *path); -vfs_open_file_t *vfs_open_dir_inode(vfs_inode_t inode); -int vfs_read_dir(vfs_open_file_t *open_dir, vfs_dir_entry_t *dentry); -int vfs_close_dir(vfs_open_file_t *open_dir); - -vfs_open_file_t *vfs_open_block_file(char *file); -vfs_open_file_t *vfs_open_block_file_inode(vfs_inode_t vfs_inode); -int vfs_read_block_file(vfs_open_file_t *open_file, void *buffer); -int vfs_block_file_seek(vfs_open_file_t *open_file, u32_t block_number); -int vfs_close_block_file(vfs_open_file_t *open_file); - -#endif - diff --git a/kernel/functions.h b/kernel/functions.h deleted file mode 100644 index 654ff00..0000000 --- a/kernel/functions.h +++ /dev/null @@ -1,111 +0,0 @@ -//functions.h -//05/07/03 Josh Holtrop -//for HOS -//Modified: 02/26/04 - -#ifndef __HOS_FUNCTIONS__ -#define __HOS_FUNCTIONS__ __HOS_FUNCTIONS__ - -#include "hos_defines.h" -#include "sys/io.h" - -#ifdef __cplusplus -extern "C" { -#endif -extern u32_t _code; -extern u32_t _bss; -extern u32_t _end; -#ifdef __cplusplus -} -#endif - -//Enables (SeTs) Interrupt Flag on the processor -static inline void enable_ints() -{ - asm("sti"); -} - -//Disables (CLears) Interrupt Flag on the processor -static inline void disable_ints() -{ - asm("cli"); -} - -//Restarts the computer -static inline void restart() -{ - enable_ints(); - byte temp; - do - { - temp = inportb(0x64); - if (temp & 1) - inportb(0x60); - } while(temp & 2); - - - outportb (0x64, 0xfe); - for (;;) {} -} - -//Halts (freezes) the computer -static inline void halt() -{ - asm("cli"); - asm("hlt"); - while (1) ; -} - -//Initializes 8253 Programmable Interrupt Timer -static inline void timer_init(u32_t freq) -{ - u32_t wait = 1193180 / freq; //how many ticks the PIT must wait before issuing an interrupt - outportb(0x43, 0x34); - outportb(0x40, wait); //lsb - outportb(0x40, wait >> 8); //msb -} - -//Returns the size of the kernel (code & data & bss) -// - this should be 4kb aligned per the linker script -// - this is the amount of RAM the kernel code, data, & bss take -static inline u32_t kernel_size_used() -{ - return (u32_t)(&_end)-(u32_t)(&_code); -} - -//Returns the size of the kernel (code & data) -// - this does not include the bss section -// - this should be 4kb aligned per the linker script -// - this should be the size of kernel.bin -static inline u32_t kernel_size() -{ - return (u32_t)(&_bss)-(u32_t)(&_code); -} - -//converts a binary-coded-decimal byte to its decimal equivalent -static inline byte bcd2byte(byte bcd) -{ - return (10 * ((bcd & 0xF0) >> 4)) + (bcd & 0x0F); -} - -//converts a binary-coded-decimal byte to its decimal equivalent -static inline byte byte2bcd(byte bite) -{ - return ((bite / 10) << 4) | (bite % 10); -} - -// get the maximum of two values -static inline u32_t max(u32_t v1, u32_t v2) -{ - return ( (v2 > v1) ? v2 : v1 ); -} - -// get the minimum of two values -static inline u32_t min(u32_t v1, u32_t v2) -{ - return ( (v2 > v1) ? v1 : v2 ); -} - -#endif - - diff --git a/kernel/gdt.inc b/kernel/gdt.inc deleted file mode 100644 index 1509092..0000000 --- a/kernel/gdt.inc +++ /dev/null @@ -1,57 +0,0 @@ -;gdt.inc -;Author: Josh Holtrop -;Date: 10/30/03 -;Modified: 03/02/04 - -gdtr: - dw gdt_end-gdt-1 - dd GDT_V -gdt: ; 0 - dd 0 - dd 0 - -KERNEL_CODE equ $-gdt ; 8 - dw 0xffff ;limit 15:0 - dw 0x0000 ;base 15:0 - db 0x00 ;base 23:16 - db 0x9A ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A]) - db 0xCF ;flags ([G][D/B][0][0]) / limit 19:16 - db 0x00 ;base 31:24 - -KERNEL_DATA equ $-gdt ; 16 - dw 0xffff ;limit 15:0 - dw 0x0000 ;base 15:0 - db 0x00 ;base 23:16 - db 0x92 ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A]) - db 0xCF ;flags ([G][D/B][0][0]) / limit 19:16 - db 0x00 ;base 31:24 - - -USER_CODE equ $-gdt ; 24 - dw 0xffff ;limit 15:0 - dw 0x0000 ;base 15:0 - db 0x00 ;base 23:16 - db 0xFA ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A]) - db 0xCF ;flags ([G][D/B][0][0]) / limit 19:16 - db 0x00 ;base 31:24 - -USER_DATA equ $-gdt ; 32 - dw 0xffff ;limit 15:0 - dw 0x0000 ;base 15:0 - db 0x00 ;base 23:16 - db 0xF2 ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A]) - db 0xCF ;flags ([G][D/B][0][0]) / limit 19:16 - db 0x00 ;base 31:24 - -TSS0_SEG equ $-gdt ; 40 - dw 0x67 ;limit 15:0 - dw 0 ;base 15:0 - db 0 ;base 23:16 - db 0xE9 ;access ([P][DPL][0][1][0][Busy][1]) - db 0x00 ;flags ([G][0][0][AVL]) / limit 19:16 - db 0 ;base 31:24 - -gdt_end: - - - diff --git a/kernel/hos_defines.h b/kernel/hos_defines.h deleted file mode 100644 index 05c05b4..0000000 --- a/kernel/hos_defines.h +++ /dev/null @@ -1,58 +0,0 @@ -// hos_defines.h -// Author: Josh Holtrop -// Date: 08/15/04 -// Modified: 08/16/04 - -#ifndef __HOS_DEFINES_H__ -#define __HOS_DEFINES_H__ __HOS_DEFINES_H__ - -#define PARALLEL_DEBUG - -#define HOS_TIMER_FREQ 1000 -#define KERNEL_MSG_CONSOLE 11 - -#define VIRT_OFFSET 0xC0000000 -#define PHYS_LOAD 0x00108000 -#define PDBR 0x00104000 -#define VIRT_STACK_TOP 0xD0000000 -#define HEAP_START 0xD0000000 -#define HEAP_LENGTH 0x20000000 - -#define CONSOLE_MEMORY 0xC00B8000 -#define BIOS_CHAR_MAP 0xC00FFA6E -#define LFB_MEMORY 0xF0000000 - -#define SEG_KERNEL_CODE 8 -#define SEG_KERNEL_DATA 16 -#define SEG_USER_CODE 24 -#define SEG_USER_DATA 32 -#define SEG_TSS0 40 - -#define MAX_MODULES 16 -#define MAX_MMAP 16 - -#define NULL 0 - -#define HOS_INIT_TASK "/bin/init" - -#define New(x) kcalloc(1, sizeof(x)) - -typedef unsigned long long u64_t; -typedef unsigned int u32_t; -typedef unsigned short u16_t; -typedef unsigned char u8_t; -typedef unsigned char byte; -typedef int lock_t; - -#ifdef __cplusplus -extern "C" { -#endif -extern u32_t _end; -extern u32_t _bss; -extern u32_t start; -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/kernel/idt.inc b/kernel/idt.inc deleted file mode 100644 index 7310934..0000000 --- a/kernel/idt.inc +++ /dev/null @@ -1,117 +0,0 @@ -;idt.inc -;Author: Josh Holtrop -;Date: 10/30/03 -;Modified: 01/02/06 - -idtr: - dw 50*8-1 ;size of idt - dd IDT_V ;address of idt - - -%macro isr_label 1 -isr_%1: - push eax - mov eax, %1 - jmp isr_main -%endmacro - -isr_label 0 -isr_label 1 -isr_label 2 -isr_label 3 -isr_label 4 -isr_label 5 -isr_label 6 -isr_label 7 -isr_label 8 -isr_label 9 -isr_label 10 -isr_label 11 -isr_label 12 -isr_label 13 -isr_label 14 -isr_label 15 -isr_label 16 -isr_label 17 -isr_label 18 -isr_label 19 -isr_label 20 -isr_label 21 -isr_label 22 -isr_label 23 -isr_label 24 -isr_label 25 -isr_label 26 -isr_label 27 -isr_label 28 -isr_label 29 -isr_label 30 -isr_label 31 -isr_label 32 -isr_label 33 -isr_label 34 -isr_label 35 -isr_label 36 -isr_label 37 -isr_label 38 -isr_label 39 -isr_label 40 -isr_label 41 -isr_label 42 -isr_label 43 -isr_label 44 -isr_label 45 -isr_label 46 -isr_label 47 -isr_label 48 -isr_label 49 - -isr_main: - ; ok, here, we need to duplicate the top item on the stack - ; (the old eax) if the interrupt number is not 8 or 10-14 - ; this is to properly align the stack for both exceptions - ; having and not having error codes - cmp eax, 8 - jz isr_main_nodup ; if int=8, no dup - cmp eax, 10 - jb isr_main_dup ; if int<10, dup - cmp eax, 14 - jbe isr_main_nodup ; if int<=14, no dup -isr_main_dup: ; else dup - sub esp, 4 - push eax - mov eax, [esp+8] - mov [esp+4], eax - pop eax -isr_main_nodup: - push ebx - push ecx - push edx - push edi - push esi - push ebp - push ds - push es - push fs - push gs - - push esp - push eax ;interrupt number - call isr - add esp, 8 - - pop gs - pop fs - pop es - pop ds - pop ebp - pop esi - pop edi - pop edx - pop ecx - pop ebx - add esp, 4 ;bypass error code - pop eax ;original saved eax - - iret - diff --git a/kernel/kernel.c b/kernel/kernel.c deleted file mode 100644 index 19a101a..0000000 --- a/kernel/kernel.c +++ /dev/null @@ -1,288 +0,0 @@ -/* kernel.h - * Author: Josh Holtrop - * Date: 08/16/04 - * Modified: 11/02/05 - * This is the main kernel initialization and boot-strapping file - */ - -#include "kernel.h" -#include "multiboot.h" -#include "module.h" -#include "lang/lang.h" -#include "functions.h" -#include "mm/mm.h" -#include "mm/vmm.h" -#include "lang/conv.h" -#include "devices.h" -#include "display/display.h" -#include "display/kout.h" -#include "sys/io.h" -#include "sys/pic.h" -#include "char/keyboard.h" -#include "block/ramdisk.h" -#include "fs/vfs.h" -#include "fs/ext2/ext2.h" -#include "sys/pci.h" -#include "proc/proc.h" -#include "syscall.h" - -mb_info_t mb_info_block; -mb_mmap_t mb_mmap[MAX_MMAP]; -u32_t mmap_entries; -mb_module_t mb_modules[MAX_MODULES]; -mb_apm_t mb_apm_table; -mb_module_t *real_mode_module; // pointer to real mode module (if present) -real_mode_param_t rm_params; -char mb_cmdline[256]; -int criticalCounter; // semaphore for if interrupts are disabled -u32_t timer; // number of IRQ 0's - -extern u32_t mm_freepages; -extern u32_t proc_new_esp; -extern u32_t cur_task; - -/* This function runs in segmented memory - 0xC000_0000 is mapped to 0x0 but 0x0 - itself is an invalid linear address. Therefore, the multiboot information addresses - must be manually adjusted by VIRT_OFFSET to become valid linear addresses. */ -mb_module_t *k_mbsave(mb_info_t *mbinfo, unsigned int mb_magic) -{ - real_mode_module = NULL; - if (mb_magic != MULTIBOOT_BOOTLOADER_MAGIC) - { - char *msg = "Bad multiboot magic identifier!"; - char *dest = (char *) CONSOLE_MEMORY; - while (*msg) - { - *dest++ = *msg++; - *dest++ = 0x04; //red error message - } - for (;;) ; - } - mb_info_block = *mbinfo; - if (mb_info_block.flags & MB_BOOTLOADER_COMMAND_LINE) - { - mb_info_block.cmdline += VIRT_OFFSET; - memcpy(mb_cmdline, (void *)mb_info_block.cmdline, 256); - mb_cmdline[255] = 0; - } - if (mb_info_block.flags & MB_BOOTLOADER_MODS) - { - mb_info_block.mods_addr += VIRT_OFFSET; - int i; - for (i = 0; i < mb_info_block.mods_count && i < MAX_MODULES; i++) - { - mb_modules[i] = ((mb_module_t *)mb_info_block.mods_addr)[i]; - mb_modules[i].mod_start += VIRT_OFFSET; - mb_modules[i].mod_end += VIRT_OFFSET; - hos_module_header_t *mod = (hos_module_header_t *)mb_modules[i].mod_start; - if (mod->mod_magic == 0x4D534F48 && mod->mod_type == MOD_REAL_MODE) - real_mode_module = &mb_modules[i]; - } - } - if (mb_info_block.flags & MB_BOOTLOADER_MMAP) - { - mb_info_block.mmap_addr += (VIRT_OFFSET - 4); //-4 to get to size field, not base_addr_low field - mb_mmap_t *mmap = (mb_mmap_t *)mb_info_block.mmap_addr; - int i, sz = 0; - for (i = 0; sz < mb_info_block.mmap_length && i < MAX_MMAP; i++) - { - sz += mmap->size + 4; - mb_mmap[i] = *mmap; - mmap = (mb_mmap_t *)(((u32_t) mmap) + mmap->size + 4); - mmap_entries++; - } - } - if (mb_info_block.flags & MB_BOOTLOADER_APM) - { - mb_info_block.apm_table += VIRT_OFFSET; - mb_apm_table = *(mb_apm_t *)mb_info_block.apm_table; - } - return real_mode_module; -} - -/* Main kernel initialization routine */ -void k_init() -{ - criticalCounter++; - pic_remap(0x20, 0x28); - pic_mask1(0); //unmask IRQ's 0-7 - pic_mask2(0); //unmask IRQ's 8-15 - timer_init(HOS_TIMER_FREQ); - mm_init(); - vmm_init(); - devices_init(); - if (real_mode_module) - { - if (rm_params.vid_addr) // there is video memory to map in - { - u32_t vid_mem = rm_params.width * rm_params.height; - switch (rm_params.bpp) - { - case 15: case 16: - vid_mem <<= 1; break; - case 24: - vid_mem *= 3; break; - case 32: - vid_mem <<= 2; break; - } - // map in video memory so we can access the video card's LFB - vmm_mapn(LFB_MEMORY, (u32_t)rm_params.vid_addr, (vid_mem >> 12) + 1); - } - } - display_init(); // initialize display subsystem - kprintf("HOS v0.16 initializing...\n"); - kprintf("Kernel load line: '%s'\n", mb_cmdline); - kprintf("Kernel load size: %d (0x%x) bytes (%d kb)\n", kernel_size(), kernel_size(), kernel_size() >> 10); - kprintf("Kernel memory size: %d (0x%x) bytes (%d kb)\n", kernel_size_used(), kernel_size_used(), kernel_size_used() >> 10); - - k_check(pci_init(), "pci_init() failed!"); - k_check(vfs_init(), "vfs_init() failed!"); - k_check(proc_init(), "proc_init() failed!"); - - int i; - for (i = 0; i < mb_info_block.mods_count; i++) - { - kprintf("Loaded kernel module %d: 0x%x - 0x%x (%d bytes, type %d)\n", i, mb_modules[i].mod_start, mb_modules[i].mod_end, mb_modules[i].mod_end - mb_modules[i].mod_start, ((hos_module_header_t*)mb_modules[i].mod_start)->mod_type); - if (((mb_modules[i].mod_end - mb_modules[i].mod_start) > 2048) && - ((ext2_super_block_t *)(mb_modules[i].mod_start + 1024))->s_magic == EXT2_MAGIC) - { - // we found an initrd - minor_t initrd_minor = ramdisk_register((void *)mb_modules[i].mod_start, mb_modules[i].mod_end - mb_modules[i].mod_start); - kprintf("initrd (%dkb) loaded\n", (mb_modules[i].mod_end - mb_modules[i].mod_start) >> 10); - k_check(vfs_mount(DEV(MAJOR_RAMDISK, initrd_minor), "ext2", "/"), "Kernel panic: Could not mount initrd to /!"); - } - } - - - void *root = vfs_open_dir("///"); - char name[VFS_MAX_PATH_LENGTH]; - if (root) - { - vfs_dir_entry_t dentry; - vfs_stat_t fstat; - while (!vfs_read_dir(root, &dentry)) - { - strcpy(name, "/"); - strcat(name, dentry.name); - vfs_stat(name, &fstat); - kprintf("%d\t", fstat.inode); - putc(fstat.type == VFS_FT_DIR ? 'd' : fstat.type == VFS_FT_CHAR ? 'c' : fstat.type == VFS_FT_BLOCK ? 'b' : fstat.type == VFS_FT_SYMLINK ? 'l' : '-'); - putc(fstat.permissions & VFS_PERMS_UR ? 'r' : '-'); - putc(fstat.permissions & VFS_PERMS_UW ? 'w' : '-'); - putc(fstat.permissions & VFS_PERMS_UX ? 'x' : '-'); - - putc(fstat.permissions & VFS_PERMS_GR ? 'r' : '-'); - putc(fstat.permissions & VFS_PERMS_GW ? 'w' : '-'); - putc(fstat.permissions & VFS_PERMS_GX ? 'x' : '-'); - - putc(fstat.permissions & VFS_PERMS_OR ? 'r' : '-'); - putc(fstat.permissions & VFS_PERMS_OW ? 'w' : '-'); - putc(fstat.permissions & VFS_PERMS_OX ? 'x' : '-'); - - kprintf(" %d\t%d\t%d\t%d\t%s", fstat.links, fstat.uid, fstat.gid, fstat.size, dentry.name); - if (fstat.type == VFS_FT_CHAR || fstat.type == VFS_FT_BLOCK) - kprintf("\t(%d, %d)", fstat.dev >> 8, fstat.dev & 0xFF); - if (fstat.type == VFS_FT_SYMLINK) - { - char *link = kmalloc(4096); - vfs_link_deref(name, link); - kprintf(" -> %s", link); - kfree(link); - } - putc('\n'); - } - vfs_close_dir(root); - } - else - kprintf("Error: Could not open directory\n"); - - /* Create the initial task */ - vfs_stat_t stat; - if (!vfs_stat(HOS_INIT_TASK, &stat)) - { - if (stat.permissions & - (VFS_PERMS_UX | VFS_PERMS_GX | VFS_PERMS_UX)) - { - u8_t *buf = kmalloc(stat.size); - void *file = vfs_open_file(HOS_INIT_TASK, VFS_MODE_READ); - vfs_read_file_block(file, buf, stat.size); - vfs_close_file(file); - create_task(buf, stat.size, 0, 0); - } - } - - criticalCounter--; -} - -void isr(u32_t num, int_stack_t *int_stack) -{ - criticalCounter++; - switch (num) - { - case 0x0: /* divide by zero */ - kprintf("divide by zero, current process: %u\n", cur_task); - break; - case 0x20: // timer - timer++; - (*(u16_t *)CONSOLE_MEMORY)++; - proc_sched(int_stack); - pic_eoi(); - break; - case 0x21: // keyboard - isr_keyboard(); - pic_eoi(); - break; - case 0x30: - syscall(cur_task, int_stack); - break; - case 0x0D: /* general protection (error code) */ - kprintf("General protection fault process %u, error #%u\n", cur_task, int_stack->error); - break; - case 0x0E: /* Page fault (error code) */ - kprintf("Page fault process %u, error #%u\n", cur_task, int_stack->error); - break; - case 0x01: /* debug exception */ - case 0x02: /* non-maskable interrupt */ - case 0x03: /* breakpoint */ - case 0x04: /* overflow */ - case 0x05: /* bound exception */ - case 0x06: /* invalid opcode */ - case 0x07: /* FPU not available */ - case 0x08: /* Double fault (error code) */ - case 0x09: /* coprocessor segment overrun */ - case 0x0A: /* invalid TSS (error code) */ - case 0x0B: /* segment not present (error code) */ - case 0x0C: /* stack exception (error code) */ - case 0x10: /* floating point error */ - case 0x11: /* alignment check */ - case 0x12: /* machine check */ - default: - kprintf("Unhandled interrupt #%d, CR2 = 0x%x, int_stack at 0x%x!\n", num, read_cr2(), int_stack); - halt(); - } - criticalCounter--; -} - - -void k_enter_critical() // functions for implementing "atomic actions" -{ - disable_ints(); - criticalCounter++; -} - -void k_leave_critical() -{ - criticalCounter--; - if (!criticalCounter) - enable_ints(); -} - -void k_check(int val, char *msg) -{ - if (val) - { - kprintf("\e[31;1m%s\n", msg); - halt(); - } -} - diff --git a/kernel/kernel.h b/kernel/kernel.h deleted file mode 100644 index eacc302..0000000 --- a/kernel/kernel.h +++ /dev/null @@ -1,53 +0,0 @@ -// kernel.h -// Author: Josh Holtrop -// Date: 08/16/04 -// Modified: 08/18/05 - -#ifndef __HOS_KERNEL_H__ -#define __HOS_KERNEL_H__ __HOS_KERNEL_H__ - -#include "hos_defines.h" -#include "multiboot.h" - -typedef struct -{ - void *vid_addr; // address of LFB, 0 if console mode - u32_t width; // width in pixels or columns if vid_mem == 0 - u32_t height; // height in pixels or columns if vid_mem == 0 - u32_t bpp; // bits per pixel - 15/16/24/32 -} __attribute__ ((packed)) real_mode_param_t; - -typedef struct -{ - u32_t gs; - u32_t fs; - u32_t es; - u32_t ds; - - u32_t ebp; - u32_t esi; - u32_t edi; - u32_t edx; - - u32_t ecx; - u32_t ebx; - u32_t eax; - - u32_t error; /* valid on exceptions 8, 10-14 */ - u32_t eip; - u32_t cs; - u32_t eflags; - u32_t esp; /* present if privilege transition */ - u32_t ss; -} int_stack_t; - -/* returns true to callee if we should jump to a real mode module */ -mb_module_t *k_mbsave(mb_info_t *mbinfo, unsigned int mb_magic); -void _init(); -void isr(u32_t num, int_stack_t *stack_frame); -void k_enter_critical(); // functions for implementing "atomic actions" -void k_leave_critical(); -void k_check(int val, char *msg); - -#endif - diff --git a/kernel/lang/conv.c b/kernel/lang/conv.c deleted file mode 100644 index 25a38d2..0000000 --- a/kernel/lang/conv.c +++ /dev/null @@ -1,109 +0,0 @@ -// conv.h -// Author: Josh Holtrop -// Date: 08/02/04 -// Modified: 12/30/04 - -#include "conv.h" -#include "hos_defines.h" - -// BCD to string -// returns number of characters generated before null terminator -int bcdtoa(u32_t bcd, char *buf) -{ - *buf++ = ((bcd & 0xF0) >> 4) + '0'; - *buf++ = (bcd & 0xF) + '0'; - *buf = 0; - return 2; -} - - -// convert integer to hexadecimal string -int itox(u32_t num, char *buf) -{ - int s, i = 0; - for (s = 28; s >= 0; s -= 4) - { - u32_t val = (num >> s) & 0xF; - if (i || val || (!s)) - { - val = (val > 9) ? (val + 'A' - 10) : (val + '0'); - buf[i++] = val; - } - } - buf[i] = 0; - return i - 1; -} - - -// convert integer to an octal string -int itoo(u32_t num, char *buf) -{ - int s, i = 0; - for (s = 30; s >= 0; s -= 3) - { - u32_t val = (num >> s) & 0x7; - if (i || val || (!s)) - buf[i++] = val + '0'; - } - buf[i] = 0; - return i - 1; -} - - -// convert signed integer to decimal string -int itoa(int num, char *buf) -{ - // 4,294,967,296 - int hitNum = 0, i = 0, mod, val; - if (num < 0) - { - buf[i++] = '-'; - num = -num; - } - for (mod = 1000000000; mod >= 1; mod /= 10) - { - val = num / mod; - num %= mod; - if (val || (mod == 1)) - hitNum = 1; - if (hitNum) - { - buf[i++] = val + '0'; - } - } - buf[i] = 0; - return i - 1; -} - - -// convert an unsigned integer to decimal string -int utoa(u32_t num, char *buf) -{ - // 4,294,967,296 - int hitNum = 0, i = 0, mod, val; - for (mod = 1000000000; mod >= 1; mod /= 10) - { - val = num / mod; - num %= mod; - if (val || (mod == 1)) - hitNum = 1; - if (hitNum) - { - buf[i++] = val + '0'; - } - } - buf[i] = 0; - return i - 1; -} - - -char asciiSwitchCase(char chr) -{ - if (chr >= 'A' && chr <= 'Z') - return chr + ('a' - 'A'); - if (chr >= 'a' && chr <= 'z') - return chr - ('a' - 'A'); - return chr; -} - - diff --git a/kernel/lang/conv.h b/kernel/lang/conv.h deleted file mode 100644 index 39505f5..0000000 --- a/kernel/lang/conv.h +++ /dev/null @@ -1,20 +0,0 @@ -// conv.h -// Author: Josh Holtrop -// Date: 08/02/04 -// Modified: 12/30/04 - -#ifndef __HOS_CONV__ -#define __HOS_CONV__ __HOS_CONV__ - -#include "hos_defines.h" - -int bcdtoa(u32_t bcd, char *buf); -int itox(u32_t num, char *buf); -int itoo(u32_t num, char *buf); -int itoa(int num, char *buf); -int utoa(u32_t num, char *buf); - -char asciiSwitchCase(char chr); - -#endif - diff --git a/kernel/lang/lang.asm b/kernel/lang/lang.asm deleted file mode 100644 index 7306465..0000000 --- a/kernel/lang/lang.asm +++ /dev/null @@ -1,362 +0,0 @@ -; lang.asm -; Josh Holtrop -; Created: 10/23/03 -; Modified: 12/30/04 - -[bits 32] - -%macro jzfar 1 - jnz %%skip - jmp %1 -%%skip: - -%endmacro - -;implements a lock -[global lockit] -lockit: - push ebp - mov ebp, esp - push eax - push ebx - push esi - - mov esi, [ebp + 8] -_lock_loop0: - xor eax, eax - mov ebx, 1 - cmpxchg [esi], ebx - jnz _lock_loop0 ; failed to acquire lock - - pop esi - pop ebx - pop eax - pop ebp - ret - -;releases a lock -[global unlock] -unlock: - push ebp - mov ebp, esp - push esi - - mov esi, [ebp + 8] - mov [esi], dword 0 - - pop esi - pop ebp - ret - -;returns the value in the CR0 register -;extern dword read_cr0(); -[global read_cr0] -read_cr0: - mov eax, cr0; - ret - -;stores the parameter to the CR0 register -;extern dword write_cr0(dword cr0); -[global write_cr0] -write_cr0: - push ebp - mov ebp, esp - mov eax, [ebp+8] - mov cr0, eax - pop ebp - ret - -;returns the value in the CR2 register -;extern dword read_cr2(); -[global read_cr2] -read_cr2: - mov eax, cr2; - ret - - - -;returns the value in the CR3 register -;extern dword read_cr3(); -[global read_cr3] -read_cr3: - mov eax, cr3; - ret - - -;stores the parameter to the CR3 register -;extern dword write_cr3(dword cr3); -[global write_cr3] -write_cr3: - push ebp - mov ebp, esp - mov eax, [ebp+8] - mov cr3, eax - pop ebp - ret - - -; read ss register -[global read_ss] -read_ss: - mov ax, ss - ret - - -;copies a string from the source to the destination parameter -;extern void strcpy(char *dest, char *src); -[global strcpy] -strcpy: - push ebp - mov ebp, esp - push esi - push edi - mov edi, [ebp+8] - mov esi, [ebp+12] -strcpyloop: - lodsb - stosb - or al, al - jnz strcpyloop - pop edi - pop esi - pop ebp - ret - -;copies memory of n bytes from src to destination -;void memcpy(void *dest, void *src, dword n); -[global memcpy] -memcpy: - push ebp - mov ebp, esp - push esi - push edi - push ecx - mov edi, [ebp+8] - mov esi, [ebp+12] - mov ecx, [ebp+16] - - cld - rep movsb - - pop ecx - pop edi - pop esi - pop ebp - ret - - -;copies memory of n words (n*2 bytes) from src to destination -;void memcpyw(void *dest, void *src, dword n); -[global memcpyw] -memcpyw: - push ebp - mov ebp, esp - push esi - push edi - push ecx - mov edi, [ebp+8] - mov esi, [ebp+12] - mov ecx, [ebp+16] - - cld - rep movsw - - pop ecx - pop edi - pop esi - pop ebp - ret - - -;copies memory of n dwords (n*4 bytes) from src to destination -;void memcpyd(void *dest, void *src, dword n); -[global memcpyd] -memcpyd: - push ebp - mov ebp, esp - push esi - push edi - push ecx - mov edi, [ebp+8] - mov esi, [ebp+12] - mov ecx, [ebp+16] - - cld - rep movsd - - pop ecx - pop edi - pop esi - pop ebp - ret - - -;sets num bytes at buffer to the value of c -;void *memset(void *buffer, int c, int num); -[global memset] -memset: - push ebp - mov ebp, esp - push edi - push ecx - mov edi, [ebp+8] - push edi ;save for return address - mov eax, [ebp+12] - mov ecx, [ebp+16] - - rep stosb - - pop eax - pop ecx - pop edi - pop ebp - ret - - -;sets num words at buffer to the value of c -;void *memsetw(void *buffer, int c, int num); -[global memsetw] -memsetw: - push ebp - mov ebp, esp - push edi - push ecx - mov edi, [ebp+8] - push edi ;save for return address - mov eax, [ebp+12] - mov ecx, [ebp+16] - - rep stosw - - pop eax - pop ecx - pop edi - pop ebp - ret - - -;sets num dwords at buffer to the value of c -;void *memsetd(void *buffer, int c, int num); -[global memsetd] -memsetd: - push ebp - mov ebp, esp - push edi - push ecx - mov edi, [ebp+8] - push edi ;save for return address - mov eax, [ebp+12] - mov ecx, [ebp+16] - - rep stosd - - pop eax - pop ecx - pop edi - pop ebp - ret - - -;returns the number of characters in a string -;extern dword strlen(char *str); -[global strlen] -strlen: - push ebp - mov ebp, esp - push esi - push ebx - mov esi, [ebp+8] - xor ebx, ebx -strlenloop: - lodsb - or al, al - jz strlendone - inc ebx - jmp strlenloop -strlendone: - mov eax, ebx - pop ebx - pop esi - pop ebp - ret - - -;this function invalidates the page directory/table entry that -; would be used to access the memory address given in the parameter -;extern void invlpg_(dword addr); -[global invlpg_] -invlpg_: - mov eax, [esp+4] - invlpg [eax] - ret - - -; -;void writeCursorPosition(word pos) -; -[global writeCursorPosition] -writeCursorPosition: - push ebp - mov ebp, esp - - push eax - push ebx - push edx - - mov eax, [ebp+8] ;cursor position in ax - - mov bl, al - mov dx, 0x03D4 - mov al, 0x0E - out dx, al - - inc dx - mov al, ah - out dx, al - - dec dx - mov al, 0x0F - out dx, al - - inc dx - mov al, bl - out dx, al - - pop edx - pop ebx - pop eax - pop ebp - - ret - - -; -;word getCursorPosition() -; -[global getCursorPosition] -getCursorPosition: - push ebx - push edx - - xor eax, eax - mov dx, 0x03D4 - mov al, 0x0E - out dx, al - - inc dx - in al, dx - mov bl, al - - dec dx - mov al, 0x0F - out dx, al - - inc dx - in al, dx - mov ah, bl - - pop edx - pop ebx - - ret - diff --git a/kernel/lang/lang.c b/kernel/lang/lang.c deleted file mode 100644 index 71d276c..0000000 --- a/kernel/lang/lang.c +++ /dev/null @@ -1,114 +0,0 @@ -// lang.c -// Author: Josh Holtrop -// Date: 12/30/04 -// Modified: 12/30/04 - -#include "lang.h" - - -/* strcmp compares two strings - * Returns: - * 0 if the strings are equal - * <0 if the second string is less than the first - * >0 if the second string is greater than the first - */ -int strcmp(char *str1, char *str2) -{ - while (*str1 || *str2) - { - if (*str1 != *str2) - return *str2 - *str1; - str1++; - str2++; - } - return 0; -} - -/* strncmp compares up to n characters of two strings - * Returns: - * 0 if the strings are equal - * <0 if the second string is less than the first - * >0 if the second string is greater than the first - */ -int strncmp(char *str1, char *str2, int n) -{ - while (n > 0 && (*str1 || *str2)) - { - if (*str1 != *str2) - return *str2 - *str1; - str1++; - str2++; - n--; - } - return 0; -} - - -/* str_change changes a certain character in a string - * to a different character - * Returns: how many characters were changed - */ -int str_change(char *str, char ch1, char ch2) -{ - int count = 0; - while (*str) - { - if (*str == ch1) - { - *str = ch2; - count++; - } - str++; - } - return count; -} - -// counts the occurrences of lookfor in str -int str_count(char *str, char lookfor) -{ - int count = 0; - while (*str) - { - if (*str == lookfor) - count++; - str++; - } - return count; -} - -// split the string into substrings by the splitchar, return number of substrings -int str_split(char *str, char splitchar) -{ - if (!(*str)) - return 0; - int subs = 1; - while (*str) - { - if (*str == splitchar) - { - *str = 0; - subs++; - } - str++; - } - return subs; -} - -// advance the string pointer to the next substring, return a pointer to the next substring -char *str_advance(char *str) -{ - char *next = str; - while (*next) - next++; // advance pointer to end of this substring (null character) - return next + 1; -} - - -// concatentate src onto the end of dest -void strcat(char *dest, char *src) -{ - while (*dest) - dest++; - strcpy(dest, src); -} - diff --git a/kernel/lang/lang.h b/kernel/lang/lang.h deleted file mode 100644 index 2607776..0000000 --- a/kernel/lang/lang.h +++ /dev/null @@ -1,43 +0,0 @@ -// lang.h -// Author: Josh Holtrop -// Created: 02/26/04 -// Modified: 12/30/04 - -#ifndef __HOS_LANG__ -#define __HOS_LANG__ __HOS_LANG__ - -#include "hos_defines.h" - -/* lang.asm */ -void lockit(lock_t *addr); -void unlock(lock_t *addr); -u32_t read_cr0(); -u32_t write_cr0(u32_t cr0); -u32_t read_cr2(); -u32_t read_cr3(); -u32_t write_cr3(u32_t cr3); -u32_t read_ss(); -void writeCursorPosition(u32_t pos); -u32_t getCursorPosition(); -void strcpy(char *dest, const char *src); -void memcpy(void *dest, const void *src, u32_t n); -void memcpyw(void *dest, const void *src, u32_t n); -void memcpyd(void *dest, const void *src, u32_t n); -void *memset(void *buffer, int c, int num); -void *memsetw(void *buffer, int c, int num); -void *memsetd(void *buffer, int c, int num); -u32_t strlen(const char *str); -void invlpg_(u32_t addr); - -/* lang.c */ -int strcmp(char *str1, char *str2); -int strncmp(char *str1, char *str2, int n); -int str_change(char *str, char ch1, char ch2); -int str_count(char *str, char lookfor); -int str_split(char *str, char splitchar); -char *str_advance(char *str); -void strcat(char *dest, char *src); - -#endif - - diff --git a/kernel/lang/new.cpp b/kernel/lang/new.cpp deleted file mode 100644 index bd8b38b..0000000 --- a/kernel/lang/new.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// Author: Josh Holtrop -// Date: 05/10/05 -// Adds C++ support for new, delete functions - -extern "C" -{ -#include "hos_defines.h" -#include "mm/vmm.h" -} - -//overload the operator "new" -void * operator new (u32_t size) -{ return kmalloc(size); } - -//overload the operator "new[]" -void * operator new[] (u32_t size) -{ return kmalloc(size); } - -//overload the operator "delete" -void operator delete (void *p) -{ kfree(p); } - -//overload the operator "delete[]" -void operator delete[] (void *p) -{ kfree(p); } diff --git a/kernel/lang/string.cpp b/kernel/lang/string.cpp deleted file mode 100644 index 16dbf20..0000000 --- a/kernel/lang/string.cpp +++ /dev/null @@ -1,258 +0,0 @@ - -// string.cpp -// implements c++ string object for HOS -// Author: Josh Holtrop -// Date: 06/01/04 -// Modified: 05/10/05 - -extern "C" -{ -#include "string.h" //string class declaration -#include "lang/lang.h" //memcpy(void *dest, void *src, int n), strlen(char *str) -} - -string::string() -{ - myLength = 0; - myChars = new char; //myChars must be a valid pointer at all times - *myChars = 0; -} - -string::~string() -{ - delete[] myChars; -} - -string::string(const string & orig) -{ - myLength = orig.myLength; - myChars = new char[myLength + 1]; - memcpy(myChars, orig.myChars, myLength + 1); -} - -string::string(const char *cstring) -{ - myLength = strlen(cstring); - myChars = new char[myLength + 1]; - memcpy(myChars, cstring, myLength + 1); -} - -string & string::operator=(const string & orig) -{ - if (this != &orig) - { - delete[] myChars; - myLength = orig.myLength; - myChars = new char[myLength + 1]; - memcpy(myChars, orig.myChars, myLength + 1); - } - return *this; -} - -string & string::operator=(const char *cstring) -{ - if (myChars != cstring) - { - delete[] myChars; - myLength = strlen(cstring); - myChars = new char[myLength + 1]; - memcpy(myChars, cstring, myLength + 1); - } - return *this; -} - -char * string::data() const { return myChars; } - -int string::size() const { return myLength; } - -string & string::operator+=(const string & str) -{ - char *newStr = new char[myLength + str.myLength + 1]; - memcpy(newStr, myChars, myLength); - memcpy(newStr + myLength, str.myChars, str.myLength + 1); - delete[] myChars; - myChars = newStr; - myLength += str.myLength; - return *this; -} - -string & string::operator+=(const char *cstring) -{ - char *newStr = new char[myLength + strlen(cstring) + 1]; - memcpy(newStr, myChars, myLength); - memcpy(newStr + myLength, cstring, strlen(cstring) + 1); - delete[] myChars; - myChars = newStr; - myLength += strlen(cstring); - return *this; -} - -string & string::operator+=(char chr) -{ - myLength++; - char *newStr = new char[myLength + 1]; - memcpy(newStr, myChars, myLength); - newStr[myLength - 1] = chr; - newStr[myLength] = 0; - delete[] myChars; - myChars = newStr; - return *this; -} - - -string string::operator+(const string & str) -{ return string(*this, str); } - -string string::operator+(const char *cstring) -{ return string(*this, cstring); } - -string string::operator+(char chr) -{ return string(*this, chr); } - - - -string::string(const string & str1, const string & str2) -{ - myLength = str1.myLength + str2.myLength; - myChars = new char[myLength + 1]; - memcpy(myChars, str1.myChars, str1.myLength); - memcpy(myChars + str1.myLength, str2.myChars, str2.myLength + 1); -} - -string::string(const string & str1, const char *cstring) -{ - myLength = str1.myLength + strlen(cstring); - myChars = new char[myLength + 1]; - memcpy(myChars, str1.myChars, str1.myLength); - memcpy(myChars + str1.myLength, cstring, strlen(cstring) + 1); -} - -string::string(const char *cstring, const string & str) -{ - myLength = str.myLength + strlen(cstring); - myChars = new char[myLength + 1]; - memcpy(myChars, cstring, strlen(cstring)); - memcpy(myChars + strlen(cstring), str.myChars, str.myLength + 1); -} - -string::string(const string & str1, char chr) -{ - myLength = str1.myLength + 1; - myChars = new char[myLength + 1]; - memcpy(myChars, str1.myChars, myLength); - myChars[myLength - 1] = chr; - myChars[myLength] = 0; -} - -string::string(char chr, const string & str1) -{ - myLength = str1.myLength + 1; - myChars = new char[myLength + 1]; - memcpy(myChars + 1, str1.myChars, myLength + 1); - *myChars = chr; -} - -const char & string::operator[](unsigned int index) const -{ - if (index < myLength) - return myChars[index]; - return *myChars; //if index is invalid, return a pointer to the trailing 0 -} - -char & string::operator[](unsigned int index) -{ - if (index < myLength) - return myChars[index]; - return *myChars; //if index is invalid, return a pointer to the trailing 0 -} - - - -bool string::operator==(const string & second) const -{ - if (myLength != second.myLength) - return false; - for (unsigned int i = 0; i < myLength; i++) - { - if (myChars[i] != second.myChars[i]) - return false; - } - return true; -} - -bool string::operator==(const char *cstring) const -{ - if (myLength != strlen(cstring)) - return false; - for (unsigned int i = 0; i < myLength; i++) - { - if (myChars[i] != cstring[i]) - return false; - } - return true; -} - -bool string::operator!=(const string & second) const -{ return !operator==(second); } - -bool string::operator!=(const char *cstring) const -{ return !operator==(cstring); } - -bool string::operator<(const string & second) const -{ - char *c1 = myChars, *c2 = second.myChars; - while (*c1 == *c2 && *c1) - { - c1++; - c2++; - } - return *c1 < *c2; -} - -bool string::operator>(const string & second) const -{ - char *c1 = myChars, *c2 = second.myChars; - while (*c1 == *c2 && *c1) - { - c1++; - c2++; - } - return *c1 > *c2; -} - -bool string::operator<(const char *cstring) const -{ - char *c1 = myChars; - while (*c1 == *cstring && *c1) - { - c1++; - cstring++; - } - return *c1 < *cstring; -} - -bool string::operator>(const char *cstring) const -{ - char *c1 = myChars; - while (*c1 == *cstring && *c1) - { - c1++; - cstring++; - } - return *c1 > *cstring; -} - -bool string::operator<=(const string & second) const -{ return !operator>(second); } - -bool string::operator>=(const string & second) const -{ return !operator<(second); } - -bool string::operator<=(const char *cstring) const -{ return operator<(cstring) || operator==(cstring); } - -bool string::operator>=(const char *cstring) const -{ return operator>(cstring) || operator==(cstring); } - - - diff --git a/kernel/lang/string.h b/kernel/lang/string.h deleted file mode 100644 index ba5b1de..0000000 --- a/kernel/lang/string.h +++ /dev/null @@ -1,110 +0,0 @@ - -// string.h -// implements c++ string object for HOS -// Author: Josh Holtrop -// Date: 06/01/04 -// Modified: 05/10/05 - - -#ifndef __HOS_STRING__ -#define __HOS_STRING__ __HOS_STRING__ - -class string -{ -private: - /* myChars is a pointer to a character array - * It will always be a valid pointer, not null. - * The constructor is responsible for initializing - * it to point to a 1-char array with myChars[0] == 0 */ - char * myChars; - - /* myLength holds how many characters are in the - * string, not including the trailing null value - * (ASCII 0 character) */ - unsigned int myLength; -public: - /* Basic constructors */ - string(); - ~string(); - - /* Copy constructor */ - string(const string & orig); - - /* Construct strings from c-style strings: - * Allows declarations like string s = "data"; */ - string(const char *cstring); - - /* Assignment operators */ - string & operator=(const string & orig); - string & operator=(const char *cstring); - - /* Boolean comparison operators */ - bool operator==(const string & second) const; - bool operator==(const char *cstring) const; - bool operator!=(const string & second) const; - bool operator!=(const char *cstring) const; - bool operator<(const string & second) const; - bool operator>(const string & second) const; - bool operator<(const char *cstring) const; - bool operator>(const char *cstring) const; - bool operator<=(const string & second) const; - bool operator>=(const string & second) const; - bool operator<=(const char *cstring) const; - bool operator>=(const char *cstring) const; - - /* Construct strings made up of combinations of other - * strings, c-style strings, and characters */ - string(const string & str1, const string & str2); - string(const string & str1, const char *cstring); - string(const char *cstring, const string & str); - string(const string & str1, char chr); - string(char chr, const string & str1); - - /* Append operators */ - string & operator+=(const string & str); - string & operator+=(const char *cstring); - string & operator+=(char chr); - - string operator+(const string & str); - string operator+(const char *cstring); - string operator+(char chr); - - /* Direct character-access operators */ - const char & operator[](unsigned int index) const; - char & operator[](unsigned int index); - - /* Returns handle to actual character-array for programs - * that need raw data instead of a string object */ - char * data() const; - - /* Returns the size of the string. This is myLength - * and is the number of characters in the string - * not counting the trailing null (ASCII 0) character */ - int size() const; -}; - - -static inline bool operator==(char *cstring, const string & str) -{ return str == cstring; } - -static inline bool operator!=(char *cstring, const string & str) -{ return str != cstring; } - -static inline bool operator<(const char *cstring, const string & str) -{ return str > cstring; } - -static inline bool operator>(const char *cstring, const string & str) -{ return str < cstring; } - -static inline bool operator<=(const char *cstring, const string & str) -{ return str >= cstring; } - -static inline bool operator>=(const char *cstring, const string & str) -{ return str <= cstring; } - -static inline string operator+(const char *cstring, const string & str) -{ return string(cstring, str); } - - -#endif - diff --git a/kernel/lang/vector.h b/kernel/lang/vector.h deleted file mode 100644 index ded371e..0000000 --- a/kernel/lang/vector.h +++ /dev/null @@ -1,147 +0,0 @@ - -// vector.h -// implements c++ vector object for HOS -// Author: Josh Holtrop -// Date: 05/30/05 -// Modified: 05/30/05 - - -#ifndef __HOS_VECTOR__ -#define __HOS_VECTOR__ __HOS_VECTOR__ - -#include "hos_defines.h" - -template -class vector -{ -protected: - typedef type * type_ptr_t; - - /* Pointers to vector elements */ - type **myData; - - /* How many elements are present */ - unsigned int mySize; - - /* How many elements there are pointers for */ - unsigned int myAllocated; - - /* Causes the vector to double in its allocated size */ - void grow() - { - myAllocated <<= 1; - if (myAllocated == 0) - myAllocated = 1; - type **data_new = new type_ptr_t[myAllocated]; - for (unsigned int i = 0; i < mySize; i++) - data_new[i] = myData[i]; - if (myData) - delete[] myData; - myData = data_new; - } - -public: - /* Constructors/Destructor */ - vector() - { - myData = NULL; - mySize = 0; - myAllocated = 0; - } - - vector(unsigned int size) - { - myData = new type_ptr_t[size]; - mySize = 0; - myAllocated = size; - } - - vector(const vector & v1) - { - mySize = v1.mySize; - myAllocated = v1.myAllocated; - myData = new type_ptr_t[myAllocated]; - for (u32_t i = 0; i < mySize; i++) - myData[i] = new type(*v1.myData[i]); - } - - ~vector() - { - for (unsigned int i = 0; i < mySize; i++) - delete myData[i]; - delete[] myData; - } - - /* Assignment operator */ - vector & operator=(const vector & v1) - { - mySize = v1.mySize; - myAllocated = v1.myAllocated; - myData = new type_ptr_t[myAllocated]; - for (u32_t i = 0; i < mySize; i++) - myData[i] = new type(*v1.myData[i]); - return *this; - } - - /* Returns the size of the vector */ - unsigned int size() const - { - return mySize; - } - - /* Add an element to the end of the vector */ - vector & add(type elem) - { - while (mySize >= myAllocated) - grow(); - myData[mySize++] = new type(elem); - return *this; - } - - /* Remove an element from the vector */ - vector & remove(unsigned int index) - { - if (index < mySize) - { - delete myData[index]; - for (unsigned int i = index; i < (mySize - 1); i++) - myData[i] = myData[i+1]; - mySize--; - } - return *this; - } - - /* Insert an element into a position in the vector */ - vector & insert(type elem, unsigned int position) - { - if (position <= mySize) - { - if (mySize >= myAllocated) - grow(); - for (unsigned int i = mySize; i > position; i--) - myData[i] = myData[i-1]; - myData[position] = new type(elem); - mySize++; - } - return *this; - } - - /* Direct access operators */ - const type & operator[](unsigned int index) const - { - return *myData[index]; - } - - type & operator[](unsigned int index) - { - return *myData[index]; - } - - /* Returns pointer to data */ - type **data() - { - return myData; - } -}; - -#endif diff --git a/kernel/link.ld b/kernel/link.ld deleted file mode 100644 index f881b0f..0000000 --- a/kernel/link.ld +++ /dev/null @@ -1,26 +0,0 @@ -OUTPUT_FORMAT("binary") -ENTRY(start) -SECTIONS -{ - .text 0xC0108000 : { - code = .; _code = .; __code = .; - *(.text) - *(.eh_frame*) - } - .gnulinkonce : { - *(.gnu.linkonce*) - . = ALIGN(4096); - } - .data : { - data = .; _data = .; __data = .; - *(.data*) - *(.rodata*) - . = ALIGN(4096); - } - .bss : { - bss = .; _bss = .; __bss = .; - *(.bss) - . = ALIGN(4096); - } - end = .; _end = .; __end = .; -} diff --git a/kernel/mm/mm.c b/kernel/mm/mm.c deleted file mode 100644 index dae7ecc..0000000 --- a/kernel/mm/mm.c +++ /dev/null @@ -1,155 +0,0 @@ -// mm.c -// Author: Josh Holtrop -// Created: 09/01/03 -// Modified: 08/19/04 - -#include "kernel.h" -#include "mm/mm.h" -#include "multiboot.h" -#include "hos_defines.h" - -extern mb_info_t mb_info_block; -extern mb_mmap_t mb_mmap[MAX_MMAP]; -extern u32_t mmap_entries; -extern mb_module_t mb_modules[MAX_MODULES]; - -u32_t mm_totalmem; -u32_t mm_megabytes; -u32_t mm_freepages; -u32_t mm_first_free_byte; -byte page_bitmap[MM_BITMAP_SIZE]; //used to store a bit for each page that is used, 0 if available - //0x20000*(8 bits/byte)=0x100000 pages in 4gb total - -//This function initializes the memory manager's linked list, filling it with the -// memory areas returned by bios interrupt 0x8E20 -void mm_init() -{ - u32_t a; - for (a = 0; a < MM_BITMAP_SIZE; a++) //mark all pages used - { - page_bitmap[a] = 0xFF; - } - for (a = 0; a < mmap_entries; a++) //free BIOS #1 areas - { - if (mb_mmap[a].type == 1) // (1) mem free to OS - { - mm_totalmem += mb_mmap[a].length; - u32_t freethis = mb_mmap[a].base; - u32_t limit = mb_mmap[a].base + mb_mmap[a].length - 4096; - while (freethis <= limit) - { - if (freethis >= PHYS_LOAD) //above physical kernel load point - mm_pfree(freethis); - freethis += 4096; - } - } - } - mm_preserven(PHYS_LOAD, (((u32_t)&_end - (u32_t)&start) >> 12) + 1); //reserve kernel memory - int i; - for (i = 0; i < mb_info_block.mods_count; i++) //reserve module memory - { - mm_preserven(mb_modules[i].mod_start - VIRT_OFFSET, (mb_modules[i].mod_end - mb_modules[i].mod_start + 4095) >> 12); - } - mm_megabytes = (mm_totalmem >> 20) + ((mm_totalmem % 0x100000) ? 1 : 0); -} - - -// This function frees a certain number of pages starting at the address -// specified in base for a length of pages pages -void mm_pfreen(u32_t base, u32_t pages) -{ - //convert pages to max address - for (pages = base + (pages << 12); base < pages; base += 4096) - mm_pfree(base); -} - - -// This function frees a single page -void mm_pfree(u32_t base) -{ -// u32_t pageNumber = base >> 12; // >>12 == /4096 - u32_t byteNumber = base >> 15; //pageNumber >> 3; //pageNumber/8 - u32_t bitNumber = (base >> 12) & 0x07; //pageNumber % 8; - page_bitmap[byteNumber] = page_bitmap[byteNumber] & ((0x01 << bitNumber) ^ 0xFF); - mm_freepages++; - if (byteNumber < mm_first_free_byte) - mm_first_free_byte = byteNumber; -} - - -// This function reserves a certain number of pages starting at the address -// specified in base for a length of pages pages -void mm_preserven(u32_t base, u32_t pages) -{ - //convert pages to max address - for (pages = base + (pages << 12); base < pages; base += 4096) - mm_preserve(base); -} - - -// This function reserves a single page -void mm_preserve(u32_t base) -{ -// u32_t pageNumber = base >> 12; // >>12 == /4096 - u32_t byteNumber = base >> 15; //pageNumber >> 3; //pageNumber/8 - u32_t bitNumber = (base >> 12) & 0x07; //pageNumber % 8; - page_bitmap[byteNumber] = page_bitmap[byteNumber] | (0x01 << bitNumber); - mm_freepages--; -} - - -// This function allocates a single page, returning its physical address -u32_t mm_palloc() -{ - u32_t bite; - for (bite = mm_first_free_byte; bite < MM_BITMAP_SIZE; bite++) - { - if (page_bitmap[bite] != 0xFF) //there is an available page within this 8-page region - { - int bit; - for (bit = 0; bit < 8; bit++) - { - if (!(page_bitmap[bite] & (1 << bit))) //this bite/bit combination is available - { - mm_first_free_byte = bite; //start searching from here next time - mm_freepages--; - page_bitmap[bite] = page_bitmap[bite] | (1 << bit); //set page as used - return ((bite << 15) | (bit << 12)); - } - } - } - } - return 0; //no free page -} - - -// This function reports the number of bytes of free physical memory -u32_t mm_getFreeMem() -{ - return mm_freepages << 12; -} - - -u32_t mm_getFreePages() -{ - return mm_freepages; -} - - -u32_t mm_getTotalMem() -{ - return mm_totalmem; -} - - -u32_t mm_getTotalMegs() -{ - return mm_megabytes; -} - - - - - - - diff --git a/kernel/mm/mm.h b/kernel/mm/mm.h deleted file mode 100644 index 8c13ea8..0000000 --- a/kernel/mm/mm.h +++ /dev/null @@ -1,27 +0,0 @@ -// mm.c -// Author: Josh Holtrop -// Created: 09/01/03 -// Modified: 03/08/04 - -#ifndef __HOS_MM__ -#define __HOS_MM__ __HOS_MM__ - -#include "kernel.h" - -//The total amount of physical memory available (bytes, 1 bit per page) -#define MM_BITMAP_SIZE 0x20000 - -void mm_init(); -void mm_pfreen(u32_t base, u32_t pages); -void mm_pfree(u32_t base); -void mm_preserven(u32_t base, u32_t pages); -void mm_preserve(u32_t base); -u32_t mm_palloc(); -u32_t mm_getFreeMem(); -u32_t mm_getFreePages(); -u32_t mm_getTotalMem(); -u32_t mm_getTotalMegs(); - - -#endif - diff --git a/kernel/mm/vmm.c b/kernel/mm/vmm.c deleted file mode 100644 index c78a24b..0000000 --- a/kernel/mm/vmm.c +++ /dev/null @@ -1,528 +0,0 @@ -// vmm.c -// Author: Josh Holtrop -// Date: 09/30/03 -// Rewritten from scratch: 12/23/03 -// Modified: 09/12/05 - -#include "hos_defines.h" -#include "kernel.h" -#include "mm/vmm.h" -#include "lang/lang.h" -#include "mm/mm.h" - -int vmm_map_range(void *virt_start, void *virt_end, u32_t phys_start); -void *vmm_getFreeChunk(u32_t size); -void vmm_removeHeapEntry(u32_t queue, HeapEntry_t *he); -int vmm_moreCore(u32_t size); -int vmm_coalesceEntry(u32_t queue, HeapEntry_t *newHE); -void vmm_heb_init(HeapEntryBlock_t *heb); -void vmm_addToQueue(u32_t queue, HeapEntry_t *preceeding, HeapEntry_t *he); -int vmm_countHeapEntries(HeapEntry_t *he); -HeapEntry_t *vmm_followChain(HeapEntry_t *he); -HeapEntry_t *vmm_getUnusedEntry(); -HeapEntry_t *vmm_stripUnusedEntry(); - -extern mb_info_t mb_info_block; -extern mb_module_t mb_modules[MAX_MODULES]; -extern u32_t mm_freepages; - -HeapEntryQueue_t heapEntryQueues[VMM_HE_TYPES]; // linked queues of HeapEntry objects -HeapEntry_t heapEntryHeadNodes[VMM_HE_TYPES]; // head nodes for linked queues -HeapEntry_t heapEntryTailNodes[VMM_HE_TYPES]; // tail nodes for linked queues -HeapEntryBlock_t initialHEB; // block for initial 256 HeapEntry objects - - -// This is the initialization procedure for the Virtual Memory Manager -// It sets up the heap for dynamic memory allocation and virtual page allocation -void vmm_init() -{ - int i; - for (i = 0; i < mb_info_block.mods_count; i++) //page in the kernel modules - vmm_map_range((void*)mb_modules[i].mod_start, (void*)mb_modules[i].mod_end - 1, mb_modules[i].mod_start - VIRT_OFFSET); - for (i = 0; i < VMM_HE_TYPES; i++) - { - heapEntryQueues[i].count = 0; - heapEntryQueues[i].head = &heapEntryHeadNodes[i]; - heapEntryHeadNodes[i].next = &heapEntryTailNodes[i]; - heapEntryTailNodes[i].prev = &heapEntryHeadNodes[i]; - } - vmm_heb_init(&initialHEB); - vmm_addToQueue(VMM_HE_UNUSED, &heapEntryHeadNodes[VMM_HE_UNUSED], &initialHEB.entry[0]); - HeapEntry_t *wilderness = vmm_stripUnusedEntry(); - wilderness->base = (void *) HEAP_START; - wilderness->length = HEAP_LENGTH; - vmm_addToQueue(VMM_HE_HOLE, &heapEntryHeadNodes[VMM_HE_HOLE], wilderness); -} - - -/* Allocate a physical page and map the virtual address to it, return physical address allocated or NULL */ -int vmm_map(void *virt) -{ - u32_t dum; - return vmm_map_addr(virt, &dum); -} - -int vmm_map_addr(void *virt, u32_t *phys_addr) -{ - if (mm_freepages < 10) - return -1; - return vmm_map1((u32_t)virt, *phys_addr = mm_palloc()); -} - - -// This function maps a virtual address to a physical address using the page directory / page table -int vmm_map1(u32_t virt, u32_t physical) -{ - virt &= 0xFFFFF000; - physical &= 0xFFFFF000; - u32_t pde = virt >> 22; - u32_t pte = (virt & 0x003FF000) >> 12; - u32_t *pageTables = (u32_t *)0xFFFFF000; //this is the location of the page directory - if (!(pageTables[pde] & 0x01)) //the page directory entry is not present, we must allocate a page table - { - u32_t newpagetable; - if (!(newpagetable = mm_palloc())) - return -1; //out of physical memory - pageTables[pde] = newpagetable | 0x03; - invlpg_(0xFFFFF000 + (pde << 2)); - invlpg_(virt); //in case it was cached, so we can fill page table safely - memsetd((void*)(0xFFC00000 | (pde << 12)), 0, 1024); //zero out new page table - } - *(u32_t *)(0xFFC00000 | (pde << 12) | (pte << 2)) = physical | 0x03; - invlpg_((0xFFC00000 | (pde << 12) | (pte << 2))); - invlpg_(virt); - return 0; -} - - -// This function maps a variable number of pages in a row -int vmm_mapn(u32_t virt, u32_t physical, u32_t n) -{ - while (n > 0) - { - if (vmm_map1(virt, physical)) - return 1; // error mapping page - virt += 4096; - physical += 4096; - n--; - } - return 0; -} - - -// This function removes the virtual address's entry in the -// page directory / page table -void vmm_unmap1(u32_t virt) -{ - *(u32_t *)(0xFFC00000 | - ((virt & 0xFFC00000) >> 10) | - ((virt & 0x003FF000) >> 10)) = 0; - invlpg_(virt); -} - - -// This function removes multiple pages' entries -void vmm_unmapn(u32_t virt, u32_t n) -{ - while (n > 0) - { - vmm_unmap1(virt); - virt += 4096; - n--; - } -} - - -// This function maps an entire address range into memory -int vmm_map_range(void *virt_start, void *virt_end, u32_t phys_start) -{ - if (virt_end < virt_start) - return -1; // invalid region - while (virt_start < virt_end) - { - if (vmm_map1((u32_t)virt_start, phys_start)) - return -2; // out of memory - virt_start += 4096; - phys_start += 4096; - } - return 0; -} - - - -// kernel virtual memory allocator -void *kmalloc(u32_t size) -{ - k_enter_critical(); - if (size % VMM_MALLOC_GRANULARITY) - size = size + VMM_MALLOC_GRANULARITY - - (size % VMM_MALLOC_GRANULARITY); - /* added 09/12/05 by josh - fixed bug returning size 0 segments - multiple times */ - if (size < VMM_MALLOC_GRANULARITY) - size = VMM_MALLOC_GRANULARITY; - void *attempt = vmm_getFreeChunk(size); - if (attempt) - { - k_leave_critical(); - return attempt; - } - if (vmm_moreCore(size)) - { - k_leave_critical(); - return NULL; //we could not get any more heap memory - } - attempt = vmm_getFreeChunk(size); - k_leave_critical(); - return attempt; -} - - -// kernel virtual memory de-allocator -int kfree(void *addr) -{ - k_enter_critical(); - HeapEntry_t *he = heapEntryQueues[VMM_HE_USED].head->next; - while (he->next) - { - if (he->base == addr) - { - vmm_removeHeapEntry(VMM_HE_USED, he); - if (vmm_coalesceEntry(VMM_HE_FREE, he)) - vmm_addToQueue(VMM_HE_FREE, heapEntryQueues[VMM_HE_FREE].head, he); - else - vmm_addToQueue(VMM_HE_UNUSED, heapEntryQueues[VMM_HE_UNUSED].head, he); - break; - } - he = (HeapEntry_t *)he->next; - } - k_leave_critical(); - return 0; -} - - -// This function allocates a virtual page and maps it to a physical page -void *vmm_palloc() -{ - u32_t dum; - return vmm_palloc_addr(&dum); -} - -void *vmm_palloc_addr(u32_t *phys_addr) -{ - k_enter_critical(); - HeapEntry_t *he = heapEntryQueues[VMM_HE_HOLE].head->next; - HeapEntry_t *wilderness = he; - while (he->next) - { - if (he->length == 4096) - { - vmm_removeHeapEntry(VMM_HE_HOLE, he); - vmm_addToQueue(VMM_HE_USED, &heapEntryHeadNodes[VMM_HE_USED], he); - if (vmm_map_addr(he->base, phys_addr)) - he->base = NULL; - k_leave_critical(); - return he->base; - } - if (he->length > wilderness->length) - wilderness = he; - he = (HeapEntry_t *)he->next; - } - if (wilderness->length < 0x00010000) //leave 16 pages free - { - k_leave_critical(); - return NULL; - } - wilderness->length -= 4096; //strip 4k from the top - he = vmm_getUnusedEntry(); - he->base = wilderness->base + wilderness->length; - he->length = 4096; - vmm_addToQueue(VMM_HE_USED, &heapEntryHeadNodes[VMM_HE_USED], he); - if (vmm_map_addr(he->base, phys_addr)) - he->base = NULL; - k_leave_critical(); - return he->base; -} - - -// This function frees a previously-allocated virtual page -int vmm_pfree(void *addr) -{ - u32_t pbase = *(u32_t *)(0xFFC00000 | - (((u32_t)addr & 0xFFC00000) >> 10) | - (((u32_t)addr & 0x003FF000) >> 10)); - if (vmm_unmapp(addr)) - return -1; - mm_pfree(pbase); - return 0; -} - -int vmm_unmapp(void *addr) -{ - if (!addr) - return -2; - k_enter_critical(); - HeapEntry_t *he = heapEntryQueues[VMM_HE_USED].head->next; - while (he->next) - { - if (he->base == addr) //found the page to free - { - vmm_removeHeapEntry(VMM_HE_USED, he); - vmm_unmap1((u32_t)he->base); - vmm_addToQueue(VMM_HE_HOLE, &heapEntryHeadNodes[VMM_HE_HOLE], he); - k_leave_critical(); - return 0; - } - he = he->next; - } - k_leave_critical(); - return -1; // page not found -} - - -// This function allocates and zeros memory for the given number of objects, -// given the size of each object -void *kcalloc(u32_t number, u32_t size) -{ - void *mem = kmalloc(number * size); - if (!mem) - return NULL; //could not get memory - memset(mem, 0, number * size); - return mem; -} - - -// This function re-allocates memory already allocated, preserving the old contents -// (as long as newSize is greater than oldSize) -void *krealloc(void *orig, unsigned int newSize) -{ - void *newMem; - if ((newMem = kmalloc(newSize))) - { - HeapEntry_t *he = heapEntryQueues[VMM_HE_USED].head->next; - while (he->next) - { - if (he->base == orig) - { - memcpy(newMem, orig, (he->length < newSize ? he->length : newSize)); - kfree(orig); - return newMem; - } - he = (HeapEntry_t *)he->next; - } - kfree(newMem); - return NULL; // base address not found - } - else - return NULL; // could not get mem for new chunk -} - - -// This function returns the base address of a free chunk of virtual memory - called from kmalloc() -void *vmm_getFreeChunk(u32_t size) -{ - HeapEntry_t *he = heapEntryQueues[VMM_HE_FREE].head->next; - HeapEntry_t *good = NULL; - while (he->next) // he is not the tail node - { - if (he->length == size) - { - vmm_removeHeapEntry(VMM_HE_FREE, he); - vmm_addToQueue(VMM_HE_USED, heapEntryQueues[VMM_HE_USED].head, he); - return he->base; - } - if (good) - { - if ((he->length > size) && (he->length < good->length)) - good = he; - } - else - { - if (he->length > size) - good = he; - } - he = (HeapEntry_t *)he->next; - } - if (!good) - return NULL; - HeapEntry_t *newHE = vmm_getUnusedEntry(); - newHE->base = good->base; - newHE->length = size; - newHE->next = NULL; - newHE->prev = NULL; - good->base += size; - good->length -= size; - vmm_addToQueue(VMM_HE_USED, heapEntryQueues[VMM_HE_USED].head, newHE); - return newHE->base; -} - - -// This function retrieves more core memory for the virtual memory allocator to allocate -int vmm_moreCore(u32_t size) -{ - int pages = (size >> 12) + 2; - size = pages << 12; - if ((mm_freepages - 5) < pages) - return -1; // out of physical memory - HeapEntry_t *he = heapEntryQueues[VMM_HE_HOLE].head->next; - HeapEntry_t *wilderness = he; - while (he->next) - { - if (he->length > wilderness->length) - wilderness = he; - he = (HeapEntry_t *)he->next; - } - if (wilderness->length <= size) - return -2; // out of virtual memory - int i; - void *virt = wilderness->base; - for (i = 0; i < pages; i++) - { - vmm_map(virt); - virt += 4096; - } - HeapEntry_t *newHE = vmm_getUnusedEntry(); - newHE->base = wilderness->base; - newHE->length = size; - newHE->next = 0; - newHE->prev = 0; - wilderness->base += size; - wilderness->length -= size; - if (vmm_coalesceEntry(VMM_HE_FREE, newHE)) // returns 0 on success (coalesced into previous entry) - vmm_addToQueue(VMM_HE_FREE, heapEntryQueues[VMM_HE_FREE].head, newHE); - else - vmm_addToQueue(VMM_HE_UNUSED, heapEntryQueues[VMM_HE_UNUSED].head, newHE); - return 0; -} - - -// This function coalesces to heap entries into one -int vmm_coalesceEntry(u32_t queue, HeapEntry_t *newHE) -{ - HeapEntry_t *existing = heapEntryQueues[queue].head->next; - while (existing->next) - { - if ((existing->base + existing->length) == newHE->base) - { - existing->length += newHE->length; - return 0; - } - else if ((newHE->base + newHE->length) == existing->base) - { - existing->base = newHE->base; - existing->length += newHE->length; - return 0; - } - existing = (HeapEntry_t *)existing->next; - } - return -1; // an entry to coalesce with was not found -} - - -// This function removes a heap entry from a queue -void vmm_removeHeapEntry(u32_t queue, HeapEntry_t *he) -{ - ((HeapEntry_t *)he->prev)->next = he->next; - ((HeapEntry_t *)he->next)->prev = he->prev; - heapEntryQueues[queue].count--; - he->next = NULL; - he->prev = NULL; -} - - -// This function initialzes a Heap Entry Block to entries linked together -void vmm_heb_init(HeapEntryBlock_t *heb) -{ - int a; - for (a = 0; a < 255; a++) - { - heb->entry[a].next = &heb->entry[a+1]; - heb->entry[a+1].prev = &heb->entry[a]; - } - heb->entry[0].prev = NULL; - heb->entry[255].next = NULL; -} - - -// This function adds a HeapEntry structure to the queue following 'preceeding' the queue -// fails if add to tail (add one element before tail node) -void vmm_addToQueue(u32_t queue, HeapEntry_t *preceeding, HeapEntry_t *he) -{ - heapEntryQueues[queue].count += vmm_countHeapEntries(he); - HeapEntry_t *last = vmm_followChain(he); - last->next = preceeding->next; - he->prev = preceeding; - ((HeapEntry_t *)last->next)->prev = last; - preceeding->next = he; -} - - -// This function returns how many HeapEntry objects are in a queue starting/including from the object given -int vmm_countHeapEntries(HeapEntry_t *he) -{ - int count = 0; - while (he) - { - count++; - he = (HeapEntry_t *)he->next; - } - return count; -} - - -// This function follows a chain of HeapEntry objects and returns a pointer to the last one -HeapEntry_t *vmm_followChain(HeapEntry_t *he) -{ - while (he->next) - he = (HeapEntry_t *)he->next; - return he; -} - - -// This function breaks an unused chunk from its queue and returns a pointer to it -// 09/10/05 nasty bug fixed by josh, wasn't adding unused entries when we ran out of them -HeapEntry_t *vmm_getUnusedEntry() -{ - if (heapEntryQueues[VMM_HE_UNUSED].count < 5) - { - HeapEntry_t *he = heapEntryQueues[VMM_HE_HOLE].head->next; - HeapEntry_t *wilderness = he; - while (he) - { - if ((he->length) > (wilderness->length)) - wilderness = he; - he = (HeapEntry_t *)he->next; - } - if (wilderness->length < 10000) - { - k_check(-1, "Kernel panic: out of virtual memory\n"); - } - wilderness->length -= 4096; //strip 4k from the top - HeapEntryBlock_t *newHEB = wilderness->base + wilderness->length; - vmm_map(newHEB); - vmm_heb_init(newHEB); - vmm_addToQueue(VMM_HE_UNUSED, heapEntryTailNodes[VMM_HE_UNUSED].prev, &newHEB->entry[0]); - } - return vmm_stripUnusedEntry(); -} - - -// Return pointer to an unused HeapEntry object, ASSUMES THERE IS ONE PRESENT IN QUEUE -HeapEntry_t *vmm_stripUnusedEntry() -{ - HeapEntry_t *he = heapEntryQueues[VMM_HE_UNUSED].head->next; - heapEntryQueues[VMM_HE_UNUSED].head->next = he->next; - if (! he->next) - k_check(1, "kernel panic: he->next is NULL\n"); - ((HeapEntry_t *)he->next)->prev = he->prev; - heapEntryQueues[VMM_HE_UNUSED].count--; - he->next = 0; - he->prev = 0; - return he; -} - - - - - - diff --git a/kernel/mm/vmm.h b/kernel/mm/vmm.h deleted file mode 100644 index bc7b1ae..0000000 --- a/kernel/mm/vmm.h +++ /dev/null @@ -1,58 +0,0 @@ -// vmm.h -// Author: Josh Holtrop -// Date: 09/30/03 -// Rewritten from scratch: 12/23/03, 07/13/04 -// Modified: 08/28/04 - -#ifndef __HOS_VMM__ -#define __HOS_VMM__ __HOS_VMM__ - -#include "hos_defines.h" -#include "multiboot.h" - -#define VMM_HE_TYPES 4 //4 types of heap entries -#define VMM_HE_UNUSED 0 //available entry -#define VMM_HE_FREE 1 //free section of memory -#define VMM_HE_USED 2 //used section of memory -#define VMM_HE_HOLE 3 //a "hole" (unmapped/wilderness) section of virtual memory - -#define VMM_MALLOC_GRANULARITY 4 //a power of 2, granularity for all memory requests -#define VMM_MALLOC_GRAN_MASK VMM_MALLOC_GRANULARITY-1 //mask for determining how much of a request is past granularity - - -typedef struct { - void *base; //virtual base address - u32_t length; //size in bytes - void *next; //link to next HeapEntry - void *prev; //link to previous HeapEntry -} __attribute__((packed)) HeapEntry_t; - -typedef struct { - HeapEntry_t entry[256]; //256 HeapEntry objects = 4kb (1 page) -} __attribute__((packed)) HeapEntryBlock_t; - -typedef struct { - int count; - HeapEntry_t *head; -} HeapEntryQueue_t; - - -void vmm_init(); -void *kmalloc(u32_t size); -int kfree(void *addr); -int vmm_unmapp(void *addr); -void *vmm_palloc(); -void *vmm_palloc_addr(u32_t *phys_addr); -int vmm_pfree(void *addr); -void *kcalloc(unsigned int number, unsigned int size); - -int vmm_map(void *virt); -int vmm_map_addr(void *virt, u32_t *phys_addr); -int vmm_map1(unsigned int virt, unsigned int physical); -int vmm_mapn(unsigned int virt, unsigned int physical, unsigned int n); -void vmm_unmap1(unsigned int virt); -void vmm_unmapn(unsigned int virt, unsigned int n); - -#endif - - diff --git a/kernel/module.h b/kernel/module.h deleted file mode 100644 index d816c6d..0000000 --- a/kernel/module.h +++ /dev/null @@ -1,16 +0,0 @@ - -#ifndef __HOS_MODULE_H__ -#define __HOS_MODULE_H__ __HOS_MODULE_H__ - -#define MOD_INITRD 0 -#define MOD_REAL_MODE 1 - -typedef struct { - unsigned int mod_magic; // "HOSM" = dword value 0x4D534F48 - unsigned int mod_type; // module type - void (*init) (); // address of void initialization function - unsigned int reserved; -} hos_module_header_t; - -#endif - diff --git a/kernel/multiboot.h b/kernel/multiboot.h deleted file mode 100644 index 98d038a..0000000 --- a/kernel/multiboot.h +++ /dev/null @@ -1,145 +0,0 @@ - -#ifndef __HOS_MULTIBOOT_H__ -#define __HOS_MULTIBOOT_H__ __HOS_MULTIBOOT_H__ - -#include "hos_defines.h" - -/* The magic number for the Multiboot header. */ -#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 - -#define MB_HEADER_ALIGN_MODULES 0x01 -#define MB_HEADER_MEM_INFO 0x02 -#define MB_HEADER_VIDEO_INFO 0x04 -#define MB_HEADER_KLUDGE_OFFSETS 0x10000 - -/* The magic number passed by a Multiboot-compliant boot loader. */ -#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 - -#define MB_BOOTLOADER_MEM_INFO 0x01 -#define MB_BOOTLOADER_BOOT_DEVICE 0x02 -#define MB_BOOTLOADER_COMMAND_LINE 0x04 -#define MB_BOOTLOADER_MODS 0x08 -#define MB_BOOTLOADER_AOUT 0x10 -#define MB_BOOTLOADER_ELF 0x20 -#define MB_BOOTLOADER_MMAP 0x40 -#define MB_BOOTLOADER_DRIVES 0x80 -#define MB_BOOTLOADER_CONFIG 0x0100 -#define MB_BOOTLOADER_APM 0x0200 -#define MB_BOOTLOADER_GRAPHICS 0x0400 - -#define MB_DRIVE_MODE_CHS 0 -#define MB_DRIVE_MODE_LBA 1 - -/* The Multiboot header. */ -typedef struct -{ - unsigned int magic; - unsigned int flags; - unsigned int checksum; - unsigned int header_addr; - unsigned int load_addr; - unsigned int load_end_addr; - unsigned int bss_end_addr; - unsigned int entry_addr; -} mb_header_t; - -/* The symbol table for a.out. */ -typedef struct -{ - unsigned int tabsize; - unsigned int strsize; - unsigned int addr; - unsigned int reserved; -} mb_aout_symbol_table_t; - -/* The section header table for ELF. */ -typedef struct -{ - unsigned int num; - unsigned int size; - unsigned int addr; - unsigned int shndx; -} mb_elf_section_header_table_t; - -/* The Multiboot information. */ -typedef struct -{ - unsigned int flags; - unsigned int mem_lower; // present if flags[0] is set - unsigned int mem_upper; - unsigned int boot_device; // 1 - unsigned int cmdline; // 2 - unsigned int mods_count; // 3 - unsigned int mods_addr; - union - { - mb_aout_symbol_table_t aout_sym; // 4 - mb_elf_section_header_table_t elf_sec; // 5 - }; - unsigned int mmap_length; // 6 - unsigned int mmap_addr; - unsigned int drives_length; // 7 - unsigned int drives_addr; - unsigned int config_table; // 8 - unsigned int bootloader_name; // 9 - unsigned int apm_table; // 10 - - unsigned int vbe_control_info; // 11 - unsigned int vbe_mode_info; - unsigned short vbe_mode; - unsigned short vbe_interface_seg; - unsigned short vbe_interface_off; - unsigned short vbe_interface_len; -} mb_info_t; - -/* The module structure. */ -typedef struct -{ - unsigned int mod_start; - unsigned int mod_end; - unsigned int string; - unsigned int reserved; -} mb_module_t; - -/* The memory map. Be careful that the offset 0 is base_addr_low, not size. */ -typedef struct -{ - unsigned int size; //offset -4 -// unsigned int base_addr_low; //offset 0 -// unsigned int base_addr_high; -// unsigned int length_low; -// unsigned int length_high; - u64_t base; - u64_t length; - unsigned int type; -} mb_mmap_t; - -/* The drive structure */ -typedef struct -{ - unsigned int size; - unsigned char drive_number; - unsigned char drive_mode; - unsigned char drive_cylinders; - unsigned char drive_heads; - unsigned char drive_sectors; - unsigned short drive_ports[1]; -} mb_drive_t; - -/* APM table structure */ -typedef struct -{ - unsigned short version; - unsigned short cseg; - unsigned int offset; - unsigned short cseg_16; - unsigned short dseg; - unsigned short flags; - unsigned short cseg_len; - unsigned short cseg_16_len; - unsigned short dseg_len; -} mb_apm_t; - - -#endif - diff --git a/kernel/proc/hash.cpp b/kernel/proc/hash.cpp deleted file mode 100644 index 62c9b57..0000000 --- a/kernel/proc/hash.cpp +++ /dev/null @@ -1,117 +0,0 @@ -// hash.cpp -// Author: Josh Holtrop -// Date: 08/28/05 -// Modified: 08/28/05 -// Implements a basic hash table (u32_t -> void*) - -#include "hos_defines.h" -#include "hash.h" -#include "lang/vector.h" - -extern "C"{ -#include "display/kout.h" -#include "mm/vmm.h" -} - -/* Hash Primes come from - * http://planetmath.org/encyclopedia/GoodHashTablePrimes.html - */ -const u32_t hash_primes[] = - {53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317, - 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, - 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741}; - -hash::hash() -{ - mySizeIndex = 0; - mySize = 0; - for (u32_t i = 0; i < hash_primes[mySizeIndex]; i++) - myTable.add(vector()); -} - -int hash::add(u32_t key, void *val) -{ - u32_t hashed = hash_key(key); - for (u32_t i = 0; i < myTable[hashed].size(); i++) - if ( myTable[hashed][i].key == key ) - return -1; // key exists already - hash_entry_t he = {key, val}; - myTable[hashed].add(he); - mySize++; - if ( mySize > (hash_primes[mySizeIndex] << 1) ) // re-hash - { - vector< vector > oldTable = myTable; - mySizeIndex++; - myTable = vector< vector >(); - for (u32_t i = 0; i < hash_primes[mySizeIndex]; i++) - myTable.add(vector()); - mySize = 0; - for (u32_t i = 0; i < hash_primes[mySizeIndex - 1]; i++) - { - for (u32_t j = 0; j < oldTable[i].size(); j++) - { - add( oldTable[i][j].key, - oldTable[i][j].data ); - } - } - } - return 0; -} - -void *hash::get(u32_t key) -{ - u32_t hashed = hash_key(key); - for (u32_t i = 0; i < myTable[hashed].size(); i++) - if ( myTable[hashed][i].key == key ) - return myTable[hashed][i].data; - return NULL; -} - -int hash::remove(u32_t key) -{ - u32_t hashed = hash_key(key); - for (u32_t i = 0; i < myTable[hashed].size(); i++) - if ( myTable[hashed][i].key == key ) - { - myTable[hashed].remove(i); // remove key - mySize--; - return 0; - } - return -1; -} - -int hash::exists(u32_t key) -{ - u32_t hashed = hash_key(key); - for (u32_t i = 0; i < myTable[hashed].size(); i++) - if ( myTable[hashed][i].key == key ) - return 1; // key exists - return 0; -} - -u32_t hash::hash_key(u32_t key) -{ - return ((key * 11) + mySizeIndex) % hash_primes[mySizeIndex]; -} - -u32_t hash::size() -{ - return mySize; -} - -void hash::dump() -{ - kprintf("hash table @ 0x%x : {\n", &myTable); - for (u32_t i = 0; i < hash_primes[mySizeIndex]; i++) - { - kprintf("\t%d @ 0x%x (", i, &myTable[i]); - for (u32_t j = 0; j < myTable[i].size(); j++) - kprintf("%s%d -> %d @ 0x%x", (j ? ", " : ""), - myTable[i][j].key, - myTable[i][j].data, - &myTable[i][j]); - kprintf(")\n"); - } - kprintf("}\n"); -} - diff --git a/kernel/proc/hash.h b/kernel/proc/hash.h deleted file mode 100644 index 4898c37..0000000 --- a/kernel/proc/hash.h +++ /dev/null @@ -1,58 +0,0 @@ -// hash.h -// Author: Josh Holtrop -// Date: 08/28/05 -// Modified: 08/28/05 -// Implements a basic hash table (u32_t -> void*) - -#ifndef __HOS_HASH_H__ -#define __HOS_HASH_H__ __HOS_HASH_H__ - -#include "hos_defines.h" -#include "lang/vector.h" - -typedef struct -{ - u32_t key; - void *data; -} hash_entry_t; - -class hash -{ -private: - /* index into hash_primes[] */ - u32_t mySizeIndex; - - /* How many values in the hash table */ - u32_t mySize; - - /* array of hash entries */ - vector< vector > myTable; - - /* hash the key to a table index */ - u32_t hash_key(u32_t key); - -public: - /* Constructor */ - hash(); - - /* Add a value to the hash table */ - int add(u32_t key, void *val); - - /* Retrieve a value from the hash table */ - void *get(u32_t key); - - /* Remove a value from the hash table */ - int remove(u32_t key); - - /* Check if the given key exists in the hash table */ - int exists(u32_t key); - - /* Dump a hash */ - void dump(); - - /* How many values are in the hash table */ - u32_t size(); -}; - -#endif - diff --git a/kernel/proc/proc.cpp b/kernel/proc/proc.cpp deleted file mode 100644 index e7bff65..0000000 --- a/kernel/proc/proc.cpp +++ /dev/null @@ -1,214 +0,0 @@ -// proc.c -// Author: Josh Holtrop -// Date; 08/18/05 -// Modified: 08/18/05 - -extern "C" { - -#include "hos_defines.h" -#include "mm/mm.h" -#include "mm/vmm.h" -#include "lang/lang.h" -#include "kernel.h" -#include "functions.h" //halt() - -#include "display/kout.h" - -extern u32_t mm_freepages; - -} - -#include "proc.h" -#include "proc/hash.h" - -extern "C" { -u32_t cur_task = 0; /* PID of currently executing process */ -u32_t n_processes = 0; /* total number of processes */ -tss_t tss0; -u32_t pid_base = 1024; -u32_t pid_index = 0; /* index of running process in 'pids' vector */ -} - -hash *processes; -vector *pids; - -int proc_init() -{ - /* initialize tss0 */ - memset(&tss0, 0, sizeof(tss_t)); - tss0.ss0 = SEG_KERNEL_DATA; - tss0.esp0 = VIRT_STACK_TOP; - processes = new hash(); - process_t *proc = (process_t *)New(process_t); - proc->p_page_dir = read_cr3(); - proc->page_dir = (u32_t *)0xFFFFF000; - processes->add(0, proc); - pids = new vector(); - pids->add(0); - return 0; -} - -process_t *proc_get_struct(u32_t pid) -{ - return (process_t *) processes->get(pid); -} - -void proc_sched(int_stack_t *int_stack) -{ - u32_t new_pid_index = (pid_index + 1) % pids->size(); - switch_task(int_stack, (*pids)[new_pid_index]); - pid_index = new_pid_index; -} - -u32_t get_pid() -{ - u32_t potential = pid_base; - while (processes->exists(potential)) - { - potential++; - if (potential == 0) - potential = PROC_MIN_USER_PID; - } - pid_base = potential + 1; - if (pid_base == 0) - pid_base = PROC_MIN_USER_PID; - return potential; -} - -void switch_task(int_stack_t *int_stack, u32_t new_task) -{ - memcpy(&((process_t *)processes->get(cur_task))->int_stack, int_stack, - sizeof(int_stack_t)); - cur_task = new_task; - memcpy(int_stack, &((process_t *)processes->get(cur_task))->int_stack, - sizeof(int_stack_t)); - write_cr3( ((process_t *)processes->get(cur_task))->p_page_dir ); -} - -u32_t create_task(void *base, u32_t image_size, u32_t bss_size, void *entry) -{ - u32_t pid = get_pid(); - processes->add(pid, create_process(base, image_size, bss_size, entry)); - pids->add(pid); - return pid; -} - -/* Create process_t struct for a new process - * image_size should be a multiple of 4096 - */ -process_t *create_process(void *base, u32_t image_size, u32_t bss_size, void *entry) -{ - if (mm_freepages < ((image_size + bss_size) >> 12) + 25) - return 0; - process_t *process = (process_t *) New(process_t); /* Allocate process_t struct */ - create_address_space(process); - create_process_stack(process, entry); - int i; - u32_t *ptr32 = process->v_page_dir = (u32_t *) vmm_palloc(); - for (i = 0; i < 1024; i++) - *ptr32++ = 0; - u32_t code_data_pages = (image_size + 4095) >> 12; - u32_t bss_pages = (bss_size + 4095) >> 12; - /* Load program at address 0 */ - copy_into_address_space(0, (char *) base, code_data_pages, process); - zero_address_space(code_data_pages << 12, bss_pages, process); - ptr32 = process->v_page_dir; - for (i = 0; i < 1024; i++) - if (*ptr32) - vmm_unmapp((void *)*ptr32); - vmm_unmapp(process->v_page_dir); - process->v_page_dir = 0; - process->size = image_size + bss_size; - return process; -} - -void create_address_space(process_t *p) -{ - /* Allocate a new page directory */ - p->page_dir = (u32_t *) vmm_palloc_addr(&p->p_page_dir); - int i; - u32_t *ptr32 = p->page_dir; - for (i = 0; i < 768; i++) /* zero 3 gigs */ - *ptr32++ = 0; - memcpyd(ptr32, (void *)0xFFFFFC00, 256); /* 1 gig kernel mem */ -} - -void create_process_stack(process_t *p, void *entry) -{ - u32_t p_stack_table, p_stack; - u32_t *v_stack_table = (u32_t *) vmm_palloc_addr(&p_stack_table); - u32_t *v_stack = (u32_t *) vmm_palloc_addr(&p_stack); - int i; - u32_t *ptr32 = v_stack_table; - for (i = 0; i < 1023; i++) - *ptr32++ = 0; - v_stack_table[1023] = p_stack | 0x7; /* user permissions */ - p->page_dir[511] = p_stack_table | 0x7; /* stack at 2GB */ - vmm_unmapp(v_stack_table); - vmm_unmapp(v_stack); - p->int_stack.ds = SEG_USER_DATA | 0x3; - p->int_stack.es = SEG_USER_DATA | 0x3; - p->int_stack.fs = SEG_USER_DATA | 0x3; - p->int_stack.gs = SEG_USER_DATA | 0x3; - p->int_stack.ss = SEG_USER_DATA | 0x3; - p->int_stack.esp = 0x80000000; /* esp at 2GB */ - p->int_stack.eflags = 0x0202; - p->int_stack.cs = SEG_USER_CODE | 0x3; - p->int_stack.eip = (u32_t)entry; -} - -/* Copy pages into new address space (v_page_dir must be set up) */ -void copy_into_address_space(u32_t dest_addr, - char *src_addr, - u32_t pages, - process_t *p) -{ - u32_t pde, pte; - void *page; - while (pages) - { - pde = dest_addr >> 22; - pte = (dest_addr >> 12) & 0x3FF; - u32_t p_page_addr; - if (!p->v_page_dir[pde]) - { - /* Time for a new page table & page directory entry! */ - p->v_page_dir[pde] = (u32_t)vmm_palloc_addr(&p_page_addr); - p->page_dir[pde] = p_page_addr | 0x7; - } - page = vmm_palloc_addr(&p_page_addr); - ((u32_t *)(p->v_page_dir[pde]))[pte] = p_page_addr | 0x7; - memcpyd(page, src_addr, 1024); - vmm_unmapp(page); - dest_addr += 4096; - src_addr += 4096; - pages--; - } -} - -/* Zeros pages into new address space (v_page_dir must be set up) */ -void zero_address_space(u32_t dest_addr, u32_t pages, process_t *p) -{ - u32_t pde, pte; - void *page; - while (pages) - { - pde = dest_addr >> 22; - pte = (dest_addr >> 12) & 0x3FF; - u32_t p_page_addr; - if (!p->v_page_dir[pde]) - { - /* Time for a new page table & page directory entry! */ - p->v_page_dir[pde] = (u32_t)vmm_palloc_addr(&p_page_addr); - p->page_dir[pde] = p_page_addr | 0x7; - vmm_unmapp((void *)p->v_page_dir[pde]); - } - page = vmm_palloc_addr(&p_page_addr); - ((u32_t *)(p->v_page_dir[pde]))[pte] = p_page_addr | 0x7; - memsetd(page, 0, 1024); - vmm_unmapp(page); - dest_addr += 4096; - pages--; - } -} - diff --git a/kernel/proc/proc.h b/kernel/proc/proc.h deleted file mode 100644 index df4e4c0..0000000 --- a/kernel/proc/proc.h +++ /dev/null @@ -1,91 +0,0 @@ -// proc.h -// Author: Josh Holtrop -// Date; 08/18/05 -// Modified: 08/18/05 - -#ifndef __HOS_PROC_H__ -#define __HOS_PROC_H__ __HOS_PROC_H__ - -#ifdef _HOS_CPP_ -extern "C" { -#endif - -#include "hos_defines.h" -#include "kernel.h" - -#define PROC_MIN_USER_PID 1024 - -typedef struct -{ - u32_t *page_dir; /* Page directory with physical PT addys */ - u32_t *v_page_dir; /* Virtual page table addresses for init */ - u32_t p_page_dir; /* Physical address of page directory */ - u32_t size; /* Process size, bytes from 0 through bss */ - u32_t uid; /* Process owner */ - int_stack_t int_stack; -} process_t; - -typedef struct -{ - u16_t backlink; - u16_t reserved0; - u32_t esp0; - u16_t ss0; - u16_t _ss0; - u32_t esp1; - u16_t ss1; - u16_t _ss1; - u32_t esp2; - u16_t ss2; - u16_t _ss2; - u32_t pdbr; - u32_t eip; - u32_t eflags; - u32_t eax; - u32_t ecx; - u32_t edx; - u32_t ebx; - u32_t esp; - u32_t ebp; - u32_t esi; - u32_t edi; - u16_t es; - u16_t _es; - u16_t cs; - u16_t _cs; - u16_t ss; - u16_t _ss; - u16_t ds; - u16_t _ds; - u16_t fs; - u16_t _fs; - u16_t gs; - u16_t _gs; - u16_t ldt; - u16_t _ldt; - u16_t trap; - u16_t iomap; -} __attribute__((packed)) tss_t; - -int proc_init(); -process_t *proc_get_struct(u32_t pid); - -void proc_sched(int_stack_t *int_stack); -u32_t get_pid(); -void switch_task(int_stack_t *int_stack, u32_t new_task); -u32_t create_task(void *base, u32_t image_size, u32_t bss_size, void *entry); -process_t *create_process(void *base, u32_t image_size, u32_t bss_size, void *entry); -void create_address_space(process_t *p); -void create_process_stack(process_t *p, void *entry); -void copy_into_address_space(u32_t dest_addr, - char *src_addr, - u32_t pages, - process_t *p); -void zero_address_space(u32_t dest_addr, u32_t pages, process_t *p); - -#ifdef _HOS_CPP_ -} -#endif - -#endif - diff --git a/kernel/sys/cmos.c b/kernel/sys/cmos.c deleted file mode 100644 index 827f32a..0000000 --- a/kernel/sys/cmos.c +++ /dev/null @@ -1,42 +0,0 @@ -// cmos.c -// Author: Josh Holtrop -// Created: 02/26/04 -// Implements various CMOS function calls - -#include "hos_defines.h" -#include "sys/cmos.h" -#include "sys/io.h" - -//Returns the cmos type of floppy disk drive 0 (0 = not present) -unsigned char cmos_getfd0() -{ - outportb(0x70, 0x10); - return (inportb(0x71) >> 4); -} - - -//Returns the cmos type of floppy disk drive 1 (0 = not present) -unsigned char cmos_getfd1() -{ - outportb(0x70, 0x10); - return (inportb(0x71) & 0x0F); -} - - -//Returns the cmos type of hard disk drive 0 (0 = not present) -unsigned char cmos_gethd0() -{ - outportb(0x70, 0x12); - return (inportb(0x71) >> 4); -} - - -//Returns the cmos type of hard disk drive 1 (0 = not present) -unsigned char cmos_gethd1() -{ - outportb(0x70, 0x12); - return (inportb(0x71) & 0x0F); -} - - - diff --git a/kernel/sys/cmos.h b/kernel/sys/cmos.h deleted file mode 100644 index cf5ce52..0000000 --- a/kernel/sys/cmos.h +++ /dev/null @@ -1,18 +0,0 @@ -// cmos.h -// Author: Josh Holtrop -// Created: 02/26/04 -// Implements various CMOS function calls - -#include "hos_defines.h" - -#ifndef __HOS_CMOS__ -#define __HOS_CMOS__ __HOS_CMOS__ - -unsigned char cmos_getfd0(); -unsigned char cmos_getfd1(); -unsigned char cmos_gethd0(); -unsigned char cmos_gethd1(); - -#endif - - diff --git a/kernel/sys/io.h b/kernel/sys/io.h deleted file mode 100644 index 78b4c94..0000000 --- a/kernel/sys/io.h +++ /dev/null @@ -1,59 +0,0 @@ -// io.h -// Author: Josh Holtrop -// Created: 02/26/04 -// Implements basic port input/output functions - -#ifndef __HOS_IO__ -#define __HOS_IO__ __HOS_IO__ - -#include "hos_defines.h" - -//void outportb(unsigned int port, unsigned char value); -//inline void outportw(unsigned int port, unsigned int value); -//inline unsigned char inportb(unsigned short port); - -//Writes a byte out to a port -static inline void outportb(unsigned int port, unsigned int value) // Output a byte to a port -{ - asm volatile ("outb %%al,%%dx"::"d" (port), "a" (value)); -} - -//Writes a word out to a port -static inline void outportw(unsigned int port, unsigned int value) // Output a word to a port -{ - asm volatile ("outw %%ax,%%dx"::"d" (port), "a" (value)); -} - -//Writes a dword out to a port -static inline void outportd(unsigned int port, unsigned int value) // Output a word to a port -{ - asm volatile ("outl %%eax,%%dx"::"d" (port), "a" (value)); -} - -//Reads a byte from a port -static inline unsigned char inportb(unsigned int port) -{ - unsigned char ret_val; - asm volatile("inb %w1,%b0" : "=a"(ret_val) : "d"(port)); - return ret_val; -} - -//Reads a word from a port -static inline unsigned short inportw(unsigned int port) -{ - unsigned int ret_val; - asm volatile("inw %w1,%w0" : "=a"(ret_val) : "d"(port)); - return ret_val; -} - -//Reads a dword from a port -static inline unsigned int inportd(unsigned int port) -{ - unsigned int ret_val; - asm volatile("inl %w1,%0" : "=a"(ret_val) : "d"(port)); - return ret_val; -} - -#endif - - diff --git a/kernel/sys/pci.cpp b/kernel/sys/pci.cpp deleted file mode 100644 index 56bfdbb..0000000 --- a/kernel/sys/pci.cpp +++ /dev/null @@ -1,59 +0,0 @@ -// pci.cpp -// Author: Josh Holtrop -// Date: 07/13/05 -// Modified: 07/17/05 - -extern "C" { -#include "hos_defines.h" -#include "display/kout.h" -#include "sys/io.h" -} - -#include "pci.h" -#include "lang/vector.h" - -vector *pci_devices; - -int pci_init() -{ - pci_devices = new vector; - pci_scanBus(0); - return 0; -} - -void pci_scanBus(u32_t bus) -{ - pci_header_t pciHdr; - u32_t dev, func, off, reg, numFuncs; - for (dev = 0; dev < 32; dev++) - { - numFuncs = 1; - for (func = 0; func < 8; func++) - { - reg = pci_readConfigRegister(bus, dev, func, 0); - if (reg != 0 && reg != 0xFFFFFFFF) - { - for (off = 0; off < 0x40; off += 4) - *((u32_t *)(((u32_t)&pciHdr)+off)) = pci_readConfigRegister(bus, dev, func, off); - pci_devices->add(pciHdr); - if (func == 0 && (pciHdr.header & 0x80)) - numFuncs = 8; - kprintf("PCI device %d.%d.%d:\t(%s)\n", bus, dev, func, pci_getDeviceClass(pciHdr.cls, pciHdr.subclass, pciHdr.progif)); - if ((pciHdr.header & 0x7F) == 1) - pci_scanBus(pciHdr.h1_bus1); - } - } - } -} - -u32_t pci_readConfigRegister(u32_t bus, u32_t dev, u32_t func, u32_t offset) -{ - outportd(PCI_CONFIG_ADDRESS, - 0x80000000 | - ((bus & 0xFF) << 16) | - ((dev & 0x1F) << 11) | - ((func & 0x7) << 8) | - (offset & 0xFC)); - return inportd(PCI_CONFIG_DATA); -} - diff --git a/kernel/sys/pci.h b/kernel/sys/pci.h deleted file mode 100644 index c1903e7..0000000 --- a/kernel/sys/pci.h +++ /dev/null @@ -1,75 +0,0 @@ -// pci.h -// Author: Josh Holtrop -// Date: 07/13/05 -// Modified: 07/13/05 - -#ifndef __HOS_PCI__ -#define __HOS_PCI__ __HOS_PCI__ - -#define PCI_CONFIG_ADDRESS 0xCF8 -#define PCI_CONFIG_DATA 0xCFC -#define PCI_HEADER_MF_MASK 0x80 - -#include "hos_defines.h" - -typedef struct -{ - u8_t subclass; - u8_t progif; - char *desc; -} pci_class_t; - -typedef struct -{ - u16_t vendorID; /* 0x00 Vender ID Number */ - u16_t deviceID; /* 0x02 Device ID Number */ - u16_t command; /* 0x04 Command Register */ - u16_t status; /* 0x06 Status Register */ - u8_t revision; /* 0x08 Revision ID */ - u8_t progif; /* 0x09 Programming Interface */ - u8_t subclass; /* 0x0A Subclass Number */ - u8_t cls; /* 0x0B PCI Device Class */ - u8_t cacheLineSize; /* 0x0C Cache Line Size (for DMA) */ - u8_t latency; /* 0x0D Latency Timer (PCI Bus cycles) */ - u8_t header; /* 0x0E bit7:multifunc, 0-6: header format */ - u8_t bist; /* 0x0F Built-In Self Test Result */ - /* Header-specific fields */ - u32_t bar0; /* 0x10 */ - u32_t bar1; /* 0x14 */ - union { /* 0x18 */ - u32_t bar2; - struct { - u8_t h1_bus0; - u8_t h1_bus1; - u8_t h1_secBus; - u8_t h1_secLatency; - }; - }; - u32_t bar3; /* 0x1C */ - u32_t bar4; /* 0x20 */ - u32_t bar5; /* 0x24 */ - u32_t cardbusCIS; /* 0x28 ro */ - u16_t ssVendorID; /* 0x2C */ - u16_t ssID; /* 0x2E */ - u32_t expansionAddr; /* 0x30 */ - u32_t reserved[2]; /* 0x34 */ - u8_t irq; /* 0x3C IRQ Number, 0 if none */ - u8_t intPin; /* 0x3D Interrupt Pin, 0 if none, ro */ - u8_t minGrant; /* 0x3E 250ns units, ro */ - u8_t maxLatency; /* 0x3F 250ns units, ro */ -} pci_header_t; - -#ifdef _HOS_CPP_ -extern "C" { -#endif - -int pci_init(); -u32_t pci_readConfigRegister(u32_t bus, u32_t dev, u32_t func, u32_t offset); -char *pci_getDeviceClass(u8_t cls, u8_t sub, u8_t progif); - void pci_scanBus(u32_t bus); - -#ifdef _HOS_CPP_ -} -#endif - -#endif diff --git a/kernel/sys/pci_classes.c b/kernel/sys/pci_classes.c deleted file mode 100644 index fc4cdba..0000000 --- a/kernel/sys/pci_classes.c +++ /dev/null @@ -1,112 +0,0 @@ -// pci_classes.c -// Author: Josh Holtrop -// Date: 07/21/05 -// Modified: 07/21/05 -// Had to be a C file because g++ doesn't like pci_classes declaration - -#include "hos_defines.h" -#include "pci.h" - -pci_class_t* pci_classes[] = -{ - (pci_class_t[]) { - {1, 1, "Generic PCI VGA Device"}, - {0xFF, 0xFF, "Generic PCI Device"} - }, - (pci_class_t[]) { - {0, 0, "SCSI Controller"}, - {1, 0xFF, "IDE Controller"}, - {2, 0, "Floppy Disk Controller"}, - {3, 0, "IPI Controller"}, - {4, 0, "RAID Controller"}, - {0xFF, 0xFF, "Generic Mass Storage Controller"} - }, - (pci_class_t[]) { - {0, 0, "Ethernet Controller"}, - {1, 0, "Token Ring Network Controller"}, - {2, 0, "FDDI Controller"}, - {3, 0, "ATM Controller"}, - {0xFF, 0xFF, "Generic Network Controller"} - }, - (pci_class_t[]) { - {0, 0, "VGA Compatible Controller"}, - {0, 1, "8514 Compatible Display Controller"}, - {1, 0, "XGA Controller"}, - {0xFF, 0xFF, "Generic Display Controller"} - }, - (pci_class_t[]) { - {0, 0, "Multimedia Video Device"}, - {0, 0, "Multimedia Audio Device"}, - {0xFF, 0xFF, "Generic Multimedia Device"} - }, - (pci_class_t[]) { - {0, 0, "RAM Controller"}, - {1, 0, "Flash Memory Controller"}, - {0xFF, 0xFF, "Generic Memory Controller"} - }, - (pci_class_t[]) { - {0, 0, "Host/PCI Bridge"}, - {1, 0, "PCI/ISA Bridge"}, - {2, 0, "PCI/EISA Bridge"}, - {3, 0, "PCI/Micro Channel Bridge"}, - {4, 0, "PCI/PCI Bridge"}, - {5, 0, "PCI/PCMCIA Bridge"}, - {6, 0, "PCI/NuBus Bridge"}, - {7, 0, "PCI/CardBus Bridge"}, - {0xFF, 0xFF, "Generic Bridge"} - }, - (pci_class_t[]) { - {0, 0xFF, "Serial Controller"}, - {1, 0xFF, "Parallel Port"}, - {0xFF, 0xFF, "Generic Communications Device"} - }, - (pci_class_t[]) { - {0, 0xFF, "Programmable Interrupt Controller"}, - {1, 0xFF, "DMA Controller"}, - {2, 0xFF, "System Timer"}, - {3, 0xFF, "RTC Controller"}, - {0xFF, 0xFF, "Generic System Peripheral"} - }, - (pci_class_t[]) { - {0, 0, "Keyboard Controller"}, - {1, 0, "Digitizer (Pen)"}, - {2, 0, "Mouse Controller"}, - {0xFF, 0xFF, ""} - }, - (pci_class_t[]) { - {0xFF, 0xFF, "Docking Station"} - }, - (pci_class_t[]) { - {0, 0, "386 Processor"}, - {1, 0, "486 Processor"}, - {2, 0, "Pentium Processor"}, - {0x10, 0, "Alpha Processor"}, - {0x20, 0, "PowerPC Processor"}, - {0x40, 0, "Co-Processor"}, - {0xFF, 0xFF, "Generic Processor"} - }, - (pci_class_t[]) { - {0, 0, "Firewire (IEEE 1394) Controller"}, - {1, 0, "ACCESS Bus Controller"}, - {2, 0, "SSA (Serial Storage Architecture) Controller"}, - {3, 0, "USB Controller"}, - {0xFF, 0xFF, "Generic Serial Bus Controller"} - } -}; - -char *pci_getDeviceClass(u8_t cls, u8_t sub, u8_t progif) -{ - if (cls < sizeof(pci_classes)/sizeof(pci_class_t *)) - { - pci_class_t *pcls = pci_classes[cls]; - for (;;) - { - if ( (pcls->subclass == 0xFF || pcls->subclass == sub) - && (pcls->progif == 0xFF || pcls->progif == progif) ) - return pcls->desc; - pcls++; - } - } - return "Unknown PCI Device"; -} - diff --git a/kernel/sys/pic.c b/kernel/sys/pic.c deleted file mode 100644 index 310ff60..0000000 --- a/kernel/sys/pic.c +++ /dev/null @@ -1,30 +0,0 @@ -// pic.c -// Author: Josh Holtrop -// Created: 02/26/04 - -#include "hos_defines.h" -#include "pic.h" -#include "sys/io.h" - -//Re-maps the Programmable Interrupr Controllers so IRQ0->pic1 base address, IRG8->pic2 base address -void pic_remap(int pic1, int pic2) -{ - byte a1, a2; - - a1 = inportb(PIC1_DATA); //0x21 - a2 = inportb(PIC2_DATA); //0xA1 - - outportb(PIC1_COMMAND, ICW1_INIT+ICW1_ICW4); //0x20, 0x10+0x01 00010001b - outportb(PIC2_COMMAND, ICW1_INIT+ICW1_ICW4); //0xA0, 0x10+0x01 00010001b - outportb(PIC1_DATA, pic1); //0x21, pic1 - outportb(PIC2_DATA, pic2); //0xA1, pic2 - outportb(PIC1_DATA, 4); //0x21, 0x04 00000100b - outportb(PIC2_DATA, 2); //0xA1, 0x02 00000010b - outportb(PIC1_DATA, ICW4_8086); //0x21, 0x01 00000001b - outportb(PIC2_DATA, ICW4_8086); //0xA1, 0x01 00000001b - - outportb(PIC1_DATA, a1); //0x21 - outportb(PIC2_DATA, a2); //0xA1 -} - - diff --git a/kernel/sys/pic.h b/kernel/sys/pic.h deleted file mode 100644 index c363732..0000000 --- a/kernel/sys/pic.h +++ /dev/null @@ -1,65 +0,0 @@ -// pic.h -// Author: Josh Holtrop -// Created: 02/26/04 - -#ifndef __HOS_PIC__ -#define __HOS_PIC__ __HOS_PIC__ - -#include "hos_defines.h" -#include "sys/io.h" - -#define PIC1 0x20 -#define PIC2 0xA0 -#define PIC1_COMMAND PIC1 -#define PIC1_DATA (PIC1+1) -#define PIC2_COMMAND PIC2 -#define PIC2_DATA (PIC2+1) -#define PIC_EOI 0x20 - -#define ICW1_ICW4 0x01 /* ICW4 (not) needed */ -#define ICW1_SINGLE 0x02 /* Single (cascade) mode */ -#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */ -#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */ -#define ICW1_INIT 0x10 /* Initialization - required! */ - -#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */ -#define ICW4_AUTO 0x02 /* Auto (normal) EOI */ -#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */ -#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */ -#define ICW4_SFNM 0x10 /* Special fully nested (not) */ - -void pic_remap(int pic1, int pic2); -//inline void pic_mask1(byte mask); -//inline void pic_mask2(byte mask); -//inline void pic_eoi(); -//inline void pic_eoi2(); - -//Masks interrupts on first Programmable Interrupt Controller -static inline void pic_mask1(byte mask) -{ - outportb(PIC1_DATA, mask); //0x21, maskfield *OCW1* -} - -//Masks interrupts on second Programmable Interrupt Controller -static inline void pic_mask2(byte mask) -{ - outportb(PIC2_DATA, mask); //0xA1, maskfield *OCW1* -} - - -//Signals an End Of Interrupt signal to the first PIC -static inline void pic_eoi() -{ - outportb(0x20, 0x20); -} - -//Signals an End Of Interrupt signal to both the second and first PIC unit -static inline void pic_eoi2() -{ - outportb(0xA0, 0x20); - outportb(0x20, 0x20); -} - -#endif - - diff --git a/kernel/sys/rtc.c b/kernel/sys/rtc.c deleted file mode 100644 index d0cd1ad..0000000 --- a/kernel/sys/rtc.c +++ /dev/null @@ -1,83 +0,0 @@ -// rtc.c -// Author: Josh Holtrop -// Created: 02/26/04 -// Implements Real-Time Clock function calls -// These functions are for reading and writing various values stored on the CMOS Real Time Clock -// Parameters / return values are in BCD format - -#include "hos_defines.h" -#include "sys/rtc.h" -#include "sys/io.h" - -unsigned char rtc_readDay() -{ - outportb(0x70, 7); - return inportb(0x71); -} - -unsigned char rtc_readMonth() -{ - outportb(0x70, 8); - return inportb(0x71); -} - -unsigned char rtc_readYear() -{ - outportb(0x70, 9); - return inportb(0x71); -} - -unsigned char rtc_readSecond() -{ - outportb(0x70, 0); - return inportb(0x71); -} - -unsigned char rtc_readMinute() -{ - outportb(0x70, 2); - return inportb(0x71); -} - -unsigned char rtc_readHour() -{ - outportb(0x70, 4); - return inportb(0x71); -} - -void rtc_setDay(unsigned char day) -{ - outportb(0x70, 7); - outportb(0x71, day); -} - -void rtc_setMonth(unsigned char month) -{ - outportb(0x70, 8); - outportb(0x71, month); -} - -void rtc_setYear(unsigned char year) -{ - outportb(0x70, 9); - outportb(0x71, year); -} - -void rtc_setSecond(unsigned char second) -{ - outportb(0x70, 0); - outportb(0x71, second); -} - -void rtc_setMinute(unsigned char minute) -{ - outportb(0x70, 2); - outportb(0x71, minute); -} - -void rtc_setHour(unsigned char hour) -{ - outportb(0x70, 4); - outportb(0x71, hour); -} - diff --git a/kernel/sys/rtc.h b/kernel/sys/rtc.h deleted file mode 100644 index 3c589de..0000000 --- a/kernel/sys/rtc.h +++ /dev/null @@ -1,28 +0,0 @@ -// rtc.h -// Author: Josh Holtrop -// Created: 02/26/04 -// Implements Real-Time Clock function calls -// These functions are for reading and writing various values stored on the CMOS Real Time Clock -// Parameters / return values are in BCD format - -#ifndef __HOS_RTC__ -#define __HOS_RTC__ __HOS_RTC__ - -#include "hos_defines.h" - -unsigned char rtc_readDay(); -unsigned char rtc_readMonth(); -unsigned char rtc_readYear(); -unsigned char rtc_readSecond(); -unsigned char rtc_readMinute(); -unsigned char rtc_readHour(); -void rtc_setDay(unsigned char dat); -void rtc_setMonth(unsigned char month); -void rtc_setYear(unsigned char year); -void rtc_setSecond(unsigned char second); -void rtc_setMinute(unsigned char minute); -void rtc_setHour(unsigned char hour); - -#endif - - diff --git a/kernel/syscall.c b/kernel/syscall.c deleted file mode 100644 index 4002755..0000000 --- a/kernel/syscall.c +++ /dev/null @@ -1,25 +0,0 @@ -// syscall.c -// Author: Josh Holtrop -// Date; 01/02/06 -// Modified: 01/02/06 - -#include "syscall.h" -#include "display/kout.h" -#include "proc/proc.h" - -void syscall(u32_t cur_task, int_stack_t *int_stack) -{ - static u32_t times = 0; - process_t *proc = proc_get_struct(cur_task); - switch (int_stack->eax) - { - case 1: - times++; - kprintf("\033[sTimes Called: %d\033[u", times); - break; - case 2: - kprintf("%s", int_stack->ebx); - break; - } -} - diff --git a/kernel/syscall.h b/kernel/syscall.h deleted file mode 100644 index 08171a0..0000000 --- a/kernel/syscall.h +++ /dev/null @@ -1,14 +0,0 @@ -// syscall.h -// Author: Josh Holtrop -// Date; 01/02/06 -// Modified: 01/02/06 - -#ifndef __HOS_SYSCALL_H__ -#define __HOS_SYSCALL_H__ __HOS_SYSCALL_H__ - -#include "hos_defines.h" -#include "kernel.h" - -void syscall(u32_t cur_task, int_stack_t *int_stack); - -#endif diff --git a/kernel/vmm.S b/kernel/vmm.S deleted file mode 100644 index 233b611..0000000 --- a/kernel/vmm.S +++ /dev/null @@ -1,1272 +0,0 @@ - .file "vmm.c" - .intel_syntax - .text -.globl _vmm_init - .type _vmm_init, @function -_vmm_init: - push %ebp - mov %ebp, %esp - sub %esp, 24 - mov DWORD PTR [%ebp-4], 0 -.L2: - mov %eax, DWORD PTR [%ebp-4] - cmp %eax, DWORD PTR _mb_info_block+20 - jb .L5 - jmp .L3 -.L5: - mov %eax, DWORD PTR [%ebp-4] - sal %eax, 4 - mov %eax, DWORD PTR _mb_modules[%eax] - add %eax, 1073741824 - mov DWORD PTR [%esp+8], %eax - mov %eax, DWORD PTR [%ebp-4] - sal %eax, 4 - mov %eax, DWORD PTR _mb_modules[%eax+4] - dec %eax - mov DWORD PTR [%esp+4], %eax - mov %eax, DWORD PTR [%ebp-4] - sal %eax, 4 - mov %eax, DWORD PTR _mb_modules[%eax] - mov DWORD PTR [%esp], %eax - call _vmm_map_range - lea %eax, [%ebp-4] - inc DWORD PTR [%eax] - jmp .L2 -.L3: - mov DWORD PTR [%ebp-4], 0 -.L6: - cmp DWORD PTR [%ebp-4], 3 - jle .L9 - jmp .L7 -.L9: - mov %ecx, DWORD PTR [%ebp-4] - mov %eax, DWORD PTR [%ebp-4] - mov %edx, %eax - sal %edx, 4 - mov %eax, OFFSET FLAT:_heapEntryHeadNodes - add %eax, %edx - mov DWORD PTR _heapEntryQueues[4+%ecx*8], %eax - mov %eax, DWORD PTR [%ebp-4] - mov %ecx, %eax - sal %ecx, 4 - mov %eax, DWORD PTR [%ebp-4] - mov %edx, %eax - sal %edx, 4 - mov %eax, OFFSET FLAT:_heapEntryTailNodes - add %eax, %edx - mov DWORD PTR _heapEntryHeadNodes[%ecx+8], %eax - mov %eax, DWORD PTR [%ebp-4] - mov %ecx, %eax - sal %ecx, 4 - mov %eax, DWORD PTR [%ebp-4] - mov %edx, %eax - sal %edx, 4 - mov %eax, OFFSET FLAT:_heapEntryHeadNodes - add %eax, %edx - mov DWORD PTR _heapEntryTailNodes[%ecx+12], %eax - lea %eax, [%ebp-4] - inc DWORD PTR [%eax] - jmp .L6 -.L7: - mov DWORD PTR [%esp], OFFSET FLAT:_initialHEB - call _vmm_heb_init - mov DWORD PTR [%esp+8], OFFSET FLAT:_initialHEB - mov DWORD PTR [%esp+4], OFFSET FLAT:_heapEntryHeadNodes - mov DWORD PTR [%esp], 0 - call _vmm_addToQueue - call _vmm_stripUnusedEntry - mov DWORD PTR [%ebp-8], %eax - mov %eax, DWORD PTR [%ebp-8] - mov DWORD PTR [%eax], -805306368 - mov %eax, DWORD PTR [%ebp-8] - mov DWORD PTR [%eax+4], 536870912 - mov %eax, DWORD PTR [%ebp-8] - mov DWORD PTR [%esp+8], %eax - mov DWORD PTR [%esp+4], OFFSET FLAT:_heapEntryHeadNodes+48 - mov DWORD PTR [%esp], 3 - call _vmm_addToQueue - leave - ret - .size _vmm_init, .-_vmm_init -.globl _vmm_map - .type _vmm_map, @function -_vmm_map: - push %ebp - mov %ebp, %esp - sub %esp, 24 - lea %eax, [%ebp-4] - mov DWORD PTR [%esp+4], %eax - mov %eax, DWORD PTR [%ebp+8] - mov DWORD PTR [%esp], %eax - call _vmm_map_addr - leave - ret - .size _vmm_map, .-_vmm_map -.globl _vmm_map_addr - .type _vmm_map_addr, @function -_vmm_map_addr: - push %ebp - mov %ebp, %esp - sub %esp, 24 - cmp DWORD PTR _mm_freepages, 9 - ja .L12 - mov DWORD PTR [%ebp-4], -1 - jmp .L11 -.L12: - call _mm_palloc - mov %edx, %eax - mov %eax, DWORD PTR [%ebp+12] - mov DWORD PTR [%eax], %edx - mov %eax, DWORD PTR [%eax] - mov DWORD PTR [%esp+4], %eax - mov %eax, DWORD PTR [%ebp+8] - mov DWORD PTR [%esp], %eax - call _vmm_map1 - mov DWORD PTR [%ebp-4], %eax -.L11: - mov %eax, DWORD PTR [%ebp-4] - leave - ret - .size _vmm_map_addr, .-_vmm_map_addr -.globl _vmm_map1 - .type _vmm_map1, @function -_vmm_map1: - push %ebp - mov %ebp, %esp - sub %esp, 40 - and DWORD PTR [%ebp+8], -4096 - lea %eax, [%ebp+12] - and DWORD PTR [%eax], -4096 - mov %eax, DWORD PTR [%ebp+8] - shr %eax, 22 - mov DWORD PTR [%ebp-4], %eax - mov %eax, DWORD PTR [%ebp+8] - and %eax, 4190208 - shr %eax, 12 - mov DWORD PTR [%ebp-8], %eax - mov DWORD PTR [%ebp-12], -4096 - mov %eax, DWORD PTR [%ebp-4] - lea %edx, [0+%eax*4] - mov %eax, DWORD PTR [%ebp-12] - mov %eax, DWORD PTR [%eax+%edx] - and %eax, 1 - test %eax, %eax - jne .L14 - call _mm_palloc - mov DWORD PTR [%ebp-16], %eax - cmp DWORD PTR [%ebp-16], 0 - jne .L15 - mov DWORD PTR [%ebp-20], -1 - jmp .L13 -.L15: - mov %eax, DWORD PTR [%ebp-4] - lea %ecx, [0+%eax*4] - mov %edx, DWORD PTR [%ebp-12] - mov %eax, DWORD PTR [%ebp-16] - or %eax, 3 - mov DWORD PTR [%edx+%ecx], %eax - mov %eax, DWORD PTR [%ebp-4] - sal %eax, 2 - sub %eax, 4096 - mov DWORD PTR [%esp], %eax - call _invlpg_ - mov %eax, DWORD PTR [%ebp+8] - mov DWORD PTR [%esp], %eax - call _invlpg_ - mov DWORD PTR [%esp+8], 1024 - mov DWORD PTR [%esp+4], 0 - mov %eax, DWORD PTR [%ebp-4] - sal %eax, 12 - or %eax, -4194304 - mov DWORD PTR [%esp], %eax - call _memsetd -.L14: - mov %eax, DWORD PTR [%ebp-4] - mov %edx, %eax - sal %edx, 12 - mov %eax, DWORD PTR [%ebp-8] - sal %eax, 2 - or %eax, %edx - mov %edx, %eax - or %edx, -4194304 - mov %eax, DWORD PTR [%ebp+12] - or %eax, 3 - mov DWORD PTR [%edx], %eax - mov %eax, DWORD PTR [%ebp-4] - mov %edx, %eax - sal %edx, 12 - mov %eax, DWORD PTR [%ebp-8] - sal %eax, 2 - or %eax, %edx - or %eax, -4194304 - mov DWORD PTR [%esp], %eax - call _invlpg_ - mov %eax, DWORD PTR [%ebp+8] - mov DWORD PTR [%esp], %eax - call _invlpg_ - mov DWORD PTR [%ebp-20], 0 -.L13: - mov %eax, DWORD PTR [%ebp-20] - leave - ret - .size _vmm_map1, .-_vmm_map1 -.globl _vmm_mapn - .type _vmm_mapn, @function -_vmm_mapn: - push %ebp - mov %ebp, %esp - sub %esp, 24 - nop -.L17: - cmp DWORD PTR [%ebp+16], 0 - jne .L19 - jmp .L18 -.L19: - mov %eax, DWORD PTR [%ebp+12] - mov DWORD PTR [%esp+4], %eax - mov %eax, DWORD PTR [%ebp+8] - mov DWORD PTR [%esp], %eax - call _vmm_map1 - test %eax, %eax - je .L20 - mov DWORD PTR [%ebp-4], 1 - jmp .L16 -.L20: - add DWORD PTR [%ebp+8], 4096 - lea %eax, [%ebp+12] - add DWORD PTR [%eax], 4096 - lea %eax, [%ebp+16] - dec DWORD PTR [%eax] - jmp .L17 -.L18: - mov DWORD PTR [%ebp-4], 0 -.L16: - mov %eax, DWORD PTR [%ebp-4] - leave - ret - .size _vmm_mapn, .-_vmm_mapn -.globl _vmm_unmap1 - .type _vmm_unmap1, @function -_vmm_unmap1: - push %ebp - mov %ebp, %esp - sub %esp, 8 - mov %eax, DWORD PTR [%ebp+8] - and %eax, -4194304 - mov %edx, %eax - shr %edx, 10 - mov %eax, DWORD PTR [%ebp+8] - and %eax, 4190208 - shr %eax, 10 - or %eax, %edx - or %eax, -4194304 - mov DWORD PTR [%eax], 0 - mov %eax, DWORD PTR [%ebp+8] - mov DWORD PTR [%esp], %eax - call _invlpg_ - leave - ret - .size _vmm_unmap1, .-_vmm_unmap1 -.globl _vmm_unmapn - .type _vmm_unmapn, @function -_vmm_unmapn: - push %ebp - mov %ebp, %esp - sub %esp, 8 - nop -.L23: - cmp DWORD PTR [%ebp+12], 0 - jne .L25 - jmp .L22 -.L25: - mov %eax, DWORD PTR [%ebp+8] - mov DWORD PTR [%esp], %eax - call _vmm_unmap1 - add DWORD PTR [%ebp+8], 4096 - lea %eax, [%ebp+12] - dec DWORD PTR [%eax] - jmp .L23 -.L22: - leave - ret - .size _vmm_unmapn, .-_vmm_unmapn -.globl _vmm_map_range - .type _vmm_map_range, @function -_vmm_map_range: - push %ebp - mov %ebp, %esp - sub %esp, 24 - mov %eax, DWORD PTR [%ebp+12] - cmp %eax, DWORD PTR [%ebp+8] - jae .L27 - mov DWORD PTR [%ebp-4], -1 - jmp .L26 -.L27: - nop -.L28: - mov %eax, DWORD PTR [%ebp+8] - cmp %eax, DWORD PTR [%ebp+12] - jb .L30 - jmp .L29 -.L30: - mov %eax, DWORD PTR [%ebp+16] - mov DWORD PTR [%esp+4], %eax - mov %eax, DWORD PTR [%ebp+8] - mov DWORD PTR [%esp], %eax - call _vmm_map1 - test %eax, %eax - je .L31 - mov DWORD PTR [%ebp-4], -2 - jmp .L26 -.L31: - add DWORD PTR [%ebp+8], 4096 - lea %eax, [%ebp+16] - add DWORD PTR [%eax], 4096 - jmp .L28 -.L29: - mov DWORD PTR [%ebp-4], 0 -.L26: - mov %eax, DWORD PTR [%ebp-4] - leave - ret - .size _vmm_map_range, .-_vmm_map_range -.globl _kmalloc - .type _kmalloc, @function -_kmalloc: - push %ebp - mov %ebp, %esp - sub %esp, 24 - call _k_enter_critical - mov %eax, DWORD PTR [%ebp+8] - and %eax, 3 - test %eax, %eax - je .L33 - mov %eax, DWORD PTR [%ebp+8] - mov %edx, %eax - and %edx, 3 - mov %eax, DWORD PTR [%ebp+8] - sub %eax, %edx - add %eax, 4 - mov DWORD PTR [%ebp+8], %eax -.L33: - mov %eax, DWORD PTR [%ebp+8] - mov DWORD PTR [%esp], %eax - call _vmm_getFreeChunk - mov DWORD PTR [%ebp-4], %eax - cmp DWORD PTR [%ebp-4], 0 - je .L34 - call _k_leave_critical - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%ebp-8], %eax - jmp .L32 -.L34: - mov %eax, DWORD PTR [%ebp+8] - mov DWORD PTR [%esp], %eax - call _vmm_moreCore - test %eax, %eax - je .L35 - call _k_leave_critical - mov DWORD PTR [%ebp-8], 0 - jmp .L32 -.L35: - mov %eax, DWORD PTR [%ebp+8] - mov DWORD PTR [%esp], %eax - call _vmm_getFreeChunk - mov DWORD PTR [%ebp-4], %eax - call _k_leave_critical - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%ebp-8], %eax -.L32: - mov %eax, DWORD PTR [%ebp-8] - leave - ret - .size _kmalloc, .-_kmalloc -.globl _kfree - .type _kfree, @function -_kfree: - push %ebp - mov %ebp, %esp - sub %esp, 24 - call _k_enter_critical - mov %eax, DWORD PTR _heapEntryQueues+20 - mov %eax, DWORD PTR [%eax+8] - mov DWORD PTR [%ebp-4], %eax -.L37: - mov %eax, DWORD PTR [%ebp-4] - cmp DWORD PTR [%eax+8], 0 - jne .L39 - jmp .L38 -.L39: - mov %eax, DWORD PTR [%ebp-4] - mov %eax, DWORD PTR [%eax] - cmp %eax, DWORD PTR [%ebp+8] - jne .L40 - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%esp+4], %eax - mov DWORD PTR [%esp], 2 - call _vmm_removeHeapEntry - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%esp+4], %eax - mov DWORD PTR [%esp], 1 - call _vmm_coalesceEntry - test %eax, %eax - je .L41 - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%esp+8], %eax - mov %eax, DWORD PTR _heapEntryQueues+12 - mov DWORD PTR [%esp+4], %eax - mov DWORD PTR [%esp], 1 - call _vmm_addToQueue - jmp .L38 -.L41: - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%esp+8], %eax - mov %eax, DWORD PTR _heapEntryQueues+4 - mov DWORD PTR [%esp+4], %eax - mov DWORD PTR [%esp], 0 - call _vmm_addToQueue - jmp .L38 -.L40: - mov %eax, DWORD PTR [%ebp-4] - mov %eax, DWORD PTR [%eax+8] - mov DWORD PTR [%ebp-4], %eax - jmp .L37 -.L38: - call _k_leave_critical - mov %eax, 0 - leave - ret - .size _kfree, .-_kfree -.globl _vmm_palloc - .type _vmm_palloc, @function -_vmm_palloc: - push %ebp - mov %ebp, %esp - sub %esp, 8 - lea %eax, [%ebp-4] - mov DWORD PTR [%esp], %eax - call _vmm_palloc_addr - leave - ret - .size _vmm_palloc, .-_vmm_palloc -.globl _vmm_palloc_addr - .type _vmm_palloc_addr, @function -_vmm_palloc_addr: - push %ebp - mov %ebp, %esp - sub %esp, 24 - call _k_enter_critical - mov %eax, DWORD PTR _heapEntryQueues+28 - mov %eax, DWORD PTR [%eax+8] - mov DWORD PTR [%ebp-4], %eax - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%ebp-8], %eax -.L45: - mov %eax, DWORD PTR [%ebp-4] - cmp DWORD PTR [%eax+8], 0 - jne .L47 - jmp .L46 -.L47: - mov %eax, DWORD PTR [%ebp-4] - cmp DWORD PTR [%eax+4], 4096 - jne .L48 - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%esp+4], %eax - mov DWORD PTR [%esp], 3 - call _vmm_removeHeapEntry - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%esp+8], %eax - mov DWORD PTR [%esp+4], OFFSET FLAT:_heapEntryHeadNodes+32 - mov DWORD PTR [%esp], 2 - call _vmm_addToQueue - mov %eax, DWORD PTR [%ebp+8] - mov DWORD PTR [%esp+4], %eax - mov %eax, DWORD PTR [%ebp-4] - mov %eax, DWORD PTR [%eax] - mov DWORD PTR [%esp], %eax - call _vmm_map_addr - test %eax, %eax - je .L49 - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%eax], 0 -.L49: - call _k_leave_critical - mov %eax, DWORD PTR [%ebp-4] - mov %eax, DWORD PTR [%eax] - mov DWORD PTR [%ebp-12], %eax - jmp .L44 -.L48: - mov %eax, DWORD PTR [%ebp-4] - mov %edx, DWORD PTR [%ebp-8] - mov %eax, DWORD PTR [%eax+4] - cmp %eax, DWORD PTR [%edx+4] - jbe .L50 - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%ebp-8], %eax -.L50: - mov %eax, DWORD PTR [%ebp-4] - mov %eax, DWORD PTR [%eax+8] - mov DWORD PTR [%ebp-4], %eax - jmp .L45 -.L46: - mov %eax, DWORD PTR [%ebp-8] - cmp DWORD PTR [%eax+4], 65535 - ja .L51 - call _k_leave_critical - mov DWORD PTR [%ebp-12], 0 - jmp .L44 -.L51: - mov %edx, DWORD PTR [%ebp-8] - mov %eax, DWORD PTR [%ebp-8] - mov %eax, DWORD PTR [%eax+4] - sub %eax, 4096 - mov DWORD PTR [%edx+4], %eax - call _vmm_getUnusedEntry - mov DWORD PTR [%ebp-4], %eax - mov %ecx, DWORD PTR [%ebp-4] - mov %edx, DWORD PTR [%ebp-8] - mov %eax, DWORD PTR [%ebp-8] - mov %eax, DWORD PTR [%eax+4] - add %eax, DWORD PTR [%edx] - mov DWORD PTR [%ecx], %eax - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%eax+4], 4096 - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%esp+8], %eax - mov DWORD PTR [%esp+4], OFFSET FLAT:_heapEntryHeadNodes+32 - mov DWORD PTR [%esp], 2 - call _vmm_addToQueue - mov %eax, DWORD PTR [%ebp+8] - mov DWORD PTR [%esp+4], %eax - mov %eax, DWORD PTR [%ebp-4] - mov %eax, DWORD PTR [%eax] - mov DWORD PTR [%esp], %eax - call _vmm_map_addr - test %eax, %eax - je .L52 - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%eax], 0 -.L52: - call _k_leave_critical - mov %eax, DWORD PTR [%ebp-4] - mov %eax, DWORD PTR [%eax] - mov DWORD PTR [%ebp-12], %eax -.L44: - mov %eax, DWORD PTR [%ebp-12] - leave - ret - .size _vmm_palloc_addr, .-_vmm_palloc_addr -.globl _vmm_pfree - .type _vmm_pfree, @function -_vmm_pfree: - push %ebp - mov %ebp, %esp - sub %esp, 24 - mov %eax, DWORD PTR [%ebp+8] - and %eax, -4194304 - mov %edx, %eax - shr %edx, 10 - mov %eax, DWORD PTR [%ebp+8] - and %eax, 4190208 - shr %eax, 10 - or %eax, %edx - or %eax, -4194304 - mov %eax, DWORD PTR [%eax] - mov DWORD PTR [%ebp-4], %eax - mov %eax, DWORD PTR [%ebp+8] - mov DWORD PTR [%esp], %eax - call _vmm_unmapp - test %eax, %eax - je .L54 - mov DWORD PTR [%ebp-8], -1 - jmp .L53 -.L54: - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%esp], %eax - call _mm_pfree - mov DWORD PTR [%ebp-8], 0 -.L53: - mov %eax, DWORD PTR [%ebp-8] - leave - ret - .size _vmm_pfree, .-_vmm_pfree -.globl _vmm_unmapp - .type _vmm_unmapp, @function -_vmm_unmapp: - push %ebp - mov %ebp, %esp - sub %esp, 24 - cmp DWORD PTR [%ebp+8], 0 - jne .L56 - mov DWORD PTR [%ebp-8], -2 - jmp .L55 -.L56: - call _k_enter_critical - mov %eax, DWORD PTR _heapEntryQueues+20 - mov %eax, DWORD PTR [%eax+8] - mov DWORD PTR [%ebp-4], %eax -.L57: - mov %eax, DWORD PTR [%ebp-4] - cmp DWORD PTR [%eax+8], 0 - jne .L59 - jmp .L58 -.L59: - mov %eax, DWORD PTR [%ebp-4] - mov %eax, DWORD PTR [%eax] - cmp %eax, DWORD PTR [%ebp+8] - jne .L60 - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%esp+4], %eax - mov DWORD PTR [%esp], 2 - call _vmm_removeHeapEntry - mov %eax, DWORD PTR [%ebp-4] - mov %eax, DWORD PTR [%eax] - mov DWORD PTR [%esp], %eax - call _vmm_unmap1 - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%esp+8], %eax - mov DWORD PTR [%esp+4], OFFSET FLAT:_heapEntryHeadNodes+48 - mov DWORD PTR [%esp], 3 - call _vmm_addToQueue - call _k_leave_critical - mov DWORD PTR [%ebp-8], 0 - jmp .L55 -.L60: - mov %eax, DWORD PTR [%ebp-4] - mov %eax, DWORD PTR [%eax+8] - mov DWORD PTR [%ebp-4], %eax - jmp .L57 -.L58: - call _k_leave_critical - mov DWORD PTR [%ebp-8], -1 -.L55: - mov %eax, DWORD PTR [%ebp-8] - leave - ret - .size _vmm_unmapp, .-_vmm_unmapp -.globl _kcalloc - .type _kcalloc, @function -_kcalloc: - push %ebp - mov %ebp, %esp - sub %esp, 24 - mov %eax, DWORD PTR [%ebp+8] - imul %eax, DWORD PTR [%ebp+12] - mov DWORD PTR [%esp], %eax - call _kmalloc - mov DWORD PTR [%ebp-4], %eax - cmp DWORD PTR [%ebp-4], 0 - jne .L62 - mov DWORD PTR [%ebp-8], 0 - jmp .L61 -.L62: - mov %eax, DWORD PTR [%ebp+8] - imul %eax, DWORD PTR [%ebp+12] - mov DWORD PTR [%esp+8], %eax - mov DWORD PTR [%esp+4], 0 - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%esp], %eax - call _memset - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%ebp-8], %eax -.L61: - mov %eax, DWORD PTR [%ebp-8] - leave - ret - .size _kcalloc, .-_kcalloc -.globl _krealloc - .type _krealloc, @function -_krealloc: - push %ebp - mov %ebp, %esp - sub %esp, 40 - mov %eax, DWORD PTR [%ebp+12] - mov DWORD PTR [%esp], %eax - call _kmalloc - mov DWORD PTR [%ebp-4], %eax - cmp DWORD PTR [%ebp-4], 0 - je .L64 - mov %eax, DWORD PTR _heapEntryQueues+20 - mov %eax, DWORD PTR [%eax+8] - mov DWORD PTR [%ebp-8], %eax -.L65: - mov %eax, DWORD PTR [%ebp-8] - cmp DWORD PTR [%eax+8], 0 - jne .L67 - jmp .L66 -.L67: - mov %eax, DWORD PTR [%ebp-8] - mov %eax, DWORD PTR [%eax] - cmp %eax, DWORD PTR [%ebp+8] - jne .L68 - mov %eax, DWORD PTR [%ebp-8] - mov %eax, DWORD PTR [%eax+4] - mov DWORD PTR [%ebp-20], %eax - mov %eax, DWORD PTR [%ebp+12] - mov DWORD PTR [%ebp-16], %eax - mov %eax, DWORD PTR [%ebp-20] - cmp DWORD PTR [%ebp-16], %eax - jbe .L69 - mov %eax, DWORD PTR [%ebp-20] - mov DWORD PTR [%ebp-16], %eax -.L69: - mov %eax, DWORD PTR [%ebp-16] - mov DWORD PTR [%esp+8], %eax - mov %eax, DWORD PTR [%ebp+8] - mov DWORD PTR [%esp+4], %eax - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%esp], %eax - call _memcpy - mov %eax, DWORD PTR [%ebp+8] - mov DWORD PTR [%esp], %eax - call _kfree - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%ebp-12], %eax - jmp .L63 -.L68: - mov %eax, DWORD PTR [%ebp-8] - mov %eax, DWORD PTR [%eax+8] - mov DWORD PTR [%ebp-8], %eax - jmp .L65 -.L66: - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%esp], %eax - call _kfree - mov DWORD PTR [%ebp-12], 0 - jmp .L63 -.L64: - mov DWORD PTR [%ebp-12], 0 -.L63: - mov %eax, DWORD PTR [%ebp-12] - leave - ret - .size _krealloc, .-_krealloc -.globl _vmm_getFreeChunk - .type _vmm_getFreeChunk, @function -_vmm_getFreeChunk: - push %ebp - mov %ebp, %esp - sub %esp, 40 - mov %eax, DWORD PTR _heapEntryQueues+12 - mov %eax, DWORD PTR [%eax+8] - mov DWORD PTR [%ebp-4], %eax - mov DWORD PTR [%ebp-8], 0 -.L72: - mov %eax, DWORD PTR [%ebp-4] - cmp DWORD PTR [%eax+8], 0 - jne .L74 - jmp .L73 -.L74: - mov %eax, DWORD PTR [%ebp-4] - mov %eax, DWORD PTR [%eax+4] - cmp %eax, DWORD PTR [%ebp+8] - jne .L75 - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%esp+4], %eax - mov DWORD PTR [%esp], 1 - call _vmm_removeHeapEntry - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%esp+8], %eax - mov %eax, DWORD PTR _heapEntryQueues+20 - mov DWORD PTR [%esp+4], %eax - mov DWORD PTR [%esp], 2 - call _vmm_addToQueue - mov %eax, DWORD PTR [%ebp-4] - mov %eax, DWORD PTR [%eax] - mov DWORD PTR [%ebp-16], %eax - jmp .L71 -.L75: - cmp DWORD PTR [%ebp-8], 0 - je .L76 - mov %eax, DWORD PTR [%ebp-4] - mov %eax, DWORD PTR [%eax+4] - cmp %eax, DWORD PTR [%ebp+8] - jbe .L78 - mov %eax, DWORD PTR [%ebp-4] - mov %edx, DWORD PTR [%ebp-8] - mov %eax, DWORD PTR [%eax+4] - cmp %eax, DWORD PTR [%edx+4] - jae .L78 - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%ebp-8], %eax - jmp .L78 -.L76: - mov %eax, DWORD PTR [%ebp-4] - mov %eax, DWORD PTR [%eax+4] - cmp %eax, DWORD PTR [%ebp+8] - jbe .L78 - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%ebp-8], %eax -.L78: - mov %eax, DWORD PTR [%ebp-4] - mov %eax, DWORD PTR [%eax+8] - mov DWORD PTR [%ebp-4], %eax - jmp .L72 -.L73: - cmp DWORD PTR [%ebp-8], 0 - je .L80 - call _vmm_getUnusedEntry - mov DWORD PTR [%ebp-12], %eax - mov %edx, DWORD PTR [%ebp-12] - mov %eax, DWORD PTR [%ebp-8] - mov %eax, DWORD PTR [%eax] - mov DWORD PTR [%edx], %eax - mov %edx, DWORD PTR [%ebp-12] - mov %eax, DWORD PTR [%ebp+8] - mov DWORD PTR [%edx+4], %eax - mov %ecx, DWORD PTR [%ebp-8] - mov %edx, DWORD PTR [%ebp-8] - mov %eax, DWORD PTR [%ebp+8] - add %eax, DWORD PTR [%edx] - mov DWORD PTR [%ecx], %eax - mov %ecx, DWORD PTR [%ebp-8] - mov %eax, DWORD PTR [%ebp-8] - mov %edx, DWORD PTR [%ebp+8] - mov %eax, DWORD PTR [%eax+4] - sub %eax, %edx - mov DWORD PTR [%ecx+4], %eax - mov %eax, DWORD PTR [%ebp-12] - mov DWORD PTR [%esp+8], %eax - mov %eax, DWORD PTR _heapEntryQueues+20 - mov DWORD PTR [%esp+4], %eax - mov DWORD PTR [%esp], 2 - call _vmm_addToQueue - mov %eax, DWORD PTR [%ebp-12] - mov %eax, DWORD PTR [%eax] - mov DWORD PTR [%ebp-16], %eax - jmp .L71 -.L80: - mov DWORD PTR [%ebp-16], 0 -.L71: - mov %eax, DWORD PTR [%ebp-16] - leave - ret - .size _vmm_getFreeChunk, .-_vmm_getFreeChunk -.globl _vmm_moreCore - .type _vmm_moreCore, @function -_vmm_moreCore: - push %ebp - mov %ebp, %esp - sub %esp, 40 - mov %eax, DWORD PTR [%ebp+8] - shr %eax, 12 - add %eax, 2 - mov DWORD PTR [%ebp-4], %eax - mov %eax, DWORD PTR [%ebp-4] - sal %eax, 12 - mov DWORD PTR [%ebp+8], %eax - mov %eax, DWORD PTR _mm_freepages - sub %eax, 5 - cmp %eax, DWORD PTR [%ebp-4] - jae .L82 - mov DWORD PTR [%ebp-28], -1 - jmp .L81 -.L82: - mov %eax, DWORD PTR _heapEntryQueues+28 - mov %eax, DWORD PTR [%eax+8] - mov DWORD PTR [%ebp-8], %eax - mov %eax, DWORD PTR [%ebp-8] - mov DWORD PTR [%ebp-12], %eax -.L83: - mov %eax, DWORD PTR [%ebp-8] - cmp DWORD PTR [%eax+8], 0 - jne .L85 - jmp .L84 -.L85: - mov %eax, DWORD PTR [%ebp-8] - mov %edx, DWORD PTR [%ebp-12] - mov %eax, DWORD PTR [%eax+4] - cmp %eax, DWORD PTR [%edx+4] - jbe .L86 - mov %eax, DWORD PTR [%ebp-8] - mov DWORD PTR [%ebp-12], %eax -.L86: - mov %eax, DWORD PTR [%ebp-8] - mov %eax, DWORD PTR [%eax+8] - mov DWORD PTR [%ebp-8], %eax - jmp .L83 -.L84: - mov %eax, DWORD PTR [%ebp-12] - mov %eax, DWORD PTR [%eax+4] - cmp %eax, DWORD PTR [%ebp+8] - ja .L87 - mov DWORD PTR [%ebp-28], -2 - jmp .L81 -.L87: - mov %eax, DWORD PTR [%ebp-12] - mov %eax, DWORD PTR [%eax] - mov DWORD PTR [%ebp-20], %eax - mov DWORD PTR [%ebp-16], 0 -.L88: - mov %eax, DWORD PTR [%ebp-16] - cmp %eax, DWORD PTR [%ebp-4] - jl .L91 - jmp .L89 -.L91: - mov %eax, DWORD PTR [%ebp-20] - mov DWORD PTR [%esp], %eax - call _vmm_map - lea %eax, [%ebp-20] - add DWORD PTR [%eax], 4096 - lea %eax, [%ebp-16] - inc DWORD PTR [%eax] - jmp .L88 -.L89: - call _vmm_getUnusedEntry - mov DWORD PTR [%ebp-24], %eax - mov %edx, DWORD PTR [%ebp-24] - mov %eax, DWORD PTR [%ebp-12] - mov %eax, DWORD PTR [%eax] - mov DWORD PTR [%edx], %eax - mov %edx, DWORD PTR [%ebp-24] - mov %eax, DWORD PTR [%ebp+8] - mov DWORD PTR [%edx+4], %eax - mov %ecx, DWORD PTR [%ebp-12] - mov %edx, DWORD PTR [%ebp-12] - mov %eax, DWORD PTR [%ebp+8] - add %eax, DWORD PTR [%edx] - mov DWORD PTR [%ecx], %eax - mov %ecx, DWORD PTR [%ebp-12] - mov %eax, DWORD PTR [%ebp-12] - mov %edx, DWORD PTR [%ebp+8] - mov %eax, DWORD PTR [%eax+4] - sub %eax, %edx - mov DWORD PTR [%ecx+4], %eax - mov %eax, DWORD PTR [%ebp-24] - mov DWORD PTR [%esp+4], %eax - mov DWORD PTR [%esp], 1 - call _vmm_coalesceEntry - test %eax, %eax - je .L92 - mov %eax, DWORD PTR [%ebp-24] - mov DWORD PTR [%esp+8], %eax - mov %eax, DWORD PTR _heapEntryQueues+12 - mov DWORD PTR [%esp+4], %eax - mov DWORD PTR [%esp], 1 - call _vmm_addToQueue - jmp .L93 -.L92: - mov %eax, DWORD PTR [%ebp-24] - mov DWORD PTR [%esp+8], %eax - mov %eax, DWORD PTR _heapEntryQueues+4 - mov DWORD PTR [%esp+4], %eax - mov DWORD PTR [%esp], 0 - call _vmm_addToQueue -.L93: - mov DWORD PTR [%ebp-28], 0 -.L81: - mov %eax, DWORD PTR [%ebp-28] - leave - ret - .size _vmm_moreCore, .-_vmm_moreCore -.globl _vmm_coalesceEntry - .type _vmm_coalesceEntry, @function -_vmm_coalesceEntry: - push %ebp - mov %ebp, %esp - sub %esp, 8 - mov %eax, DWORD PTR [%ebp+8] - mov %eax, DWORD PTR _heapEntryQueues[4+%eax*8] - mov %eax, DWORD PTR [%eax+8] - mov DWORD PTR [%ebp-4], %eax -.L95: - mov %eax, DWORD PTR [%ebp-4] - cmp DWORD PTR [%eax+8], 0 - jne .L97 - jmp .L96 -.L97: - mov %edx, DWORD PTR [%ebp-4] - mov %eax, DWORD PTR [%ebp-4] - mov %eax, DWORD PTR [%eax+4] - mov %edx, DWORD PTR [%edx] - add %edx, %eax - mov %eax, DWORD PTR [%ebp+12] - cmp %edx, DWORD PTR [%eax] - jne .L98 - mov %ecx, DWORD PTR [%ebp-4] - mov %edx, DWORD PTR [%ebp-4] - mov %eax, DWORD PTR [%ebp+12] - mov %eax, DWORD PTR [%eax+4] - add %eax, DWORD PTR [%edx+4] - mov DWORD PTR [%ecx+4], %eax - mov DWORD PTR [%ebp-8], 0 - jmp .L94 -.L98: - mov %edx, DWORD PTR [%ebp+12] - mov %eax, DWORD PTR [%ebp+12] - mov %eax, DWORD PTR [%eax+4] - mov %edx, DWORD PTR [%edx] - add %edx, %eax - mov %eax, DWORD PTR [%ebp-4] - cmp %edx, DWORD PTR [%eax] - jne .L99 - mov %edx, DWORD PTR [%ebp-4] - mov %eax, DWORD PTR [%ebp+12] - mov %eax, DWORD PTR [%eax] - mov DWORD PTR [%edx], %eax - mov %ecx, DWORD PTR [%ebp-4] - mov %edx, DWORD PTR [%ebp-4] - mov %eax, DWORD PTR [%ebp+12] - mov %eax, DWORD PTR [%eax+4] - add %eax, DWORD PTR [%edx+4] - mov DWORD PTR [%ecx+4], %eax - mov DWORD PTR [%ebp-8], 0 - jmp .L94 -.L99: - mov %eax, DWORD PTR [%ebp-4] - mov %eax, DWORD PTR [%eax+8] - mov DWORD PTR [%ebp-4], %eax - jmp .L95 -.L96: - mov DWORD PTR [%ebp-8], -1 -.L94: - mov %eax, DWORD PTR [%ebp-8] - leave - ret - .size _vmm_coalesceEntry, .-_vmm_coalesceEntry -.globl _vmm_removeHeapEntry - .type _vmm_removeHeapEntry, @function -_vmm_removeHeapEntry: - push %ebp - mov %ebp, %esp - mov %eax, DWORD PTR [%ebp+12] - mov %edx, DWORD PTR [%eax+12] - mov %eax, DWORD PTR [%ebp+12] - mov %eax, DWORD PTR [%eax+8] - mov DWORD PTR [%edx+8], %eax - mov %eax, DWORD PTR [%ebp+12] - mov %edx, DWORD PTR [%eax+8] - mov %eax, DWORD PTR [%ebp+12] - mov %eax, DWORD PTR [%eax+12] - mov DWORD PTR [%edx+12], %eax - mov %eax, DWORD PTR [%ebp+8] - dec DWORD PTR _heapEntryQueues[0+%eax*8] - mov %eax, DWORD PTR [%ebp+12] - mov DWORD PTR [%eax+8], 0 - mov %eax, DWORD PTR [%ebp+12] - mov DWORD PTR [%eax+12], 0 - pop %ebp - ret - .size _vmm_removeHeapEntry, .-_vmm_removeHeapEntry -.globl _vmm_heb_init - .type _vmm_heb_init, @function -_vmm_heb_init: - push %ebp - mov %ebp, %esp - sub %esp, 4 - mov DWORD PTR [%ebp-4], 0 -.L103: - cmp DWORD PTR [%ebp-4], 254 - jle .L106 - jmp .L104 -.L106: - mov %ecx, DWORD PTR [%ebp+8] - mov %eax, DWORD PTR [%ebp-4] - mov %edx, %eax - sal %edx, 4 - mov %eax, DWORD PTR [%ebp-4] - sal %eax, 4 - add %eax, DWORD PTR [%ebp+8] - add %eax, 16 - mov DWORD PTR [%ecx+8+%edx], %eax - mov %edx, DWORD PTR [%ebp+8] - mov %eax, DWORD PTR [%ebp-4] - sal %eax, 4 - add %eax, %edx - lea %edx, [%eax+16] - mov %eax, DWORD PTR [%ebp-4] - sal %eax, 4 - add %eax, DWORD PTR [%ebp+8] - mov DWORD PTR [%edx+12], %eax - lea %eax, [%ebp-4] - inc DWORD PTR [%eax] - jmp .L103 -.L104: - mov %eax, DWORD PTR [%ebp+8] - mov DWORD PTR [%eax+12], 0 - mov %eax, DWORD PTR [%ebp+8] - mov DWORD PTR [%eax+4088], 0 - leave - ret - .size _vmm_heb_init, .-_vmm_heb_init -.globl _vmm_addToQueue - .type _vmm_addToQueue, @function -_vmm_addToQueue: - push %ebp - mov %ebp, %esp - push %esi - push %ebx - sub %esp, 16 - mov %esi, DWORD PTR [%ebp+8] - mov %ebx, DWORD PTR [%ebp+8] - mov %eax, DWORD PTR [%ebp+16] - mov DWORD PTR [%esp], %eax - call _vmm_countHeapEntries - add %eax, DWORD PTR _heapEntryQueues[0+%ebx*8] - mov DWORD PTR _heapEntryQueues[0+%esi*8], %eax - mov %eax, DWORD PTR [%ebp+16] - mov DWORD PTR [%esp], %eax - call _vmm_followChain - mov DWORD PTR [%ebp-12], %eax - mov %edx, DWORD PTR [%ebp-12] - mov %eax, DWORD PTR [%ebp+12] - mov %eax, DWORD PTR [%eax+8] - mov DWORD PTR [%edx+8], %eax - mov %edx, DWORD PTR [%ebp+16] - mov %eax, DWORD PTR [%ebp+12] - mov DWORD PTR [%edx+12], %eax - mov %eax, DWORD PTR [%ebp-12] - mov %edx, DWORD PTR [%eax+8] - mov %eax, DWORD PTR [%ebp-12] - mov DWORD PTR [%edx+12], %eax - mov %edx, DWORD PTR [%ebp+12] - mov %eax, DWORD PTR [%ebp+16] - mov DWORD PTR [%edx+8], %eax - add %esp, 16 - pop %ebx - pop %esi - pop %ebp - ret - .size _vmm_addToQueue, .-_vmm_addToQueue -.globl _vmm_countHeapEntries - .type _vmm_countHeapEntries, @function -_vmm_countHeapEntries: - push %ebp - mov %ebp, %esp - sub %esp, 4 - mov DWORD PTR [%ebp-4], 0 -.L109: - cmp DWORD PTR [%ebp+8], 0 - jne .L111 - jmp .L110 -.L111: - lea %eax, [%ebp-4] - inc DWORD PTR [%eax] - mov %eax, DWORD PTR [%ebp+8] - mov %eax, DWORD PTR [%eax+8] - mov DWORD PTR [%ebp+8], %eax - jmp .L109 -.L110: - mov %eax, DWORD PTR [%ebp-4] - leave - ret - .size _vmm_countHeapEntries, .-_vmm_countHeapEntries -.globl _vmm_followChain - .type _vmm_followChain, @function -_vmm_followChain: - push %ebp - mov %ebp, %esp - nop -.L113: - mov %eax, DWORD PTR [%ebp+8] - cmp DWORD PTR [%eax+8], 0 - jne .L115 - jmp .L114 -.L115: - mov %eax, DWORD PTR [%ebp+8] - mov %eax, DWORD PTR [%eax+8] - mov DWORD PTR [%ebp+8], %eax - jmp .L113 -.L114: - mov %eax, DWORD PTR [%ebp+8] - pop %ebp - ret - .size _vmm_followChain, .-_vmm_followChain -.globl _vmm_getUnusedEntry - .type _vmm_getUnusedEntry, @function -_vmm_getUnusedEntry: - push %ebp - mov %ebp, %esp - sub %esp, 40 - cmp DWORD PTR _heapEntryQueues, 4 - jg .L117 - mov %eax, DWORD PTR _heapEntryQueues+28 - mov %eax, DWORD PTR [%eax+8] - mov DWORD PTR [%ebp-4], %eax - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%ebp-8], %eax -.L118: - cmp DWORD PTR [%ebp-4], 0 - jne .L120 - jmp .L119 -.L120: - mov %eax, DWORD PTR [%ebp-4] - mov %edx, DWORD PTR [%ebp-8] - mov %eax, DWORD PTR [%eax+4] - cmp %eax, DWORD PTR [%edx+4] - jbe .L121 - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%ebp-8], %eax -.L121: - mov %eax, DWORD PTR [%ebp-4] - mov %eax, DWORD PTR [%eax+8] - mov DWORD PTR [%ebp-4], %eax - jmp .L118 -.L119: - mov %edx, DWORD PTR [%ebp-8] - mov %eax, DWORD PTR [%ebp-8] - mov %eax, DWORD PTR [%eax+4] - sub %eax, 4096 - mov DWORD PTR [%edx+4], %eax - mov %edx, DWORD PTR [%ebp-8] - mov %eax, DWORD PTR [%ebp-8] - mov %eax, DWORD PTR [%eax+4] - add %eax, DWORD PTR [%edx] - mov DWORD PTR [%ebp-12], %eax - mov %eax, DWORD PTR [%ebp-12] - mov DWORD PTR [%esp], %eax - call _vmm_map - mov %eax, DWORD PTR [%ebp-12] - mov DWORD PTR [%esp], %eax - call _vmm_heb_init - call _vmm_stripUnusedEntry - mov DWORD PTR [%ebp-16], %eax - mov %edx, DWORD PTR [%ebp-16] - mov %eax, DWORD PTR [%ebp-12] - mov DWORD PTR [%edx], %eax - mov %eax, DWORD PTR [%ebp-16] - mov DWORD PTR [%eax+4], 4096 - mov %eax, DWORD PTR [%ebp-16] - mov DWORD PTR [%esp+8], %eax - mov %eax, DWORD PTR _heapEntryTailNodes+44 - mov DWORD PTR [%esp+4], %eax - mov DWORD PTR [%esp], 2 - call _vmm_addToQueue -.L117: - call _vmm_stripUnusedEntry - leave - ret - .size _vmm_getUnusedEntry, .-_vmm_getUnusedEntry -.globl _vmm_stripUnusedEntry - .type _vmm_stripUnusedEntry, @function -_vmm_stripUnusedEntry: - push %ebp - mov %ebp, %esp - sub %esp, 4 - mov %eax, DWORD PTR _heapEntryQueues+4 - mov %eax, DWORD PTR [%eax+8] - mov DWORD PTR [%ebp-4], %eax - mov %edx, DWORD PTR _heapEntryQueues+4 - mov %eax, DWORD PTR [%ebp-4] - mov %eax, DWORD PTR [%eax+8] - mov DWORD PTR [%edx+8], %eax - mov %eax, DWORD PTR [%ebp-4] - mov %edx, DWORD PTR [%eax+8] - mov %eax, DWORD PTR [%ebp-4] - mov %eax, DWORD PTR [%eax+12] - mov DWORD PTR [%edx+12], %eax - dec DWORD PTR _heapEntryQueues - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%eax+8], 0 - mov %eax, DWORD PTR [%ebp-4] - mov DWORD PTR [%eax+12], 0 - mov %eax, DWORD PTR [%ebp-4] - leave - ret - .size _vmm_stripUnusedEntry, .-_vmm_stripUnusedEntry - .comm _heapEntryQueues,32,32 - .comm _heapEntryHeadNodes,64,32 - .comm _heapEntryTailNodes,64,32 - .comm _initialHEB,4096,32 - .section .note.GNU-stack,"",@progbits - .ident "GCC: (GNU) 3.3.5-20050130 (Gentoo 3.3.5.20050130-r1, ssp-3.3.5.20050130-1, pie-8.7.7.1)" diff --git a/menu.lst b/menu.lst deleted file mode 100644 index 04fa1f0..0000000 --- a/menu.lst +++ /dev/null @@ -1,9 +0,0 @@ - -timeout 10 -default 0 - -title HOS 0.16 -root (fd0) -kernel /kernel.bin -module /rmmod.bin -module /hos_initrd.gz diff --git a/rmmod/Makefile b/rmmod/Makefile deleted file mode 100644 index 2a553c2..0000000 --- a/rmmod/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -NASM=nasm - -all: rmmod.bin - -rmmod.bin: rmmod.asm - $(NASM) -f bin rmmod.asm -l rmmod.lst -o rmmod.bin - -clean: - -rm -f *~ *.o *.bin *.lst diff --git a/rmmod/conio.inc b/rmmod/conio.inc deleted file mode 100644 index 90c4add..0000000 --- a/rmmod/conio.inc +++ /dev/null @@ -1,209 +0,0 @@ -; conio.inc -; real mode console input / output functions -; Author: Josh Holtrop -; Date: 01/04/05 -; Modified: 01/04/05 - - -con_getkey: - xor ax, ax - int 0x16 - ret - - -con_move_cursor: ;con_move_cursor(word location) - push bp - mov bp, sp - push ax - - mov ax, [bp + 4] - mov [cursor], ax - call con_write_cursor - - pop ax - pop bp - ret - - -con_clear: - pusha - push es - push ds - - mov ax, 0xB800 - mov es, ax - mov di, 0 - mov ax, 0x0720 - mov cx, 2000 - rep stosw - mov [cursor], word 0 - call con_write_cursor - - pop ds - pop es - popa - ret - - -con_putstring: ;con_putstring(char *str) - push bp - mov bp, sp - pusha - - mov si, [bp + 4] -putstring_loop: - lodsb - or al, al - jz putstring_done - mov ah, 0x07 - ccall con_putc, ax - jmp putstring_loop - -putstring_done: - popa - pop bp - ret - - -con_putHex: ;con_putHex(word hexVal) - push bp - mov bp, sp - pusha - - mov ax, [bp + 4] - mov cx, 12 - mov dl, 0 -con_putHex_loop: - push ax - shr ax, cl - and ax, 0xF - cmp ax, 0 - jnz con_putHex_putc - cmp cx, 0 - jz con_putHex_putc - cmp dl, 0 - jz con_putHex_loop_done -con_putHex_putc: - add ax, '0' - cmp ax, '9' - jbe con_putHex_putc_goon - add ax, 'A'-'9'-1 -con_putHex_putc_goon: - mov ah, 0x07 - ccall con_putc, ax - mov dl, 1 -con_putHex_loop_done: - pop ax - cmp cx, 0 - jz con_putHex_done - sub cx, 4 - jmp con_putHex_loop - -con_putHex_done: - popa - pop bp - ret - - -con_putDec: ;con_putDec(word dec) - push bp - mov bp, sp - pusha - - mov ax, [bp + 4] - mov cx, 10000 - mov di, 0 - -con_putDec_loop: - xor dx, dx - div cx ;remainder in dx, quotient in ax - mov bx, ax - mov ax, dx ;new value is ax % mod - push ax - mov ax, bx - cmp ax, 0 - jnz con_putDec_putc - cmp cx, 1 - jz con_putDec_putc - cmp di, 0 - jz con_putDec_loop_done -con_putDec_putc: - add ax, 0x0730 - ccall con_putc, ax - mov di, 1 - -con_putDec_loop_done: - mov ax, cx - xor dx, dx - mov bx, 10 - div bx - mov cx, ax - pop ax - cmp cx, 0 - jnz con_putDec_loop - - popa - pop bp - ret - - -con_putc: ;con_putc(char chr) - push bp - mov bp, sp - pusha - push es - - mov ax, 0xB800 - mov es, ax - mov di, [cursor] - mov ax, [bp + 4] - cmp al, 10 - jz putc_return - stosw - jmp putc_update -putc_return: - mov ax, di - mov bl, 160 - div bl ; quotient in al, remainder in ah - shr ax, 8 - sub di, ax - add di, 160 -putc_update: - mov [cursor], di - call con_write_cursor - - pop es - popa - pop bp - ret - - -con_write_cursor: - pusha - - mov ax, [cursor] - shr ax, 1 - - mov bl, al - mov dx, 0x03D4 - mov al, 0x0E - out dx, al - - inc dx - mov al, ah - out dx, al - - dec dx - mov al, 0x0F - out dx, al - - inc dx - mov al, bl - out dx, al - - popa - ret - - -cursor: dw 0 - diff --git a/rmmod/rmmod.asm b/rmmod/rmmod.asm deleted file mode 100644 index fef3605..0000000 --- a/rmmod/rmmod.asm +++ /dev/null @@ -1,325 +0,0 @@ -; rmmod.asm -; real mode module for HOS -; Author: Josh Holtrop -; Date: 09/20/04 -; Modified: 11/01/05 - -%define VIRT_OFFSET 0xC0000000 -%define SIZEOF_RMPARAMS 20 -%include "rmmod.inc" - -; the bootstrap process will jump us to 0x0:0x5010 so we'd better be ready for it -[org 0x5000] -[bits 32] - ;HOS module header, better be 16 bytes! - dd 0x4D534F48 ; magic identifier "HOSM" - dd 1 ; real mode module - dd start ; start address - dd 0 ; reserved - -; ebx = return address -; ecx = where to store real mode parameter table -start: - jmp 24:start_pm16 ; uses KERNEL_CODE_BS16 from kernel/boot.asm -[bits 16] -start_pm16: ; in 16-bit protected mode - mov ax, 32 - mov ss, ax - mov eax, cr0 - and eax, 0x7FFFFFFE - mov cr0, eax ; leave PM - - jmp 0:start_refreshed ; enter RM - -%include "conio.inc" -%include "vesa.inc" - -start_refreshed: - mov ax, cs ; 0 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - mov esp, 0x7000 - mov [dat_rmadd], ecx - mov [dat_retn], ebx - - mov ebx, ecx ; clear the rm_params - mov cx, SIZEOF_RMPARAMS - mov ax, 0 -clear_rmparams_loop: - mov [ebx], al - inc ebx - loop clear_rmparams_loop - -; begin real-mode code initialization, etc... - - call con_clear - - ccall vesa_get_info, es, vbe_info_block - cmp ax, 0 - jnzfar no_vesa - -vesa_present: - ccall con_putstring, txt_vesa - xor ax, ax - mov al, [VbeVersion + 1] - ccall con_putHex, ax - ccall con_putc, '.' | 0x0700 - xor ax, ax - mov al, [VbeVersion] - ccall con_putHex, ax - ccall con_putc, 10 - - xor ax, ax ; clear the scratch mem - mov cx, 129 - mov di, scratch_mem - rep stosw - - push ds - mov ax, [OemStringPtr + 2] - mov si, [OemStringPtr] - mov ds, ax - mov di, scratch_mem - mov cx, 128 - rep movsw ; and copy the string there for display - pop ds - - ccall con_putstring, scratch_mem ; write OEM string - ccall con_putc, 10 - mov ax, [VideoModePtr + 2] - mov es, ax - mov si, [VideoModePtr] - xor dx, dx -vesa_mode_loop: - mov ax, [es:si] ; get next mode number - cmp ax, 0xFFFF - jzfar vesa_mode_loop_done - ccall vesa_get_mode_info, ds, vbe_mode_info_block, ax - cmp ax, 0 - jnzfar vesa_mode_loop_next - - mov ax, [ModeAttributes] - and ax, VESA_MODE_SUPPORTED | VESA_MODE_COLOR | VESA_MODE_GRAPHICS | VESA_MODE_LFB - cmp ax, VESA_MODE_SUPPORTED | VESA_MODE_COLOR | VESA_MODE_GRAPHICS | VESA_MODE_LFB - jnzfar vesa_mode_loop_next - mov ax, [XResolution] - cmp ax, 640 - jlfar vesa_mode_loop_next - mov ax, [YResolution] - cmp ax, 480 - jlfar vesa_mode_loop_next - mov al, [BitsPerPixel] - cmp al, 15 - jz vesa_mode_good - cmp al, 16 - jz vesa_mode_good - cmp al, 24 - jz vesa_mode_good - cmp al, 32 - jnzfar vesa_mode_loop_next -vesa_mode_good: - mov ax, dx - add ax, 0x0700 | 'a' - ccall con_putc, ax - ccall con_putstring, txt_vesa_mode1 - ccall con_putDec, word [XResolution] - ccall con_putc, 'x' | 0x0700 - ccall con_putDec, word [YResolution] - ccall con_putc, 'x' | 0x0700 - xor ax, ax - mov al, [BitsPerPixel] - ccall con_putDec, ax - ccall con_putstring, txt_vesa_mode2 - mov ax, [es:si] ; mode number - ccall con_putHex, ax - ccall con_putc, 10 - - mov bx, dx - shl bx, 1 - mov [scratch_mem + bx], ax ; store modes in scratch_mem array - inc dx - -vesa_mode_loop_next: - add si, 2 - jmp vesa_mode_loop - -vesa_mode_loop_done: - ccall con_putstring, txt_vesa_end - -vesa_get_key_loop: - call con_getkey - mov ah, 0 - cmp ax, '0' - jz vesa_the_end - cmp ax, 'a' ; first choice - jb vesa_get_key_loop - add dx, 'a' - cmp ax, dx ; one past last choice - jae vesa_get_key_loop -; ok, we have a valid video mode selection - sub ax, 'a' - shl ax, 1 - mov bx, ax - mov cx, [scratch_mem + bx] - ccall vesa_get_mode_info, ds, vbe_mode_info_block, cx - or cx, 0x4000 ; enable LFB - ccall vesa_set_mode, cx ; turn on mode - - mov ebx, [dat_rmadd] ; pass mode info to kernel - mov eax, [PhysBasePtr] - mov [ebx + 0], eax - xor eax, eax - mov al, [BitsPerPixel] - mov [ebx + 12], eax - mov ax, [XResolution] - mov [ebx + 4], eax - mov ax, [YResolution] - mov [ebx + 8], eax - - jmp vesa_the_end - - - -no_vesa: - ccall con_putstring, txt_novesa - call con_getkey - -vesa_the_end: - -end_rmmod: ; get ready to go back to pmode and return to kernel initialization - mov ebx, [dat_retn] - lgdt [gdtrlin32] - mov eax, cr0 - or eax, 0x01 - mov cr0, eax - jmp KERNEL_CODE_LIN32:segmented_start - -[bits 32] -segmented_start: - lgdt [gdtrbs32] - jmp KERNEL_CODE_BS32:offset_continue+VIRT_OFFSET -offset_continue: - mov cx, KERNEL_DATA_BS32 - mov ss, cx - mov ds, cx - mov es, cx - mov gs, cx - mov fs, cx - jmp ebx - - -[bits 16] - -;------------------------------------------------------- -gdtrlin32: - dw gdt_endlin32-gdtlin32-1 - dd gdtlin32 -gdtlin32: ;null descriptor - dd 0 - dd 0 - -KERNEL_CODE_LIN32 equ $-gdtlin32 - db 0xff ;limit 7:0 - db 0xff ;limit 15:8 - db 0x00 ;base 7:0 - db 0x00 ;base 15:8 - db 0x00 ;base 23:16 - db 0x9a ;access - db 0xcf ;flags / limit 19:16 - db 0x00 ;base 31:24 - -KERNEL_DATA_LIN32 equ $-gdtlin32 - db 0xff ;limit 7:0 - db 0xff ;limit 15:8 - db 0x00 ;base 7:0 - db 0x00 ;base 15:8 - db 0x00 ;base 23:16 - db 0x92 ;access - db 0xcf ;flags / limit 19:16 - db 0x00 ;base 31:24 - -gdt_endlin32: - - -;------------------------------------------------------- -gdtrbs32: - dw gdt_endbs32-gdtbs32-1 - dd gdtbs32 -gdtbs32: ;null descriptor - dd 0 - dd 0 - - ;a base of 0x4000_0000, when added to 0xC000_0000 will produce 0x0000_0000 physical before paging in effect -KERNEL_CODE_BS32 equ $-gdtbs32 - db 0xff ;limit 7:0 - db 0xff ;limit 15:8 - db 0x00 ;base 7:0 - db 0x00 ;base 15:8 - db 0x00 ;base 23:16 - db 0x9a ;access - db 0xcf ;flags / limit 19:16 - db 0x40 ;base 31:24 - -KERNEL_DATA_BS32 equ $-gdtbs32 - db 0xff ;limit 7:0 - db 0xff ;limit 15:8 - db 0x00 ;base 7:0 - db 0x00 ;base 15:8 - db 0x00 ;base 23:16 - db 0x92 ;access - db 0xcf ;flags / limit 19:16 - db 0x40 ;base 31:24 - -gdt_endbs32: - - -txt_vesa: db "VESA found. VBE Version: ", 0 -txt_vesa_mode1 db ". ", 0 -txt_vesa_mode2 db ", mode 0x", 0 -txt_vesa_end: db "Enter the letter of your selection or 0 for console mode:", 0 -txt_novesa: db "VESA not found, using 80x25 console mode... press any key", 10, 0 - -dat_rmadd: dd 0 -dat_retn: dd 0 - -vbe_info_block: -VbeSignature: db "VBE2" -VbeVersion: dw 0 -OemStringPtr dd 0 -Capabilities: times 4 db 0 -VideoModePtr: dd 0 -TotalMemory: dw 0 -OemSoftwareRev: dw 0 -OemVendorName: dd 0 -OemProductName: dd 0 -OemProductRev: dd 0 -Reserved: times 478 db 0 - -vbe_mode_info_block: -ModeAttributes: dw 0 -WinAAttributes: db 0 -WinBAttributes: db 0 -WinGranularity: dw 0 -WinSize: dw 0 -WinASegment: dw 0 -WinBSegment: dw 0 -WinFuncPtr: dd 0 -BytesPerScanline: dw 0 - -XResolution: dw 0 -YResolution: dw 0 -XCharSize: db 0 -YCharSize: db 0 -NumberOfPlanes: db 0 -BitsPerPixel: db 0 -NumberOfBanks: db 0 -MemoryModel: db 0 -BankSize: db 0 -NumberOfImagePages: db 0 -Reserved2: times 10 db 0 -PhysBasePtr: dd 0 -Reserved3: times 212 db 0 - -scratch_mem: diff --git a/rmmod/rmmod.inc b/rmmod/rmmod.inc deleted file mode 100644 index 4d1b605..0000000 --- a/rmmod/rmmod.inc +++ /dev/null @@ -1,53 +0,0 @@ -; rmmod.inc -; Author: Josh Holtrop -; Date: 01/04/05 -; Modified: 11/02/05 - -%macro jzfar 1 - jnz %%skip - jmp %1 -%%skip: -%endmacro - -%macro jnzfar 1 - jz %%skip - jmp %1 -%%skip: -%endmacro - -%macro jlfar 1 - jge %%skip - jmp %1 -%%skip: -%endmacro - -%macro ccall 2 - push %2 - call %1 - add esp, 2 -%endmacro - -%macro ccall 3 - push %3 - push %2 - call %1 - add esp, 4 -%endmacro - -%macro ccall 4 - push %4 - push %3 - push %2 - call %1 - add esp, 6 -%endmacro - -%macro ccall 5 - push %5 - push %4 - push %3 - push %2 - call %1 - add esp, 8 -%endmacro - diff --git a/rmmod/vesa.inc b/rmmod/vesa.inc deleted file mode 100644 index 5c72f3d..0000000 --- a/rmmod/vesa.inc +++ /dev/null @@ -1,85 +0,0 @@ -; vesa.inc -; Author: Josh Holtrop -; Date: 01/04/05 -; Modified: 01/04/05 -; real mode vesa functions - -; sample bochs VBE modes: -;0x000c6a86 : 0x0100 0x0101 0x0102 0x0103 0x0105 0x0110 0x0111 0x0112 -;0x000c6a96 : 0x0113 0x0114 0x0115 0x0116 0x0117 0x0118 0x0142 0x0143 -;0x000c6aa6 : 0x0144 0x0146 0xffff - -%define VESA_MODE_SUPPORTED 0x01 -%define VESA_MODE_COLOR 0x08 -%define VESA_MODE_GRAPHICS 0x10 -%define VESA_MODE_LFB 0x80 - -vesa_return: dw 0 - -vesa_get_info: ;vesa_get_info(word seg, word offset) - push bp - mov bp, sp - pusha - push es - push ds - - mov ax, [bp + 4] - mov es, ax - mov di, [bp + 6] - mov ax, 0x4F00 - int 0x10 - sub ax, 0x004F - mov [vesa_return], ax - - pop ds - pop es - popa - pop bp - mov ax, [vesa_return] - ret - - -vesa_get_mode_info: ;vesa_get_info(word seg, word offset, word mode) - push bp - mov bp, sp - pusha - push es - push ds - - mov ax, [bp + 4] - mov es, ax - mov di, [bp + 6] - mov cx, [bp + 8] - mov ax, 0x4F01 - int 0x10 - sub ax, 0x004F - mov [vesa_return], ax - - pop ds - pop es - popa - pop bp - mov ax, [vesa_return] - ret - - -vesa_set_mode: ;vesa_set_mode(word mode) - push bp - mov bp, sp - pusha - push es - push ds - - mov bx, [bp + 4] - mov ax, 0x4F02 - int 0x10 - sub ax, 0x004F - mov [vesa_return], ax - - pop ds - pop es - popa - pop bp - mov ax, [vesa_return] - ret -