Compare commits
93 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
f51426f73f | ||
|
4b688a3ce0 | ||
|
563758b1bd | ||
|
ae5dc7df6f | ||
|
d41ffbbedc | ||
|
5ac343a2e8 | ||
|
1027b8c346 | ||
|
08491bace9 | ||
|
96ba9fabb1 | ||
|
24485b8143 | ||
|
ca82cc32ac | ||
|
4816102139 | ||
|
0bc304328d | ||
|
dccecb054b | ||
|
0c78e21e14 | ||
|
53407d7b59 | ||
|
cdea1602d5 | ||
|
b6bebfd9b4 | ||
|
1be6e37961 | ||
|
85c5a26631 | ||
|
eb2dd3b1ad | ||
|
6cd78f195f | ||
|
e4701b8d96 | ||
|
76ac4f88a4 | ||
|
f6e71b9891 | ||
|
cf7287d368 | ||
|
44c6bac2af | ||
|
bc7064e92a | ||
|
2c5a5d7093 | ||
|
ddd8c9fd71 | ||
|
d7be0159c9 | ||
|
d352afd079 | ||
|
1105e6e203 | ||
|
339eef5976 | ||
|
6a75fdfc10 | ||
|
2f810cc2ec | ||
|
63289deade | ||
|
e70b1a5213 | ||
|
c21caccb1f | ||
|
fd02ee26e1 | ||
|
ecd74fe35b | ||
|
08af04897c | ||
|
1dd8250048 | ||
|
118021a0f6 | ||
|
bf9c7d74eb | ||
|
cf2d28f5ce | ||
|
594625b0fa | ||
|
df719b4281 | ||
|
0fb590a407 | ||
|
5b9651299e | ||
|
a4d497544e | ||
|
6a69fd06ec | ||
|
6a8c7431ff | ||
|
be17cde305 | ||
|
1aace858da | ||
|
784978b131 | ||
|
54b42c0226 | ||
|
e55f2cdfc4 | ||
|
edb1a6426d | ||
|
f07e34c849 | ||
|
e907902ca0 | ||
|
a8947f8aa3 | ||
|
2bddc1d428 | ||
|
bfb4f3bdd0 | ||
|
db192f6d36 | ||
|
2faa2cc8d6 | ||
|
02c2b25ded | ||
|
39ea3f231b | ||
|
981a01ba9b | ||
|
3eea1b4fd3 | ||
|
be8d6015ff | ||
|
6ea8fe1a27 | ||
|
d4f5a0b244 | ||
|
1548e7327a | ||
|
90e03d4f95 | ||
|
fb807847bf | ||
|
d8f7e731e1 | ||
|
a5ca4348d9 | ||
|
8fe8d78051 | ||
|
1b0da72e5a | ||
|
8493002072 | ||
|
1ba82ac77f | ||
|
13f467ca47 | ||
|
81a56c9fcf | ||
|
788597b6f4 | ||
|
09fb19df15 | ||
|
af529606e9 | ||
|
f58228c559 | ||
|
8f00324b30 | ||
|
bdf4ce8ae8 | ||
|
e124ac5b1b | ||
|
fba9e3ea54 | ||
|
43d1ca0e18 |
43
.bochsrc
43
.bochsrc
@ -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
|
113
Makefile
113
Makefile
@ -1,88 +1,37 @@
|
||||
# Makefile for HOS
|
||||
# Josh Holtrop
|
||||
# Created: 07/09/04
|
||||
|
||||
FLOPPY=/dev/fd0
|
||||
FLOPPY_IMAGE=hos.flp
|
||||
FLOPPY_MOUNT=./mnt_flp
|
||||
GRUB_IMAGE=grub.flp
|
||||
INITRD=hos_initrd
|
||||
INITRD_DIR=initrd
|
||||
INITRD_MOUNT=./mnt_initrd
|
||||
INITRD_SIZE=100 #initrd size in kb
|
||||
MOUNT=sudo mount
|
||||
UMOUNT=sudo umount
|
||||
KERNEL_FILE := hos.gz
|
||||
MKISOFS := genisoimage
|
||||
ISO := hos.iso
|
||||
QEMU := qemu-system-x86_64
|
||||
BOCHS := bochs
|
||||
|
||||
# Do not print "Entering directory ..."
|
||||
MAKEFLAGS += --no-print-directory
|
||||
# default target: build the kernel and ISO image
|
||||
all: kernel iso
|
||||
|
||||
.PHONY: all clean initrd apps grub_image install install_img depend copy_image bochs bochsq
|
||||
# build the kernel
|
||||
.PHONY: kernel
|
||||
kernel:
|
||||
$(MAKE) -C $@
|
||||
|
||||
all:
|
||||
make -C kernel
|
||||
make -C rmmod
|
||||
# build the ISO image
|
||||
.PHONY: iso
|
||||
iso: $(ISO) kernel
|
||||
|
||||
$(ISO): kernel
|
||||
cp kernel/$(KERNEL_FILE) iso/boot
|
||||
-rm -f $(ISO)
|
||||
$(MKISOFS) -R -b boot/grub/stage2_eltorito -no-emul-boot \
|
||||
-boot-load-size 4 -boot-info-table -o $(ISO) iso
|
||||
|
||||
.PHONY: qemu
|
||||
qemu: iso
|
||||
$(QEMU) -cdrom $(ISO) -boot d -m 384 -localtime
|
||||
|
||||
.PHONY: bochs
|
||||
bochs: iso
|
||||
-$(BOCHS)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
-make -C kernel clean
|
||||
-make -C rmmod clean
|
||||
-rm -f *~ *.out hos.flp \#* hos_initrd hos_initrd.gz
|
||||
|
||||
apps:
|
||||
make -C apps
|
||||
|
||||
grub_image:
|
||||
dd if=/dev/zero of=$(GRUB_IMAGE) bs=1024 seek=1440 count=0
|
||||
-mkdir $(FLOPPY_MOUNT)
|
||||
mke2fs -F $(GRUB_IMAGE)
|
||||
$(MOUNT) -t ext2 -o loop $(GRUB_IMAGE) $(FLOPPY_MOUNT)
|
||||
-mkdir -p $(FLOPPY_MOUNT)/boot/grub
|
||||
-cp /boot/grub/stage1 /boot/grub/stage2 /boot/grub/e2fs_stage1_5 $(FLOPPY_MOUNT)/boot/grub
|
||||
$(UMOUNT) $(FLOPPY_MOUNT)
|
||||
-rmdir $(FLOPPY_MOUNT)
|
||||
echo "(fd0) $(GRUB_IMAGE)" > grub_image_device.map.tmp
|
||||
echo "root (fd0)" > grub_commands.tmp
|
||||
echo "setup (fd0)" >> grub_commands.tmp
|
||||
echo "quit" >> grub_commands.tmp
|
||||
grub --device-map grub_image_device.map.tmp < grub_commands.tmp
|
||||
rm grub_commands.tmp
|
||||
rm grub_image_device.map.tmp
|
||||
|
||||
copy_image:
|
||||
cp $(GRUB_IMAGE) $(FLOPPY_IMAGE)
|
||||
|
||||
install: FDEV=$(FLOPPY)
|
||||
install_img: FDEV=$(FLOPPY_IMAGE)
|
||||
install_img: MOUNT_FLAGS=-o loop
|
||||
install_img: copy_image
|
||||
install install_img:
|
||||
-mkdir $(FLOPPY_MOUNT)
|
||||
$(MOUNT) -t ext2 $(MOUNT_FLAGS) $(FDEV) $(FLOPPY_MOUNT)
|
||||
-cp kernel/kernel.bin $(FLOPPY_MOUNT)
|
||||
-cp rmmod/rmmod.bin $(FLOPPY_MOUNT)
|
||||
-cp menu.lst $(FLOPPY_MOUNT)/boot/grub
|
||||
-cp $(INITRD).gz $(FLOPPY_MOUNT)/$(INITRD).gz
|
||||
$(UMOUNT) $(FLOPPY_MOUNT)
|
||||
-rmdir $(FLOPPY_MOUNT)
|
||||
|
||||
initrd:
|
||||
dd if=/dev/zero of=$(INITRD) bs=1024 count=$(INITRD_SIZE)
|
||||
mke2fs -Fv -m0 -r0 -i1024 $(INITRD)
|
||||
-mkdir $(INITRD_MOUNT)
|
||||
$(MOUNT) -t ext2 -o loop $(INITRD) $(INITRD_MOUNT)
|
||||
cp -Pr $(INITRD_DIR)/* $(INITRD_MOUNT)
|
||||
$(UMOUNT) $(INITRD_MOUNT)
|
||||
rm -rf $(INITRD_MOUNT)
|
||||
gzip -c $(INITRD) > $(INITRD).gz
|
||||
|
||||
depend:
|
||||
make -C kernel depend
|
||||
|
||||
bochs:
|
||||
bochs
|
||||
|
||||
bochsq:
|
||||
echo 'c' | bochs -q
|
||||
|
||||
wordcount:
|
||||
find . -regex '\(.*\.[ch]\)\|\(.*\.asm\)\|\(.*\.inc\)\|\(.*\.cpp\)' | xargs cat | wc
|
||||
|
||||
$(MAKE) -C kernel clean
|
||||
-rm -f $(ISO) iso/boot/$(KERNEL_FILE)
|
||||
|
@ -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
|
||||
|
@ -1,3 +0,0 @@
|
||||
all:
|
||||
nasm -f bin hash.asm -o hash
|
||||
|
@ -1 +0,0 @@
|
||||
<EFBFBD>0<EFBFBD>
|
@ -1,6 +0,0 @@
|
||||
|
||||
[bits 32]
|
||||
|
||||
begin:
|
||||
int 0x30
|
||||
ret
|
BIN
apps/test1.app
BIN
apps/test1.app
Binary file not shown.
@ -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
|
@ -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
|
BIN
apps/test2.app
BIN
apps/test2.app
Binary file not shown.
@ -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
|
52
bochsrc
Normal file
52
bochsrc
Normal file
@ -0,0 +1,52 @@
|
||||
# configuration file generated by Bochs
|
||||
plugin_ctrl: unmapped=1, biosdev=1, speaker=1, extfpuirq=1, gameport=1, pci_ide=1, acpi=1, ioapic=1
|
||||
config_interface: textconfig
|
||||
display_library: sdl
|
||||
megs: 32
|
||||
romimage: file="/usr/share/bochs/BIOS-bochs-latest"
|
||||
vgaromimage: file="/usr/share/bochs/VGABIOS-lgpl-latest"
|
||||
boot: cdrom
|
||||
floppy_bootsig_check: disabled=0
|
||||
# no floppya
|
||||
# no floppyb
|
||||
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
|
||||
ata0-master: type=cdrom, path="hos.iso", status=inserted, biosdetect=auto, model="Generic 1234"
|
||||
ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
|
||||
ata2: enabled=0
|
||||
ata3: enabled=0
|
||||
parport1: enabled=1, file=""
|
||||
parport2: enabled=0
|
||||
com1: enabled=1, mode=null, dev=""
|
||||
com2: enabled=0
|
||||
com3: enabled=0
|
||||
com4: enabled=0
|
||||
usb_uhci: enabled=0
|
||||
usb_ohci: enabled=0
|
||||
i440fxsupport: enabled=1
|
||||
vga_update_interval: 50000
|
||||
vga: extension=vbe
|
||||
cpu: count=1, ips=4000000, reset_on_triple_fault=1, cpuid_limit_winnt=0
|
||||
print_timestamps: enabled=0
|
||||
# no gdb stub
|
||||
port_e9_hack: enabled=0
|
||||
text_snapshot_check: enabled=0
|
||||
private_colormap: enabled=0
|
||||
clock: sync=none, time0=local
|
||||
# no cmosimage
|
||||
ne2k: enabled=0
|
||||
pnic: enabled=0
|
||||
sb16: enabled=0
|
||||
# no loader
|
||||
log: -
|
||||
logprefix: %t%e%d
|
||||
panic: action=ask
|
||||
error: action=report
|
||||
info: action=report
|
||||
debug: action=ignore
|
||||
pass: action=fatal
|
||||
keyboard_type: mf
|
||||
keyboard_serial_delay: 250
|
||||
keyboard_paste_delay: 100000
|
||||
keyboard_mapping: enabled=0, map=
|
||||
user_shortcut: keys=none
|
||||
mouse: enabled=0, type=ps2
|
@ -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)
|
BIN
initrd/bin/init
BIN
initrd/bin/init
Binary file not shown.
@ -1 +0,0 @@
|
||||
test_file
|
46
initrd/ulab
46
initrd/ulab
@ -1,46 +0,0 @@
|
||||
# Change this file to contain the machines that you want to use
|
||||
# to run MPI jobs on. The format is one host name per line, with either
|
||||
# hostname
|
||||
# or
|
||||
# hostname:n
|
||||
# where n is the number of processors in an SMP. The hostname should
|
||||
# be the same as the result from the command "hostname"
|
||||
#
|
||||
#non-functional machines
|
||||
#stallman.cs.calvin.edu
|
||||
#zuse.cs.calvin.edu
|
||||
#knuth.cs.calvin.edu
|
||||
|
||||
stroustrup.cs.calvin.edu
|
||||
kernighan.cs.calvin.edu
|
||||
ritchie.cs.calvin.edu
|
||||
aiken.cs.calvin.edu
|
||||
backus-naur.cs.calvin.edu
|
||||
codd.cs.calvin.edu
|
||||
eckert-mauchly.cs.calvin.edu
|
||||
atanasoff.cs.calvin.edu
|
||||
thompson.cs.calvin.edu
|
||||
augusta.cs.calvin.edu
|
||||
babbage.cs.calvin.edu
|
||||
turing.cs.calvin.edu
|
||||
hoare.cs.calvin.edu
|
||||
wall.cs.calvin.edu
|
||||
englebart.cs.calvin.edu
|
||||
vonneuman.cs.calvin.edu
|
||||
hopper.cs.calvin.edu
|
||||
dijkstra.cs.calvin.edu
|
||||
chomsky.cs.calvin.edu
|
||||
leibniz.cs.calvin.edu
|
||||
schreyer.cs.calvin.edu
|
||||
wirth.cs.calvin.edu
|
||||
cray.cs.calvin.edu
|
||||
hillis.cs.calvin.edu
|
||||
taylor.cs.calvin.edu
|
||||
goldberg.cs.calvin.edu
|
||||
kay.cs.calvin.edu
|
||||
boole.cs.calvin.edu
|
||||
church.cs.calvin.edu
|
||||
sutherland.cs.calvin.edu
|
||||
noyce-kilby.cs.calvin.edu
|
||||
hollerith.cs.calvin.edu
|
||||
|
6
iso/boot/grub/menu.lst
Normal file
6
iso/boot/grub/menu.lst
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
timeout 2
|
||||
default 0
|
||||
|
||||
title HOS
|
||||
kernel /boot/hos.gz
|
BIN
iso/boot/grub/stage2_eltorito
Normal file
BIN
iso/boot/grub/stage2_eltorito
Normal file
Binary file not shown.
153
kernel/Makefile
153
kernel/Makefile
@ -1,128 +1,45 @@
|
||||
# Makefile for HOS
|
||||
# Josh Holtrop
|
||||
# Created: 07/08/04
|
||||
# Modified: 06/13/05
|
||||
|
||||
# Assembler Information:
|
||||
NASM=nasm
|
||||
NASM_FLAGS=-f aout
|
||||
CROSS_COMPILE := i586-elf-
|
||||
|
||||
# C/C++ Information:
|
||||
CPPFLAGS=-fleading-underscore -fno-builtin -nostdlib -nostartfiles -nodefaultlibs -I. -Wall
|
||||
# -S -masm=intel
|
||||
CC=gcc
|
||||
CXX=g++
|
||||
CXXFLAGS=-fno-rtti -fno-exceptions -D_HOS_CPP_
|
||||
export LD := $(CROSS_COMPILE)ld
|
||||
export CC := $(CROSS_COMPILE)gcc
|
||||
export CXX := $(CROSS_COMPILE)g++
|
||||
export OBJDUMP := $(CROSS_COMPILE)objdump
|
||||
export NASM := nasm
|
||||
|
||||
# Linker Information:
|
||||
LD=ld
|
||||
LDFLAGS=-nodefaultlibs -nostdlib --no-demangle -T link.ld
|
||||
export HOS_TOPLEVEL := $(shell pwd)
|
||||
LDSCRIPT := link.ld
|
||||
KERNEL := hos
|
||||
export CPPFLAGS := -I$(HOS_TOPLEVEL) -I$(HOS_TOPLEVEL)/include
|
||||
export CFLAGS := -Wall -O2 -g
|
||||
export CXXFLAGS := -Wall -O2 -fno-rtti -fno-exceptions -g
|
||||
export LDFLAGS := -T $(LDSCRIPT) -Map $(KERNEL).map
|
||||
export LDLIBS := `$(CC) -print-libgcc-file-name`
|
||||
|
||||
# Files
|
||||
OBJS=boot.o lang/lang_a.o \
|
||||
kernel.o mm/mm.o mm/vmm.o lang/conv.o display/kout.o \
|
||||
display/display.o sys/pic.o char/keyboard.o lang/lang.o \
|
||||
sys/pci_classes.o syscall.o \
|
||||
proc/proc.o proc/hash.o \
|
||||
lang/string.o lang/new.o char/misc_char.o char/vconsole.o \
|
||||
devices.o block/ramdisk.o fs/vfs.o fs/FileSystem.o fs/VFSMount.o \
|
||||
fs/ext2/ext2.o fs/sysfs/sysfs.o fs/sysfs/sysfs_entry.o \
|
||||
sys/pci.o fs/OpenFile.o fs/OpenDirectory.o \
|
||||
fs/ext2/Ext2OpenDirectory.o fs/ext2/Ext2OpenFile.o \
|
||||
fs/ext2/Ext2BlockCache.o
|
||||
CSRC=kernel.c mm/mm.c mm/vmm.c lang/conv.c display/kout.c \
|
||||
display/display.c sys/pic.c char/keyboard.c lang/lang.c \
|
||||
sys/pci_classes.c syscall.c
|
||||
CXXSRC=lang/string.cpp lang/new.cpp char/misc_char.cpp char/vconsole.cpp \
|
||||
block/ramdisk.cpp devices.cpp fs/vfs.cpp fs/FileSystem.o fs/VFSMount.o\
|
||||
fs/ext2/ext2.cpp fs/sysfs/sysfs.cpp fs/sysfs/sysfs_entry.cpp \
|
||||
sys/pci.cpp proc/proc.cpp proc/hash.cpp fs/OpenFile.cpp \
|
||||
fs/OpenDirectory.cpp fs/ext2/Ext2OpenDirectory.cpp \
|
||||
fs/ext2/Ext2OpenFile.cpp fs/ext2/Ext2BlockCache.cpp
|
||||
SUBDIRS := boot mm lang isr sys
|
||||
SUBDIRS_clean := $(SUBDIRS:%=%.clean)
|
||||
|
||||
.PHONY: all depend clean html
|
||||
.PHONY: all
|
||||
all: $(KERNEL).gz
|
||||
|
||||
all: $(OBJS)
|
||||
$(LD) $(LDFLAGS) -Map kernel.map $(OBJS) -o kernel.bin
|
||||
@echo ' Kernel built: ' `ls -sk kernel.bin | cut -d' ' -f1`kb
|
||||
$(KERNEL).gz: $(KERNEL)
|
||||
gzip -c $< > $@
|
||||
|
||||
depend:
|
||||
makedepend -- $(CPPFLAGS) -- $(CSRC) $(CXXSRC)
|
||||
$(KERNEL): $(KERNEL).o
|
||||
$(LD) $(LDFLAGS) -o $@ $<
|
||||
$(OBJDUMP) --disassemble --source $@ > $@.dump
|
||||
# strip $@
|
||||
|
||||
$(KERNEL).o: $(SUBDIRS)
|
||||
$(LD) -r -o $@ $(foreach subdir,$(SUBDIRS),$(subdir)/$(subdir)_all.o) $(LDLIBS)
|
||||
|
||||
boot.o: boot.asm idt.inc gdt.inc
|
||||
$(NASM) $(NASM_FLAGS) -l boot.lst boot.asm -o boot.o
|
||||
.PHONY: $(SUBDIRS)
|
||||
$(SUBDIRS):
|
||||
$(MAKE) -C $@ SUBDIR=$@
|
||||
|
||||
lang/lang_a.o: lang/lang.asm
|
||||
$(NASM) $(NASM_FLAGS) -l lang.lst lang/lang.asm -o lang/lang_a.o
|
||||
.PHONY: clean
|
||||
clean: $(SUBDIRS_clean)
|
||||
-rm -f *~ $(KERNEL) $(KERNEL).{gz,o,elf,dump,map}
|
||||
|
||||
clean:
|
||||
-rm -f $(OBJS) *.bin *.map *.lst *.out
|
||||
-find . -name '*~' | xargs rm -f
|
||||
|
||||
html:
|
||||
-rm -rf html
|
||||
-mkdir html
|
||||
source-highlight --output-dir=html -f xhtml -n $(CSRC) $(CXXSRC)
|
||||
|
||||
# The following is used by 'make' to automatically
|
||||
# generate dependency information
|
||||
# DO NOT DELETE
|
||||
|
||||
kernel.o: kernel.h hos_defines.h multiboot.h module.h lang/lang.h functions.h
|
||||
kernel.o: sys/io.h mm/mm.h mm/vmm.h lang/conv.h devices.h display/display.h
|
||||
kernel.o: display/kout.h sys/pic.h char/keyboard.h block/ramdisk.h fs/vfs.h
|
||||
kernel.o: fs/ext2/ext2.h sys/pci.h proc/proc.h
|
||||
mm/mm.o: kernel.h hos_defines.h multiboot.h mm/mm.h
|
||||
mm/vmm.o: hos_defines.h kernel.h multiboot.h mm/vmm.h lang/lang.h mm/mm.h
|
||||
lang/conv.o: lang/conv.h hos_defines.h
|
||||
display/kout.o: hos_defines.h display/kout.h lang/conv.h devices.h
|
||||
display/kout.o: char/misc_char.h char/misc_char.h functions.h sys/io.h
|
||||
display/display.o: devices.h hos_defines.h char/vconsole.h display/display.h
|
||||
display/display.o: lang/lang.h kernel.h multiboot.h char/keyboard.h
|
||||
display/display.o: display/kout.h
|
||||
sys/pic.o: hos_defines.h sys/pic.h sys/io.h
|
||||
char/keyboard.o: hos_defines.h char/keyboard.h sys/io.h functions.h
|
||||
char/keyboard.o: lang/conv.h display/kout.h display/display.h devices.h
|
||||
lang/lang.o: lang/lang.h hos_defines.h
|
||||
sys/pci_classes.o: hos_defines.h sys/pci.h
|
||||
lang/string.o: lang/string.h lang/lang.h hos_defines.h
|
||||
lang/new.o: hos_defines.h mm/vmm.h multiboot.h
|
||||
char/misc_char.o: hos_defines.h devices.h char/misc_char.h sys/io.h
|
||||
char/vconsole.o: hos_defines.h mm/vmm.h multiboot.h lang/lang.h
|
||||
char/vconsole.o: display/display.h devices.h functions.h sys/io.h
|
||||
char/vconsole.o: char/vconsole.h
|
||||
block/ramdisk.o: functions.h hos_defines.h sys/io.h mm/vmm.h multiboot.h
|
||||
block/ramdisk.o: lang/lang.h block/ramdisk.h devices.h
|
||||
devices.o: hos_defines.h devices.h char/misc_char.h char/misc_char.h
|
||||
devices.o: char/vconsole.h block/ramdisk.h
|
||||
fs/vfs.o: hos_defines.h display/kout.h functions.h sys/io.h lang/lang.h
|
||||
fs/vfs.o: fs/vfs.h devices.h fs/FileSystem.h fs/OpenDirectory.h lang/string.h
|
||||
fs/vfs.o: fs/OpenFile.h fs/VFSMount.h fs/FileSystem.h fs/ext2/ext2.h fs/vfs.h
|
||||
fs/vfs.o: lang/vector.h
|
||||
fs/ext2/ext2.o: display/kout.h hos_defines.h mm/vmm.h multiboot.h lang/lang.h
|
||||
fs/ext2/ext2.o: fs/ext2/ext2.h fs/vfs.h devices.h fs/ext2/Ext2OpenDirectory.h
|
||||
fs/ext2/ext2.o: fs/ext2/Ext2BlockCache.h fs/ext2/Ext2OpenFile.h fs/OpenFile.h
|
||||
fs/sysfs/sysfs.o: display/kout.h hos_defines.h fs/vfs.h devices.h
|
||||
fs/sysfs/sysfs.o: fs/sysfs/sysfs.h fs/sysfs/sysfs_entry.h lang/vector.h
|
||||
fs/sysfs/sysfs.o: lang/string.h
|
||||
fs/sysfs/sysfs_entry.o: fs/sysfs/sysfs_entry.h lang/vector.h hos_defines.h
|
||||
fs/sysfs/sysfs_entry.o: lang/string.h
|
||||
sys/pci.o: hos_defines.h display/kout.h sys/io.h sys/pci.h lang/vector.h
|
||||
proc/proc.o: hos_defines.h mm/mm.h kernel.h multiboot.h mm/vmm.h lang/lang.h
|
||||
proc/proc.o: functions.h sys/io.h display/kout.h proc/proc.h proc/hash.h
|
||||
proc/proc.o: lang/vector.h
|
||||
proc/hash.o: hos_defines.h proc/hash.h lang/vector.h display/kout.h mm/vmm.h
|
||||
proc/hash.o: multiboot.h
|
||||
fs/OpenFile.o: fs/OpenFile.h hos_defines.h
|
||||
fs/OpenDirectory.o: fs/vfs.h hos_defines.h devices.h fs/OpenDirectory.h
|
||||
fs/OpenDirectory.o: lang/string.h
|
||||
fs/ext2/Ext2OpenDirectory.o: lang/lang.h hos_defines.h fs/vfs.h devices.h
|
||||
fs/ext2/Ext2OpenDirectory.o: fs/ext2/Ext2OpenDirectory.h fs/ext2/ext2.h
|
||||
fs/ext2/Ext2OpenDirectory.o: fs/ext2/Ext2BlockCache.h fs/ext2/Ext2OpenFile.h
|
||||
fs/ext2/Ext2OpenDirectory.o: fs/OpenFile.h
|
||||
fs/ext2/Ext2OpenFile.o: fs/ext2/Ext2OpenFile.h fs/ext2/ext2.h fs/vfs.h
|
||||
fs/ext2/Ext2OpenFile.o: hos_defines.h devices.h fs/OpenFile.h
|
||||
fs/ext2/Ext2OpenFile.o: fs/ext2/Ext2BlockCache.h lang/lang.h functions.h
|
||||
fs/ext2/Ext2OpenFile.o: sys/io.h
|
||||
fs/ext2/Ext2BlockCache.o: fs/vfs.h hos_defines.h devices.h
|
||||
fs/ext2/Ext2BlockCache.o: fs/ext2/Ext2BlockCache.h fs/ext2/ext2.h
|
||||
%.clean:
|
||||
$(MAKE) -C $* clean clean=1
|
||||
|
@ -1,123 +0,0 @@
|
||||
# Makefile for HOS
|
||||
# Josh Holtrop
|
||||
# Created: 07/08/04
|
||||
# Modified: 06/13/05
|
||||
|
||||
# Assembler Information:
|
||||
NASM=nasm
|
||||
NASM_FLAGS=-f aout
|
||||
|
||||
# C/C++ Information:
|
||||
CPPFLAGS=-fleading-underscore -fno-builtin -nostdlib -nostartfiles -nodefaultlibs -I. -Wall
|
||||
# -S -masm=intel
|
||||
CC=gcc
|
||||
CXX=g++
|
||||
CXXFLAGS=-fno-rtti -fno-exceptions -D_HOS_CPP_
|
||||
|
||||
# Linker Information:
|
||||
LD=ld
|
||||
LDFLAGS=-nodefaultlibs -nostdlib --no-demangle -T link.ld
|
||||
|
||||
# Files
|
||||
OBJS=boot.o lang/lang_a.o \
|
||||
kernel.o mm/mm.o mm/vmm.o lang/conv.o display/kout.o \
|
||||
display/display.o sys/pic.o char/keyboard.o lang/lang.o \
|
||||
sys/pci_classes.o syscall.o \
|
||||
proc/proc.o proc/hash.o \
|
||||
lang/string.o lang/new.o char/misc_char.o char/vconsole.o \
|
||||
devices.o block/ramdisk.o fs/vfs.o fs/FileSystem.o fs/VFSMount.o \
|
||||
fs/ext2/ext2.o fs/sysfs/sysfs.o fs/sysfs/sysfs_entry.o \
|
||||
sys/pci.o fs/OpenFile.o fs/OpenDirectory.o \
|
||||
fs/ext2/Ext2OpenDirectory.o fs/ext2/Ext2OpenFile.o \
|
||||
fs/ext2/Ext2BlockCache.o
|
||||
CSRC=kernel.c mm/mm.c mm/vmm.c lang/conv.c display/kout.c \
|
||||
display/display.c sys/pic.c char/keyboard.c lang/lang.c \
|
||||
sys/pci_classes.c syscall.c
|
||||
CXXSRC=lang/string.cpp lang/new.cpp char/misc_char.cpp char/vconsole.cpp \
|
||||
block/ramdisk.cpp devices.cpp fs/vfs.cpp fs/FileSystem.o fs/VFSMount.o\
|
||||
fs/ext2/ext2.cpp fs/sysfs/sysfs.cpp fs/sysfs/sysfs_entry.cpp \
|
||||
sys/pci.cpp proc/proc.cpp proc/hash.cpp fs/OpenFile.cpp \
|
||||
fs/OpenDirectory.cpp fs/ext2/Ext2OpenDirectory.cpp \
|
||||
fs/ext2/Ext2OpenFile.cpp fs/ext2/Ext2BlockCache.cpp
|
||||
|
||||
.PHONY: all depend clean html
|
||||
|
||||
all: $(OBJS)
|
||||
$(LD) $(LDFLAGS) -Map kernel.map $(OBJS) -o kernel.bin
|
||||
@echo ' Kernel built: ' `ls -sk kernel.bin | cut -d' ' -f1`kb
|
||||
|
||||
depend:
|
||||
makedepend -- $(CPPFLAGS) -- $(CSRC) $(CXXSRC)
|
||||
|
||||
boot.o: boot.asm idt.inc gdt.inc
|
||||
$(NASM) $(NASM_FLAGS) -l boot.lst boot.asm -o boot.o
|
||||
|
||||
lang/lang_a.o: lang/lang.asm
|
||||
$(NASM) $(NASM_FLAGS) -l lang.lst lang/lang.asm -o lang/lang_a.o
|
||||
|
||||
clean:
|
||||
-rm -f $(OBJS) *.bin *.map *.lst *.out
|
||||
-find . -name '*~' | xargs rm -f
|
||||
|
||||
html:
|
||||
-rm -rf html
|
||||
-mkdir html
|
||||
source-highlight --output-dir=html -f xhtml -n $(CSRC) $(CXXSRC)
|
||||
|
||||
# The following is used by 'make' to automatically
|
||||
# generate dependency information
|
||||
# DO NOT DELETE
|
||||
|
||||
kernel.o: kernel.h hos_defines.h multiboot.h module.h lang/lang.h functions.h
|
||||
kernel.o: sys/io.h mm/mm.h mm/vmm.h lang/conv.h devices.h display/display.h
|
||||
kernel.o: display/kout.h sys/pic.h char/keyboard.h block/ramdisk.h fs/vfs.h
|
||||
kernel.o: fs/ext2/ext2.h sys/pci.h proc/proc.h
|
||||
mm/mm.o: kernel.h hos_defines.h multiboot.h mm/mm.h
|
||||
mm/vmm.o: hos_defines.h kernel.h multiboot.h mm/vmm.h lang/lang.h mm/mm.h
|
||||
lang/conv.o: lang/conv.h hos_defines.h
|
||||
display/kout.o: hos_defines.h display/kout.h lang/conv.h devices.h
|
||||
display/kout.o: char/misc_char.h char/misc_char.h functions.h sys/io.h
|
||||
display/display.o: devices.h hos_defines.h char/vconsole.h display/display.h
|
||||
display/display.o: lang/lang.h kernel.h multiboot.h char/keyboard.h
|
||||
display/display.o: display/kout.h
|
||||
sys/pic.o: hos_defines.h sys/pic.h sys/io.h
|
||||
char/keyboard.o: hos_defines.h char/keyboard.h sys/io.h functions.h
|
||||
char/keyboard.o: lang/conv.h display/kout.h display/display.h devices.h
|
||||
lang/lang.o: lang/lang.h hos_defines.h
|
||||
sys/pci_classes.o: hos_defines.h sys/pci.h
|
||||
lang/string.o: lang/string.h lang/lang.h hos_defines.h
|
||||
lang/new.o: hos_defines.h mm/vmm.h multiboot.h
|
||||
char/misc_char.o: hos_defines.h devices.h char/misc_char.h sys/io.h
|
||||
char/vconsole.o: hos_defines.h mm/vmm.h multiboot.h lang/lang.h
|
||||
char/vconsole.o: display/display.h devices.h functions.h sys/io.h
|
||||
char/vconsole.o: char/vconsole.h
|
||||
block/ramdisk.o: functions.h hos_defines.h sys/io.h mm/vmm.h multiboot.h
|
||||
block/ramdisk.o: lang/lang.h block/ramdisk.h devices.h
|
||||
devices.o: hos_defines.h devices.h char/misc_char.h char/misc_char.h
|
||||
devices.o: char/vconsole.h block/ramdisk.h
|
||||
fs/vfs.o: hos_defines.h display/kout.h functions.h sys/io.h lang/lang.h
|
||||
fs/vfs.o: fs/vfs.h devices.h fs/FileSystem.h fs/OpenDirectory.h fs/OpenFile.h
|
||||
fs/vfs.o: lang/string.h fs/VFSMount.h fs/FileSystem.h fs/ext2/ext2.h fs/vfs.h
|
||||
fs/vfs.o: lang/vector.h
|
||||
fs/ext2/ext2.o: display/kout.h hos_defines.h mm/vmm.h multiboot.h lang/lang.h
|
||||
fs/ext2/ext2.o: fs/ext2/ext2.h fs/vfs.h devices.h fs/ext2/Ext2OpenDirectory.h
|
||||
fs/ext2/ext2.o: fs/OpenDirectory.h fs/vfs.h fs/OpenFile.h lang/string.h
|
||||
fs/ext2/ext2.o: fs/ext2/Ext2OpenFile.h fs/OpenFile.h
|
||||
fs/sysfs/sysfs.o: display/kout.h hos_defines.h fs/vfs.h devices.h
|
||||
fs/sysfs/sysfs.o: fs/sysfs/sysfs.h fs/sysfs/sysfs_entry.h lang/vector.h
|
||||
fs/sysfs/sysfs.o: lang/string.h
|
||||
fs/sysfs/sysfs_entry.o: fs/sysfs/sysfs_entry.h lang/vector.h hos_defines.h
|
||||
fs/sysfs/sysfs_entry.o: lang/string.h
|
||||
sys/pci.o: hos_defines.h display/kout.h sys/io.h sys/pci.h lang/vector.h
|
||||
proc/proc.o: hos_defines.h mm/mm.h kernel.h multiboot.h mm/vmm.h lang/lang.h
|
||||
proc/proc.o: functions.h sys/io.h display/kout.h proc/proc.h proc/hash.h
|
||||
proc/proc.o: lang/vector.h
|
||||
proc/hash.o: hos_defines.h proc/hash.h lang/vector.h display/kout.h mm/vmm.h
|
||||
proc/hash.o: multiboot.h
|
||||
fs/OpenFile.o: fs/OpenFile.h hos_defines.h
|
||||
fs/OpenDirectory.o: fs/vfs.h hos_defines.h devices.h fs/OpenDirectory.h
|
||||
fs/OpenDirectory.o: fs/OpenFile.h lang/string.h
|
||||
fs/ext2/Ext2OpenDirectory.o: display/kout.h hos_defines.h lang/lang.h
|
||||
fs/ext2/Ext2OpenDirectory.o: fs/vfs.h devices.h fs/ext2/Ext2OpenDirectory.h
|
||||
fs/ext2/Ext2OpenDirectory.o: fs/OpenDirectory.h fs/vfs.h fs/OpenFile.h
|
||||
fs/ext2/Ext2OpenDirectory.o: lang/string.h fs/ext2/ext2.h
|
@ -1,91 +0,0 @@
|
||||
// ramdisk.cpp
|
||||
// Author: Josh Holtrop
|
||||
// Date: 08/20/04
|
||||
// Modified: 05/11/05
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "functions.h"
|
||||
#include "mm/vmm.h"
|
||||
#include "lang/lang.h"
|
||||
}
|
||||
|
||||
#include "block/ramdisk.h"
|
||||
#include "devices.h"
|
||||
|
||||
ramdisk_t *ramdisks[256];
|
||||
|
||||
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] = (ramdisk_t *)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] = (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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
236
kernel/boot.asm
236
kernel/boot.asm
@ -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 multiboot_header-VIRT_OFFSET ;header_addr
|
||||
dd _start-VIRT_OFFSET ;load_addr
|
||||
dd 0 ;load_end_addr
|
||||
dd _end-VIRT_OFFSET ;bss_end_addr
|
||||
dd 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 [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 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"
|
||||
|
2
kernel/boot/Makefile
Normal file
2
kernel/boot/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
include $(HOS_TOPLEVEL)/subdir.mak
|
23
kernel/boot/boot.asm
Normal file
23
kernel/boot/boot.asm
Normal file
@ -0,0 +1,23 @@
|
||||
; boot.asm
|
||||
; Author: Josh Holtrop
|
||||
; Date: 2009-06-25
|
||||
; Adapted from HOS 0.16 source
|
||||
|
||||
%define CONSOLE_MEMORY 0xB8000
|
||||
|
||||
; Symbols from C
|
||||
extern k_bootstrap, bootstrap_stack
|
||||
|
||||
;**************************************************************************
|
||||
;* This is the entry point for the kernel. *
|
||||
;**************************************************************************
|
||||
[global start]
|
||||
start:
|
||||
mov cx, 0x0700 + 'a'
|
||||
mov [CONSOLE_MEMORY+160*8+0*2], cx
|
||||
|
||||
mov esp, bootstrap_stack+4096 ; set up temporary stack space
|
||||
|
||||
push eax ; multiboot bootloader magic value
|
||||
push ebx ; pointer to multiboot info struct
|
||||
call k_bootstrap
|
85
kernel/boot/k_bootstrap.cc
Normal file
85
kernel/boot/k_bootstrap.cc
Normal file
@ -0,0 +1,85 @@
|
||||
|
||||
#include "k_bootstrap.h"
|
||||
#include "k_main.h"
|
||||
#include "hos_types.h"
|
||||
#include "hos_defines.h"
|
||||
#include "multiboot.h"
|
||||
#include "sys/cpu.h"
|
||||
#include "k_early_panic.h"
|
||||
#include "mm/mm.h"
|
||||
#include "mm/stack.h"
|
||||
#include "lang/kio.h"
|
||||
#include "isr/interrupts.h"
|
||||
|
||||
#define DEBUG_LETTER(col,chr) *(u16_t *)(KERNEL_OFFSET + CONSOLE_MEMORY \
|
||||
+ 160 * 8 + (col) * 2) \
|
||||
= 0x0700 | (chr)
|
||||
extern "C" {
|
||||
|
||||
u8_t bootstrap_stack[4096];
|
||||
|
||||
/**************************************************************************
|
||||
* Multiboot header data block *
|
||||
*************************************************************************/
|
||||
u32_t mb_header[] __attribute__ ((section (".multiboot_header") )) = {
|
||||
MB_HEADER_MAGIC, /* magic */
|
||||
MB_HEADER_FLAGS, /* flags */
|
||||
-(MB_HEADER_MAGIC + MB_HEADER_FLAGS) /* checksum */
|
||||
};
|
||||
|
||||
/**************************************************************************
|
||||
* This function is invoked to bootstrap the kernel. *
|
||||
*************************************************************************/
|
||||
void k_bootstrap(mb_info_t * mb_info, u32_t mb_magic)
|
||||
{
|
||||
DEBUG_LETTER(1, 'b');
|
||||
|
||||
if (mb_magic != MB_BOOTLOADER_MAGIC)
|
||||
{
|
||||
k_early_panic("Bad multiboot magic identifier!");
|
||||
}
|
||||
|
||||
if ( ! (mb_info->flags & MB_BOOTLOADER_MMAP) )
|
||||
{
|
||||
k_early_panic("No memory map provided by bootloader!");
|
||||
}
|
||||
|
||||
for (mb_mmap_t * mmap = (mb_mmap_t *) (mb_info->mmap_addr + KERNEL_OFFSET),
|
||||
* end = (mb_mmap_t *) ((u32_t)mmap + mb_info->mmap_length);
|
||||
mmap < end;
|
||||
mmap = (mb_mmap_t *) (((u32_t)mmap) + mmap->size + 4))
|
||||
{
|
||||
// kprintf(" ** size: %d, type: %d ", mmap->size, mmap->type);
|
||||
mm_record_mmap_entry(mmap);
|
||||
}
|
||||
|
||||
DEBUG_LETTER(2, 'c');
|
||||
|
||||
/*
|
||||
* These functions could destroy the multiboot information block and
|
||||
* associated structures, so we must be finished reading those structures
|
||||
* before calling them.
|
||||
*/
|
||||
mm_bootstrap();
|
||||
DEBUG_LETTER(3, 'd');
|
||||
interrupts_bootstrap();
|
||||
DEBUG_LETTER(4, 'e');
|
||||
kio_bootstrap();
|
||||
DEBUG_LETTER(5, 'f');
|
||||
|
||||
/* begin using the permanent stack */
|
||||
write_esp(KERNEL_STACK_TOP);
|
||||
k_main();
|
||||
|
||||
idle_loop();
|
||||
}
|
||||
|
||||
void idle_loop()
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
__asm__ __volatile__ ("hlt");
|
||||
}
|
||||
}
|
||||
|
||||
} /* extern "C" */
|
17
kernel/boot/k_bootstrap.h
Normal file
17
kernel/boot/k_bootstrap.h
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
#ifndef K_BOOTSTRAP_H
|
||||
#define K_BOOTSTRAP_H
|
||||
|
||||
#include "hos_types.h"
|
||||
#include "multiboot.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
void k_bootstrap(mb_info_t * mb_info, u32_t mb_magic)
|
||||
__attribute__ ((noreturn));
|
||||
void idle_loop()
|
||||
__attribute__ ((noreturn));
|
||||
|
||||
}
|
||||
|
||||
#endif
|
18
kernel/boot/k_early_panic.c
Normal file
18
kernel/boot/k_early_panic.c
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
#include "hos_types.h"
|
||||
#include "hos_defines.h"
|
||||
#include "k_early_panic.h"
|
||||
|
||||
void k_early_panic(const char * msg)
|
||||
{
|
||||
char * dest = (char *) (CONSOLE_MEMORY + KERNEL_OFFSET);
|
||||
while (*msg)
|
||||
{
|
||||
*dest++ = *msg++;
|
||||
*dest++ = 0x04; /* red error message */
|
||||
}
|
||||
|
||||
/* infinite loop */
|
||||
for (;;)
|
||||
;
|
||||
}
|
15
kernel/boot/k_early_panic.h
Normal file
15
kernel/boot/k_early_panic.h
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
#ifndef K_EARLY_PANIC_H
|
||||
#define K_EARLY_PANIC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void k_early_panic(const char * msg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
28
kernel/boot/k_main.cc
Normal file
28
kernel/boot/k_main.cc
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
#include "k_main.h"
|
||||
#include "lang/kio.h"
|
||||
#include "mm/mm.h"
|
||||
#include "sys/timer.h"
|
||||
#include "sys/pic.h"
|
||||
#include "isr/interrupts.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
void k_main()
|
||||
{
|
||||
kprintf("Kernel load address: 0x%08x\n", KERNEL_CODE);
|
||||
kprintf("Kernel code size: %d KB (%d bytes)\n",
|
||||
(KERNEL_DATA - KERNEL_CODE) >> 10, KERNEL_DATA - KERNEL_CODE);
|
||||
kprintf("Kernel data size: %d KB (%d bytes)\n",
|
||||
(KERNEL_BSS - KERNEL_DATA) >> 10, KERNEL_BSS - KERNEL_DATA);
|
||||
kprintf("Kernel bss size: %d KB (%d bytes)\n",
|
||||
(KERNEL_END - KERNEL_BSS) >> 10, KERNEL_END - KERNEL_BSS);
|
||||
mm_print_memory_map();
|
||||
timer_init(KERNEL_TIMER_FREQ);
|
||||
pic_remap(0x20, 0x28);
|
||||
pic_mask1(0x0);
|
||||
pic_mask2(0x0);
|
||||
interrupts_enable();
|
||||
}
|
||||
|
||||
} /* extern "C" */
|
11
kernel/boot/k_main.h
Normal file
11
kernel/boot/k_main.h
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
#ifndef K_MAIN_H
|
||||
#define K_MAIN_H
|
||||
|
||||
extern "C" {
|
||||
|
||||
void k_main();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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...
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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; }
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;}
|
@ -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
|
@ -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; }
|
@ -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
|
||||
|
@ -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; }
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
@ -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];
|
||||
}
|
@ -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
|
@ -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 */
|
||||
}
|
||||
|
@ -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
|
@ -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<Ext2OpenFileHandle> *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);
|
||||
lock(&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<Ext2OpenFileHandle>();
|
||||
/* 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 */
|
||||
lock(&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;
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
@ -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<Sysfs_Entry> myEntries;
|
||||
|
||||
public:
|
||||
Sysfs();
|
||||
~Sysfs();
|
||||
u32_t getRootInodeNumber();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
@ -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<Sysfs_Entry> myChildren;
|
||||
|
||||
public:
|
||||
Sysfs_Entry(int type, string name, int id);
|
||||
~Sysfs_Entry();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -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<string> 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<VFSMount *> *mountPoints;
|
||||
vector<FSHandle> *fses;
|
||||
|
||||
u32_t mount_id = 0;
|
||||
|
||||
/* initialize the VFS module */
|
||||
int vfs_init()
|
||||
{
|
||||
mountPoints = new vector<VFSMount *>;
|
||||
fses = new vector<FSHandle>;
|
||||
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<string> 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<string> 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<string> vfs_split_dirs(const string & path)
|
||||
{
|
||||
char *sptr = new char[path.size() + 1];
|
||||
strcpy(sptr, path.data());
|
||||
char *bptr = sptr;
|
||||
char *cptr = sptr;
|
||||
vector<string> 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;
|
||||
}
|
129
kernel/fs/vfs.h
129
kernel/fs/vfs.h
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -1,105 +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"
|
||||
|
||||
extern u32_t _code;
|
||||
extern u32_t _bss;
|
||||
extern u32_t _end;
|
||||
|
||||
//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
|
||||
|
||||
|
@ -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:
|
||||
|
||||
|
||||
|
@ -1,52 +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;
|
||||
|
||||
extern u32_t _end;
|
||||
extern u32_t _bss;
|
||||
extern u32_t start;
|
||||
|
||||
#endif
|
||||
|
117
kernel/idt.inc
117
kernel/idt.inc
@ -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
|
||||
|
47
kernel/include/hos_defines.h
Normal file
47
kernel/include/hos_defines.h
Normal file
@ -0,0 +1,47 @@
|
||||
|
||||
#ifndef HOS_DEFINES_H
|
||||
#define HOS_DEFINES_H
|
||||
|
||||
#include "hos_types.h"
|
||||
|
||||
#define KERNEL_OFFSET 0x00000000
|
||||
|
||||
#define PAGE_LOG_SIZE 12u
|
||||
#define PAGE_SIZE (1 << PAGE_LOG_SIZE)
|
||||
#define PAGE_HIGH_MASK (0xFFFFFFFFu << PAGE_LOG_SIZE)
|
||||
#define PAGE_LOW_MASK (0xFFFFFFFFu >> (32 - PAGE_LOG_SIZE))
|
||||
|
||||
#define CONSOLE_MEMORY 0xB8000
|
||||
|
||||
#define KERNEL_CODE (&_code)
|
||||
#define KERNEL_DATA (&_data)
|
||||
#define KERNEL_BSS (&_bss)
|
||||
#define KERNEL_END (&_end)
|
||||
|
||||
#define KERNEL_PHYSICAL_ADDRESS ((u32_t)(KERNEL_CODE - KERNEL_OFFSET))
|
||||
#define KERNEL_VIRTUAL_ADDRESS ((u32_t)KERNEL_CODE)
|
||||
#define KERNEL_SIZE ((u32_t)(KERNEL_END - KERNEL_CODE))
|
||||
|
||||
#define KERNEL_TIMER_FREQ 1000
|
||||
|
||||
#define BUILD_BUG_ON(condition) \
|
||||
do { \
|
||||
typedef struct { int negative_width_test : ((condition)?-1:1); } \
|
||||
BUILD_BUG_ON_DUMMY_STRUCT; \
|
||||
} \
|
||||
while(0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern u8_t _code;
|
||||
extern u8_t _data;
|
||||
extern u8_t _bss;
|
||||
extern u8_t _end;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
55
kernel/include/hos_types.h
Normal file
55
kernel/include/hos_types.h
Normal file
@ -0,0 +1,55 @@
|
||||
|
||||
#ifndef HOS_TYPES_H
|
||||
#define HOS_TYPES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef unsigned char u8_t;
|
||||
typedef signed char s8_t;
|
||||
typedef unsigned short u16_t;
|
||||
typedef signed short s16_t;
|
||||
typedef unsigned int u32_t;
|
||||
typedef signed int s32_t;
|
||||
typedef unsigned long long u64_t;
|
||||
typedef signed long long s64_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32_t gs;
|
||||
u32_t fs;
|
||||
u32_t es;
|
||||
u32_t ds;
|
||||
|
||||
u32_t edi;
|
||||
u32_t esi;
|
||||
u32_t ebp;
|
||||
u32_t esp_junk; /* the esp value saved by 'pusha' */
|
||||
u32_t ebx;
|
||||
u32_t edx;
|
||||
u32_t ecx;
|
||||
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;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u16_t limit;
|
||||
u32_t base;
|
||||
} __attribute__ ((packed)) gdtr_t;
|
||||
|
||||
typedef gdtr_t idtr_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
154
kernel/include/multiboot.h
Normal file
154
kernel/include/multiboot.h
Normal file
@ -0,0 +1,154 @@
|
||||
|
||||
#ifndef MULTIBOOT_H
|
||||
#define MULTIBOOT_H
|
||||
|
||||
#include "hos_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* The magic number for the Multiboot header. */
|
||||
#define MB_HEADER_MAGIC 0x1BADB002
|
||||
#define MB_HEADER_FLAGS 0x00000003
|
||||
|
||||
#define MB_HEADER_ALIGN_MODULES (1 << 0)
|
||||
#define MB_HEADER_MEM_INFO (1 << 1)
|
||||
#define MB_HEADER_VIDEO_INFO (1 << 2)
|
||||
#define MB_HEADER_KLUDGE_OFFSETS (1 << 16)
|
||||
|
||||
/* The magic number passed by a Multiboot-compliant boot loader. */
|
||||
#define MB_BOOTLOADER_MAGIC 0x2BADB002
|
||||
|
||||
#define MB_BOOTLOADER_MEM_INFO (1 << 0)
|
||||
#define MB_BOOTLOADER_BOOT_DEVICE (1 << 1)
|
||||
#define MB_BOOTLOADER_COMMAND_LINE (1 << 2)
|
||||
#define MB_BOOTLOADER_MODS (1 << 3)
|
||||
#define MB_BOOTLOADER_AOUT (1 << 4)
|
||||
#define MB_BOOTLOADER_ELF (1 << 5)
|
||||
#define MB_BOOTLOADER_MMAP (1 << 6)
|
||||
#define MB_BOOTLOADER_DRIVES (1 << 7)
|
||||
#define MB_BOOTLOADER_CONFIG (1 << 8)
|
||||
#define MB_BOOTLOADER_APM (1 << 9)
|
||||
#define MB_BOOTLOADER_GRAPHICS (1 << 10)
|
||||
|
||||
#define MB_DRIVE_MODE_CHS 0
|
||||
#define MB_DRIVE_MODE_LBA 1
|
||||
|
||||
#define MB_MMAP_TYPE_RAM 1
|
||||
|
||||
/* The Multiboot header. */
|
||||
typedef struct
|
||||
{
|
||||
u32_t magic;
|
||||
u32_t flags;
|
||||
u32_t checksum;
|
||||
u32_t header_addr; // if flags[16]
|
||||
u32_t load_addr; // if flags[16]
|
||||
u32_t load_end_addr; // if flags[16]
|
||||
u32_t bss_end_addr; // if flags[16]
|
||||
u32_t entry_addr; // if flags[16]
|
||||
u32_t mode_type; // if flags[2]
|
||||
u32_t width; // if flags[2]
|
||||
u32_t height; // if flags[2]
|
||||
u32_t depth; // if flags[2]
|
||||
} mb_header_t;
|
||||
|
||||
/* The symbol table for a.out. */
|
||||
typedef struct
|
||||
{
|
||||
u32_t tabsize;
|
||||
u32_t strsize;
|
||||
u32_t addr;
|
||||
u32_t reserved;
|
||||
} mb_aout_symbol_table_t;
|
||||
|
||||
/* The section header table for ELF. */
|
||||
typedef struct
|
||||
{
|
||||
u32_t num;
|
||||
u32_t size;
|
||||
u32_t addr;
|
||||
u32_t shndx;
|
||||
} mb_elf_section_header_table_t;
|
||||
|
||||
/* The Multiboot information. */
|
||||
typedef struct
|
||||
{
|
||||
u32_t flags;
|
||||
u32_t mem_lower; // present if flags[0] is set
|
||||
u32_t mem_upper;
|
||||
u32_t boot_device; // 1
|
||||
u32_t cmdline; // 2
|
||||
u32_t mods_count; // 3
|
||||
u32_t mods_addr; // 3
|
||||
union
|
||||
{
|
||||
mb_aout_symbol_table_t aout_sym; // 4
|
||||
mb_elf_section_header_table_t elf_sec; // 5
|
||||
};
|
||||
u32_t mmap_length; // 6
|
||||
u32_t mmap_addr; // 6
|
||||
u32_t drives_length; // 7
|
||||
u32_t drives_addr; // 7
|
||||
u32_t config_table; // 8
|
||||
u32_t bootloader_name; // 9
|
||||
u32_t apm_table; // 10
|
||||
|
||||
u32_t vbe_control_info; // 11
|
||||
u32_t vbe_mode_info; // 11
|
||||
u16_t vbe_mode; // 11
|
||||
u16_t vbe_interface_seg; // 11
|
||||
u16_t vbe_interface_off; // 11
|
||||
u16_t vbe_interface_len; // 11
|
||||
} mb_info_t;
|
||||
|
||||
/* The module structure. */
|
||||
typedef struct
|
||||
{
|
||||
u32_t mod_start;
|
||||
u32_t mod_end;
|
||||
u32_t string;
|
||||
u32_t reserved;
|
||||
} mb_module_t;
|
||||
|
||||
/* The memory map. Be careful that the offset 0 is base_addr_low, not size. */
|
||||
typedef struct
|
||||
{
|
||||
u32_t size; // offset -4
|
||||
u64_t base; // offset 0
|
||||
u64_t length;
|
||||
u32_t type;
|
||||
} mb_mmap_t;
|
||||
|
||||
/* The drive structure */
|
||||
typedef struct
|
||||
{
|
||||
u32_t size;
|
||||
u8_t drive_number;
|
||||
u8_t drive_mode;
|
||||
u8_t drive_cylinders;
|
||||
u8_t drive_heads;
|
||||
u8_t drive_sectors;
|
||||
u16_t drive_ports[1];
|
||||
} mb_drive_t;
|
||||
|
||||
/* APM table structure */
|
||||
typedef struct
|
||||
{
|
||||
u16_t version;
|
||||
u16_t cseg;
|
||||
u32_t offset;
|
||||
u16_t cseg_16;
|
||||
u16_t dseg;
|
||||
u16_t flags;
|
||||
u16_t cseg_len;
|
||||
u16_t cseg_16_len;
|
||||
u16_t dseg_len;
|
||||
} mb_apm_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
37
kernel/include/portio.h
Normal file
37
kernel/include/portio.h
Normal file
@ -0,0 +1,37 @@
|
||||
|
||||
#ifndef PORTIO_H
|
||||
#define PORTIO_H
|
||||
|
||||
#include "hos_types.h"
|
||||
|
||||
#define outportb(port, val) \
|
||||
__asm__ __volatile__ ("outb %%al, %%dx" : : "a" (val), "d" (port));
|
||||
|
||||
#define outportw(port, val) \
|
||||
__asm__ __volatile__ ("outw %%ax, %%dx" : : "a" (val), "d" (port));
|
||||
|
||||
#define outportd(port, val) \
|
||||
__asm__ __volatile__ ("outl %%eax, %%dx" : : "a" (val), "d" (port));
|
||||
|
||||
static inline u8_t inportb(u16_t port)
|
||||
{
|
||||
u8_t val;
|
||||
__asm__ __volatile__ ("inb %%dx, %%al" : "=a" (val) : "d" (port));
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline u16_t inportw(u16_t port)
|
||||
{
|
||||
u16_t val;
|
||||
__asm__ __volatile__ ("inw %%dx, %%al" : "=a" (val) : "d" (port));
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline u32_t inportd(u16_t port)
|
||||
{
|
||||
u32_t val;
|
||||
__asm__ __volatile__ ("inl %%dx, %%al" : "=a" (val) : "d" (port));
|
||||
return val;
|
||||
}
|
||||
|
||||
#endif
|
2
kernel/isr/Makefile
Normal file
2
kernel/isr/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
include $(HOS_TOPLEVEL)/subdir.mak
|
110
kernel/isr/interrupts.cc
Normal file
110
kernel/isr/interrupts.cc
Normal file
@ -0,0 +1,110 @@
|
||||
|
||||
#include "hos_types.h"
|
||||
#include "interrupts.h"
|
||||
#include "mm/mm.h"
|
||||
#include "lang/kio.h"
|
||||
#include "sys/pic.h"
|
||||
#include "sys/cpu.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
idtr_t idtr;
|
||||
|
||||
void isr(u8_t int_num, int_stack_t * istack)
|
||||
{
|
||||
switch (int_num)
|
||||
{
|
||||
case 0x20: /* timer interrupt */
|
||||
(*(u16_t *)CONSOLE_MEMORY)++;
|
||||
pic_eoi();
|
||||
break;
|
||||
case 0x21:
|
||||
/* TODO: keyboard hook */
|
||||
pic_eoi();
|
||||
break;
|
||||
default:
|
||||
kputs("--------------------------------------------------------------------------------");
|
||||
kprintf("Unhandled Interrupt #%d\n", int_num);
|
||||
kprintf(" ds: 0x%08x es: 0x%08x fs: 0x%08x gs: 0x%08x\n",
|
||||
istack->ds, istack->es, istack->fs, istack->gs);
|
||||
kprintf(" eax: 0x%08x ebx: 0x%08x ecx: 0x%08x edx: 0x%08x\n",
|
||||
istack->eax, istack->ebx, istack->ecx, istack->edx);
|
||||
kprintf(" ebp: 0x%08x esi: 0x%08x edi: 0x%08x eflags: 0x%08x\n",
|
||||
istack->ebp, istack->esi, istack->edi, istack->eflags);
|
||||
kprintf(" cs: 0x%08x eip: 0x%08x ss: 0x%08x esp: 0x%08x\n",
|
||||
istack->cs, istack->eip, istack->ss, istack->esp);
|
||||
kprintf(" cr0: 0x%08x cr2: 0x%08x cr3: 0x%08x\n",
|
||||
read_cr0(), read_cr2(), read_cr3());
|
||||
kprintf(" Error: 0x%08x (%d)\n", istack->error, istack->error);
|
||||
kputs("--------------------------------------------------------------------------------");
|
||||
|
||||
kprintf("Halting!\n");
|
||||
for (;;)
|
||||
;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} /* extern "C" */
|
||||
|
||||
void interrupts_bootstrap()
|
||||
{
|
||||
u32_t idt_phys = mm_page_alloc();
|
||||
u32_t idt_virt = mm_early_vpage_alloc();
|
||||
mm_map(idt_virt, idt_phys, 0, 1);
|
||||
|
||||
u64_t * idt = (u64_t *) idt_virt;
|
||||
idt[0] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_0, 0);
|
||||
idt[1] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_1, 0);
|
||||
idt[2] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_2, 0);
|
||||
idt[3] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_3, 0);
|
||||
idt[4] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_4, 0);
|
||||
idt[5] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_5, 0);
|
||||
idt[6] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_6, 0);
|
||||
idt[7] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_7, 0);
|
||||
idt[8] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_8, 0);
|
||||
idt[9] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_9, 0);
|
||||
idt[10] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_10, 0);
|
||||
idt[11] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_11, 0);
|
||||
idt[12] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_12, 0);
|
||||
idt[13] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_13, 0);
|
||||
idt[14] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_14, 0);
|
||||
idt[15] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_15, 0);
|
||||
idt[16] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_16, 0);
|
||||
idt[17] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_17, 0);
|
||||
idt[18] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_18, 0);
|
||||
idt[19] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_19, 0);
|
||||
idt[20] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_20, 0);
|
||||
idt[21] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_21, 0);
|
||||
idt[22] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_22, 0);
|
||||
idt[23] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_23, 0);
|
||||
idt[24] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_24, 0);
|
||||
idt[25] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_25, 0);
|
||||
idt[26] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_26, 0);
|
||||
idt[27] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_27, 0);
|
||||
idt[28] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_28, 0);
|
||||
idt[29] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_29, 0);
|
||||
idt[30] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_30, 0);
|
||||
idt[31] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_31, 0);
|
||||
idt[32] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_32, 0);
|
||||
idt[33] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_33, 0);
|
||||
idt[34] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_34, 0);
|
||||
idt[35] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_35, 0);
|
||||
idt[36] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_36, 0);
|
||||
idt[37] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_37, 0);
|
||||
idt[38] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_38, 0);
|
||||
idt[39] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_39, 0);
|
||||
idt[40] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_40, 0);
|
||||
idt[41] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_41, 0);
|
||||
idt[42] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_42, 0);
|
||||
idt[43] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_43, 0);
|
||||
idt[44] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_44, 0);
|
||||
idt[45] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_45, 0);
|
||||
idt[46] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_46, 0);
|
||||
idt[47] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_47, 0);
|
||||
idt[48] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_48, 0);
|
||||
idt[49] = MAKE_IDT_DESCRIPTOR(KERNEL_CODE_SEGMENT, isr_49, 0);
|
||||
idtr.base = idt_phys;
|
||||
idtr.limit = 49 * sizeof(idt[0]) - 1;
|
||||
__asm__ __volatile__ ("lidt (idtr)" : : : "memory");
|
||||
}
|
79
kernel/isr/interrupts.h
Normal file
79
kernel/isr/interrupts.h
Normal file
@ -0,0 +1,79 @@
|
||||
|
||||
#ifndef INTERRUPTS_H
|
||||
#define INTERRUPTS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void isr(u8_t int_num, int_stack_t * int_stack);
|
||||
|
||||
extern void isr_0();
|
||||
extern void isr_1();
|
||||
extern void isr_2();
|
||||
extern void isr_3();
|
||||
extern void isr_4();
|
||||
extern void isr_5();
|
||||
extern void isr_6();
|
||||
extern void isr_7();
|
||||
extern void isr_8();
|
||||
extern void isr_9();
|
||||
extern void isr_10();
|
||||
extern void isr_11();
|
||||
extern void isr_12();
|
||||
extern void isr_13();
|
||||
extern void isr_14();
|
||||
extern void isr_15();
|
||||
extern void isr_16();
|
||||
extern void isr_17();
|
||||
extern void isr_18();
|
||||
extern void isr_19();
|
||||
extern void isr_20();
|
||||
extern void isr_21();
|
||||
extern void isr_22();
|
||||
extern void isr_23();
|
||||
extern void isr_24();
|
||||
extern void isr_25();
|
||||
extern void isr_26();
|
||||
extern void isr_27();
|
||||
extern void isr_28();
|
||||
extern void isr_29();
|
||||
extern void isr_30();
|
||||
extern void isr_31();
|
||||
extern void isr_32();
|
||||
extern void isr_33();
|
||||
extern void isr_34();
|
||||
extern void isr_35();
|
||||
extern void isr_36();
|
||||
extern void isr_37();
|
||||
extern void isr_38();
|
||||
extern void isr_39();
|
||||
extern void isr_40();
|
||||
extern void isr_41();
|
||||
extern void isr_42();
|
||||
extern void isr_43();
|
||||
extern void isr_44();
|
||||
extern void isr_45();
|
||||
extern void isr_46();
|
||||
extern void isr_47();
|
||||
extern void isr_48();
|
||||
extern void isr_49();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#define MAKE_IDT_DESCRIPTOR(selector, offset, dpl) \
|
||||
(u64_t) ( ( (((u64_t) offset) & 0xFFFF0000ull) << 32 ) /* offset 31:16 */ \
|
||||
| ( ( (u64_t) 0x1ull) << 47 ) /* present */ \
|
||||
| ( (((u64_t) dpl) & 0x3) << 45 ) /* DPL */ \
|
||||
| ( ( (u64_t) 0xEull) << 40 ) /* TODO: gate? */ \
|
||||
| ( (((u64_t) selector) & 0xFFFFull) << 16 ) /* selector */ \
|
||||
| ( (((u64_t) offset) & 0x0000FFFFull) ) ) /* offset 15:0 */
|
||||
|
||||
void interrupts_bootstrap();
|
||||
|
||||
#define interrupts_enable() __asm__ __volatile__ ("sti");
|
||||
#define interrupts_disable() __asm__ __volatile__ ("cli");
|
||||
|
||||
#endif
|
56
kernel/isr/isr.asm
Normal file
56
kernel/isr/isr.asm
Normal file
@ -0,0 +1,56 @@
|
||||
|
||||
; C ISR routine
|
||||
[extern isr]
|
||||
|
||||
|
||||
; Macro for creating a single ISR label
|
||||
; We need to push a junk value on the stack first
|
||||
; 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.
|
||||
%macro isr_label 1
|
||||
[global isr_%1]
|
||||
isr_%1:
|
||||
%if ( (%1 != 8) && (%1 < 10 || %1 > 14) )
|
||||
push eax ; junk value to take error code stack space
|
||||
%endif
|
||||
pusha ; eax, ecx, edx, ebx, esp, ebp, esi, edi
|
||||
mov al, %1 ; save interrupt number in al
|
||||
%if ($ - isr_common) < 127 ; do a short jump and save 3 bytes if we can
|
||||
jmp short isr_common
|
||||
%else
|
||||
jmp isr_common
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
|
||||
; The common ISR routine
|
||||
isr_common:
|
||||
push ds
|
||||
push es
|
||||
push fs
|
||||
push gs
|
||||
|
||||
push esp ; pointer to interrupt stack
|
||||
push eax ; interrupt number
|
||||
call isr
|
||||
pop eax ; restore stack pointer (this is shorter
|
||||
pop eax ; than "add esp, 8" and "lea esp, [esp+8]")
|
||||
|
||||
pop gs
|
||||
pop fs
|
||||
pop es
|
||||
pop ds
|
||||
popa ; edi, esi, ebp, <null>, ebx, edx, ecx, eax
|
||||
lea esp, [esp+4] ; bypass error code
|
||||
|
||||
iret
|
||||
|
||||
|
||||
; Loop to create all of our ISR entry points
|
||||
%assign i 0
|
||||
%rep 50
|
||||
isr_label i
|
||||
%assign i i+1
|
||||
%endrep
|
||||
|
288
kernel/kernel.c
288
kernel/kernel.c
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
2
kernel/lang/Makefile
Normal file
2
kernel/lang/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
include $(HOS_TOPLEVEL)/subdir.mak
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
317
kernel/lang/kio.cc
Normal file
317
kernel/lang/kio.cc
Normal file
@ -0,0 +1,317 @@
|
||||
|
||||
#include "hos_types.h"
|
||||
#include "hos_defines.h"
|
||||
#include "kio.h"
|
||||
#include "string.h"
|
||||
#include "portio.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdarg.h> /* va_*() */
|
||||
|
||||
static void fmt_d2a(char * buf, int val);
|
||||
static void fmt_u2a(char * buf, unsigned int val);
|
||||
static void fmt_ll2a(char * buf, long long val);
|
||||
static void fmt_ull2a(char * buf, unsigned long long val);
|
||||
static void fmt_x2a(char * buf, unsigned int val);
|
||||
static void fmt_xl2a(char * buf, unsigned long long val);
|
||||
static void fmt_o2a(char * buf, unsigned int val);
|
||||
|
||||
static int cursor_x, cursor_y;
|
||||
|
||||
static void writeCursorPosition(int x, int y)
|
||||
{
|
||||
u16_t pos = 80 * y + x;
|
||||
outportb(0x3D4, 0x0E);
|
||||
outportb(0x3D5, pos >> 8);
|
||||
outportb(0x3D4, 0x0F);
|
||||
outportb(0x3D5, pos);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
void kio_bootstrap()
|
||||
{
|
||||
cursor_x = 0;
|
||||
cursor_y = 9;
|
||||
writeCursorPosition(cursor_x, cursor_y);
|
||||
}
|
||||
|
||||
void kprintf(const char * fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
kvprintf(fmt, args);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void kvprintf(const char * fmt, va_list args)
|
||||
{
|
||||
char tmpbuf[25];
|
||||
for ( ; *fmt; fmt++)
|
||||
{
|
||||
if (*fmt == '%')
|
||||
{
|
||||
fmt++;
|
||||
if (*fmt)
|
||||
{
|
||||
int width = 0;
|
||||
char pad_char = ' ';
|
||||
bool pad_right = false;
|
||||
if (*fmt == '0')
|
||||
{
|
||||
pad_char = '0';
|
||||
fmt++;
|
||||
}
|
||||
else if (*fmt == '-')
|
||||
{
|
||||
pad_right = true;
|
||||
fmt++;
|
||||
}
|
||||
for ( ; '0' <= *fmt && *fmt <= '9'; fmt++)
|
||||
{
|
||||
if (width == 0)
|
||||
{
|
||||
width = *fmt - '0';
|
||||
}
|
||||
else
|
||||
{
|
||||
width *= 10;
|
||||
width += *fmt - '0';
|
||||
}
|
||||
}
|
||||
switch (*fmt)
|
||||
{
|
||||
case 'c':
|
||||
kputc(va_arg(args, int));
|
||||
break;
|
||||
case 'd':
|
||||
fmt_d2a(tmpbuf, va_arg(args, int));
|
||||
kputs_pad(tmpbuf, width, pad_char, pad_right);
|
||||
break;
|
||||
case 'l':
|
||||
fmt_ll2a(tmpbuf, va_arg(args, long long));
|
||||
kputs_pad(tmpbuf, width, pad_char, pad_right);
|
||||
break;
|
||||
case 'L':
|
||||
fmt_ull2a(tmpbuf, va_arg(args, unsigned long long));
|
||||
kputs_pad(tmpbuf, width, pad_char, pad_right);
|
||||
break;
|
||||
case 'o':
|
||||
fmt_o2a(tmpbuf, va_arg(args, unsigned int));
|
||||
kputs_pad(tmpbuf, width, pad_char, pad_right);
|
||||
break;
|
||||
case 's':
|
||||
kputs_pad(va_arg(args, char *),
|
||||
width, pad_char, pad_right);
|
||||
break;
|
||||
case 'u':
|
||||
fmt_u2a(tmpbuf, va_arg(args, unsigned int));
|
||||
kputs_pad(tmpbuf, width, pad_char, pad_right);
|
||||
break;
|
||||
case 'x':
|
||||
fmt_x2a(tmpbuf, va_arg(args, unsigned int));
|
||||
kputs_pad(tmpbuf, width, pad_char, pad_right);
|
||||
break;
|
||||
case 'X':
|
||||
fmt_xl2a(tmpbuf, va_arg(args, unsigned long long));
|
||||
kputs_pad(tmpbuf, width, pad_char, pad_right);
|
||||
break;
|
||||
case '%':
|
||||
kputc('%');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
kputc(*fmt);
|
||||
}
|
||||
if (!*fmt)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void kputc(char c)
|
||||
{
|
||||
u16_t * console_memory = (u16_t *) CONSOLE_MEMORY;
|
||||
console_memory += 80 * cursor_y + cursor_x;
|
||||
switch (c)
|
||||
{
|
||||
case '\t':
|
||||
{
|
||||
int to_advance = 8 - (cursor_x & 0x3);
|
||||
while (to_advance--)
|
||||
{
|
||||
*console_memory++ = 0x0720;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '\n':
|
||||
cursor_x = 0;
|
||||
cursor_y++;
|
||||
break;
|
||||
default:
|
||||
*console_memory = 0x0700 | (c & 0xFF);
|
||||
cursor_x++;
|
||||
break;
|
||||
}
|
||||
if (cursor_x >= 80)
|
||||
{
|
||||
cursor_x = 0;
|
||||
cursor_y++;
|
||||
}
|
||||
if (cursor_y >= 25)
|
||||
{
|
||||
memcpy((u8_t *) CONSOLE_MEMORY,
|
||||
(u8_t *) (CONSOLE_MEMORY + 80 * 2),
|
||||
2 * 80 * 24);
|
||||
memsetw((u16_t *) (CONSOLE_MEMORY + 2 * 80 * 24), 0x0720, 80);
|
||||
cursor_y = 24;
|
||||
}
|
||||
writeCursorPosition(cursor_x, cursor_y);
|
||||
}
|
||||
|
||||
void kputs(const char * s)
|
||||
{
|
||||
while (*s)
|
||||
{
|
||||
kputc(*s);
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
void kputs_pad(const char * s, int width, char pad_char, bool pad_right)
|
||||
{
|
||||
int len = strlen(s);
|
||||
if (pad_right)
|
||||
{
|
||||
kputs(s);
|
||||
}
|
||||
int num_pad_chars = width - len;
|
||||
for (int i = 0; i < num_pad_chars; i++)
|
||||
{
|
||||
kputc(pad_char);
|
||||
}
|
||||
if (!pad_right)
|
||||
{
|
||||
kputs(s);
|
||||
}
|
||||
}
|
||||
|
||||
} /* extern "C" */
|
||||
|
||||
static void fmt_d2a(char * buf, int val)
|
||||
{
|
||||
if (val < 0)
|
||||
{
|
||||
*buf++ = '-';
|
||||
val = -val;
|
||||
}
|
||||
fmt_u2a(buf, (unsigned int) val);
|
||||
}
|
||||
|
||||
static void fmt_u2a(char * buf, unsigned int val)
|
||||
{
|
||||
bool printing = false;
|
||||
for (unsigned int div = 1000000000; div >= 1; div /= 10)
|
||||
{
|
||||
unsigned int n = val / div;
|
||||
if (n || div == 1)
|
||||
{
|
||||
printing = true;
|
||||
}
|
||||
if (printing)
|
||||
{
|
||||
*buf++ = '0' + n;
|
||||
}
|
||||
val -= n * div;
|
||||
}
|
||||
*buf = '\0';
|
||||
}
|
||||
|
||||
static void fmt_ll2a(char * buf, long long val)
|
||||
{
|
||||
if (val < 0)
|
||||
{
|
||||
*buf++ = '-';
|
||||
val = -val;
|
||||
}
|
||||
fmt_ull2a(buf, (unsigned long long) val);
|
||||
}
|
||||
|
||||
static void fmt_ull2a(char * buf, unsigned long long val)
|
||||
{
|
||||
bool printing = false;
|
||||
for (unsigned long long div = 10000000000000000000ull; div >= 1; div /= 10)
|
||||
{
|
||||
unsigned long long n = val / div;
|
||||
if (n || div == 1)
|
||||
{
|
||||
printing = true;
|
||||
}
|
||||
if (printing)
|
||||
{
|
||||
*buf++ = '0' + n;
|
||||
}
|
||||
val -= n * div;
|
||||
}
|
||||
*buf = '\0';
|
||||
}
|
||||
|
||||
static void fmt_x2a(char * buf, unsigned int val)
|
||||
{
|
||||
bool printing = false;
|
||||
for (int s = 28; s >= 0; s -= 4)
|
||||
{
|
||||
unsigned int n = (val >> s) & 0xF;
|
||||
if (n || s == 0)
|
||||
{
|
||||
printing = true;
|
||||
}
|
||||
if (printing)
|
||||
{
|
||||
*buf++ = "0123456789abcdef"[n];
|
||||
}
|
||||
}
|
||||
*buf = '\0';
|
||||
}
|
||||
|
||||
static void fmt_xl2a(char * buf, unsigned long long val)
|
||||
{
|
||||
bool printing = false;
|
||||
for (int s = 60; s >= 0; s -= 4)
|
||||
{
|
||||
unsigned int n = (val >> s) & 0xF;
|
||||
if (n || s == 0)
|
||||
{
|
||||
printing = true;
|
||||
}
|
||||
if (printing)
|
||||
{
|
||||
*buf++ = "0123456789abcdef"[n];
|
||||
}
|
||||
}
|
||||
*buf = '\0';
|
||||
}
|
||||
|
||||
static void fmt_o2a(char * buf, unsigned int val)
|
||||
{
|
||||
bool printing = false;
|
||||
for (int s = 30; s >= 0; s -= 3)
|
||||
{
|
||||
unsigned int n = (val >> s) & 0x7;
|
||||
if (n || s == 0)
|
||||
{
|
||||
printing = true;
|
||||
}
|
||||
if (printing)
|
||||
{
|
||||
*buf++ = "01234567"[n];
|
||||
}
|
||||
}
|
||||
*buf = '\0';
|
||||
}
|
27
kernel/lang/kio.h
Normal file
27
kernel/lang/kio.h
Normal file
@ -0,0 +1,27 @@
|
||||
|
||||
#ifndef KIO_H
|
||||
#define KIO_H
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void kio_bootstrap();
|
||||
|
||||
void kprintf(const char * fmt, ...);
|
||||
|
||||
void kvprintf(const char * fmt, va_list args);
|
||||
|
||||
void kputc(char c);
|
||||
|
||||
void kputs(const char * s);
|
||||
|
||||
void kputs_pad(const char * s, int width, char pad_char, bool pad_right);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
@ -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 _lock]
|
||||
_lock:
|
||||
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
|
||||
|
@ -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);
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user