Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f5e3507ba | ||
|
|
a9a6f6f4d4 | ||
|
|
2d009273a1 | ||
|
|
2b936758ff | ||
|
|
509009d134 | ||
|
|
0aaf5db5ad | ||
|
|
89d962e33a | ||
|
|
712337c485 | ||
|
|
761e3f0483 | ||
|
|
98abfc2af0 | ||
|
|
677551fba5 | ||
|
|
7daa1c5336 | ||
|
|
79ca453f66 | ||
|
|
0521733e20 | ||
|
|
396c5f3452 | ||
|
|
9e03bfc8b6 | ||
|
|
2b67ff6f49 | ||
|
|
daa29212d0 | ||
|
|
83a5b032f8 | ||
|
|
345ef6c9f3 | ||
|
|
e1682a2fe7 | ||
|
|
2cefd9441c | ||
|
|
da90bcc164 | ||
|
|
4689c11cc8 | ||
|
|
692cf2fc08 | ||
|
|
b0132c866e | ||
|
|
14792ef954 | ||
|
|
bb8ff09e3f | ||
|
|
dfeabc39aa | ||
|
|
14148e4d80 | ||
|
|
80774c48fe | ||
|
|
862b36b37b | ||
|
|
4638656aaf | ||
|
|
3381041a8f | ||
|
|
f09ed66826 | ||
|
|
ba5906c7a3 | ||
|
|
05183a3949 | ||
|
|
d8580a9393 | ||
|
|
50285aa33b | ||
|
|
ee63a84c0e | ||
|
|
76a243d894 | ||
|
|
6bad3f2b96 | ||
|
|
51948ce081 | ||
|
|
b40a68f581 | ||
|
|
55b7429d4e | ||
|
|
7b805f2495 | ||
|
|
2445034e43 | ||
|
|
3c531f3b7b | ||
|
|
11cc0c87f3 | ||
|
|
bad7f79ed1 | ||
|
|
78272f6bc3 | ||
|
|
396d5015d2 | ||
|
|
1bf14ddefa | ||
|
|
c0dd3b529e | ||
|
|
8a8f56decb | ||
|
|
b9c77827bd | ||
|
|
cd02211b21 | ||
|
|
a50c2a1233 | ||
|
|
07e8a0f4cf | ||
|
|
6d23c76e84 | ||
|
|
11da8cb162 | ||
|
|
1063a68a21 | ||
|
|
286b5e9ae1 | ||
|
|
d4aadbea38 | ||
|
|
dfb71cc759 | ||
|
|
872d562d6a | ||
|
|
0729754659 | ||
|
|
f3fe4ef3b8 | ||
|
|
c76725eac3 | ||
|
|
9a8d2c29cb | ||
|
|
b54b8191c4 | ||
|
|
fdf6b71a91 | ||
|
|
802a07ebfe | ||
|
|
b5ba5b63fe | ||
|
|
b4aca026d4 | ||
|
|
6d941b7b16 | ||
|
|
a982312d2c | ||
|
|
6b6e19effd | ||
|
|
38f009f2ca | ||
|
|
6236c341dd | ||
|
|
7110307896 | ||
|
|
ab576bf18f | ||
|
|
302538b8ff | ||
|
|
7f886e44e1 | ||
|
|
8d0e6de040 | ||
|
|
0b9d7fde22 | ||
|
|
48f4046e79 | ||
|
|
2cd08dee70 | ||
|
|
311b8afc83 | ||
|
|
21e3943b5e | ||
|
|
10fd7102ca | ||
|
|
7de4f94423 | ||
|
|
0a546f1467 | ||
|
|
af6087ecec | ||
|
|
c613002307 | ||
|
|
76398df125 | ||
|
|
e83408ce83 | ||
|
|
715bb9341a | ||
|
|
e82bf2ecdf | ||
|
|
528527a7ed | ||
|
|
71aaa7a598 | ||
|
|
9070a76b18 | ||
|
|
5048a93ff7 | ||
|
|
282b856e24 | ||
|
|
3bb1e5fffc | ||
|
|
5ccfd0fc74 | ||
|
|
70d6bb1eb3 | ||
|
|
294b4b0e27 | ||
|
|
57980293e6 | ||
|
|
ba97e8a7f0 | ||
|
|
36b025ccb4 | ||
|
|
aab5ff3c90 | ||
|
|
8bf6e65a95 |
No files matched your search
@@ -0,0 +1,43 @@
|
|||||||
|
# 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
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/hos.flp
|
||||||
|
/hos_initrd
|
||||||
|
/hos_initrd.gz
|
||||||
|
*.lst
|
||||||
|
*.map
|
||||||
|
*.bin
|
||||||
-94
@@ -1,94 +0,0 @@
|
|||||||
//Functions.c
|
|
||||||
//05/07/03 Josh Holtrop
|
|
||||||
//for HOS
|
|
||||||
|
|
||||||
|
|
||||||
inline void outportb(unsigned int port, unsigned char value) // Output a byte to a port
|
|
||||||
{
|
|
||||||
asm volatile ("outb %%al,%%dx"::"d" (port), "a" (value));
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void outportw(unsigned int port, unsigned int value) // Output a word to a port
|
|
||||||
{
|
|
||||||
asm volatile ("outw %%ax,%%dx"::"d" (port), "a" (value));
|
|
||||||
};
|
|
||||||
|
|
||||||
inline byte inportb(unsigned short port)
|
|
||||||
{
|
|
||||||
unsigned char ret_val;
|
|
||||||
|
|
||||||
asm volatile("inb %w1,%b0"
|
|
||||||
: "=a"(ret_val)
|
|
||||||
: "d"(port));
|
|
||||||
return ret_val;
|
|
||||||
};
|
|
||||||
|
|
||||||
void enable_ints()
|
|
||||||
{
|
|
||||||
asm("sti");
|
|
||||||
};
|
|
||||||
|
|
||||||
void disable_ints()
|
|
||||||
{
|
|
||||||
asm("cli");
|
|
||||||
};
|
|
||||||
|
|
||||||
void remap_pics(int pic1, int pic2)
|
|
||||||
{
|
|
||||||
byte a1, a2;
|
|
||||||
|
|
||||||
a1 = inportb(PIC1_DATA); //0x21
|
|
||||||
a2 = inportb(PIC2_DATA); //0xA1
|
|
||||||
|
|
||||||
outportb(PIC1_COMMAND, ICW1_INIT+ICW1_ICW4); //0x20, 0x10+0x01 00010001b
|
|
||||||
outportb(PIC2_COMMAND, ICW1_INIT+ICW1_ICW4); //0xA0, 0x10+0x01 00010001b
|
|
||||||
outportb(PIC1_DATA, pic1); //0x21, pic1
|
|
||||||
outportb(PIC2_DATA, pic2); //0xA1, pic2
|
|
||||||
outportb(PIC1_DATA, 4); //0x21, 0x04 00000100b
|
|
||||||
outportb(PIC2_DATA, 2); //0xA1, 0x02 00000010b
|
|
||||||
outportb(PIC1_DATA, ICW4_8086); //0x21, 0x01 00000001b
|
|
||||||
outportb(PIC2_DATA, ICW4_8086); //0xA1, 0x01 00000001b
|
|
||||||
|
|
||||||
outportb(PIC1_DATA, a1); //0x21
|
|
||||||
outportb(PIC2_DATA, a2); //0xA1
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void pic1_mask(byte mask)
|
|
||||||
{
|
|
||||||
outportb(PIC1_DATA, mask); //0x21, maskfield *OCW1*
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void pic2_mask(byte mask)
|
|
||||||
{
|
|
||||||
outportb(PIC2_DATA, mask); //0xA1, maskfield *OCW1*
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void restart()
|
|
||||||
{
|
|
||||||
outportb (0x64, 0xfe);
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void eoi()
|
|
||||||
{
|
|
||||||
outportb(0x20, 0x20); //EOI
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void eoi2()
|
|
||||||
{
|
|
||||||
outportb(0xA0, 0x20);
|
|
||||||
outportb(0x20, 0x20);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
# Do not print "Entering directory ..."
|
||||||
|
MAKEFLAGS += --no-print-directory
|
||||||
|
|
||||||
|
.PHONY: all clean initrd apps grub_image install install_img depend copy_image bochs bochsq
|
||||||
|
|
||||||
|
all:
|
||||||
|
${MAKE} -C kernel
|
||||||
|
${MAKE} -C rmmod
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
all:
|
||||||
|
make -C hash
|
||||||
|
nasm -f bin -l test1.lst test1.asm -o test1.app
|
||||||
|
nasm -f bin test2.asm -o test2.app
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
all:
|
||||||
|
nasm -f bin hash.asm -o hash
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
�0�
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
[bits 32]
|
||||||
|
|
||||||
|
begin:
|
||||||
|
int 0x30
|
||||||
|
ret
|
||||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
|||||||
|
; 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
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
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
|
||||||
Binary file not shown.
@@ -0,0 +1,17 @@
|
|||||||
|
; 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
|
||||||
-26
@@ -1,26 +0,0 @@
|
|||||||
|
|
||||||
%define VERSION "0.1.2" ;HOS version
|
|
||||||
|
|
||||||
%define BOOT_FAT_SEG 0x07E0 ;right after boot sector
|
|
||||||
%define BOOT_ROOT_SEG 0x0900 ;right after FAT
|
|
||||||
%define BOOT_KERNEL_SEG 0x0AC0 ;right after ROOT_DIR
|
|
||||||
%define BOOT_STAGE2_SEG 0x0B00 ;right after KERNEL_SEG
|
|
||||||
%define BOOT_STAGE2_ADD 0xB000 ;address of stage2 to jump to, org at
|
|
||||||
%define BOOT_KERNEL_ADD 0x100000 ;final pmode kernel destination - physical
|
|
||||||
%define BOOT_RD_ADD 0x200000 ;2mb for ram disk
|
|
||||||
|
|
||||||
%define BOOT_DATA_SEG 0x9000 ;data gathered by stage2 loader goes here
|
|
||||||
|
|
||||||
%define BOOT_HASRD 0x0000 ;1
|
|
||||||
%define BOOT_VESA 0x0002 ;2 - 0 for console, otherwise VESA mode
|
|
||||||
%define BOOT_VESA_OEM 0x0004 ;258 - null-terminated OEM identification string
|
|
||||||
%define BOOT_VESA_VBE 0x0106 ;512 - copy of VESA VBEInfoBlock
|
|
||||||
%define BOOT_VESA_INFO 0x0306 ;256 - copy of VESA ModeInfoBlock for selected mode
|
|
||||||
%define BOOT_MEMENTRIES 0x040A ;4 - dword = number of memmap entries
|
|
||||||
%define BOOT_MEMMAP 0x2000 ;? - memory map information
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
%define BOOT_DRIVE 0x7C24 ;1 - boot drive
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
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)
|
||||||
-24
@@ -1,24 +0,0 @@
|
|||||||
//functions.h
|
|
||||||
//05/07/03 Josh Holtrop
|
|
||||||
//for HOS
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
inline void outportb(unsigned int port, unsigned char value);
|
|
||||||
inline void outportw(unsigned int port, unsigned int value);
|
|
||||||
inline byte inportb(unsigned short port);
|
|
||||||
void enable_ints();
|
|
||||||
void disable_ints();
|
|
||||||
inline void restart();
|
|
||||||
void remap_pics(int pic1, int pic2);
|
|
||||||
inline void pic1_mask(byte mask);
|
|
||||||
inline void pic2_mask(byte mask);
|
|
||||||
inline void eoi();
|
|
||||||
inline void eoi2();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
gdtr:
|
|
||||||
dw gdt_end-gdt-1
|
|
||||||
dd GDT
|
|
||||||
gdt:
|
|
||||||
dd 0
|
|
||||||
dd 0
|
|
||||||
KERNEL_CODE equ $-gdt
|
|
||||||
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
|
|
||||||
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
|
|
||||||
VESA_CODE equ $-gdt
|
|
||||||
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 0x40 ;flags ([G][D/B][0][0]) / limit 19:16
|
|
||||||
db 0x00 ;base 31:24
|
|
||||||
VESA_DATA equ $-gdt
|
|
||||||
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 0x40 ;flags ([G][D/B][0][0]) / limit 19:16
|
|
||||||
db 0x00 ;base 31:24
|
|
||||||
VIDEO_TEXT equ $-gdt
|
|
||||||
dw 0x7FFF ;limit 15:0
|
|
||||||
dw 0x8000 ;base 15:0
|
|
||||||
db 0x0B ;base 23:16
|
|
||||||
db 0x92 ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A])
|
|
||||||
db 0x40 ;flags ([G][D/B][0][0]) / limit 19:16
|
|
||||||
db 0x00 ;base 31:24
|
|
||||||
VIDEO_GRAPHICS equ $-gdt
|
|
||||||
dw 0xFFFF ;limit 15:0
|
|
||||||
dw 0x0000 ;base 15:0
|
|
||||||
db 0x0A ;base 23:16
|
|
||||||
db 0x92 ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A])
|
|
||||||
db 0x40 ;flags ([G][D/B][0][0]) / limit 19:16
|
|
||||||
db 0x00 ;base 31:24
|
|
||||||
USER_CODE equ $-gdt
|
|
||||||
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
|
|
||||||
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
|
|
||||||
gdt_end:
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
|
|
||||||
idtr:
|
|
||||||
dw 50*8-1 ;size of idt
|
|
||||||
dd IDT ;address of idt
|
|
||||||
|
|
||||||
|
|
||||||
%macro isr_label 1
|
|
||||||
isr_%1:
|
|
||||||
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:
|
|
||||||
pusha
|
|
||||||
push ds
|
|
||||||
push es
|
|
||||||
|
|
||||||
push eax
|
|
||||||
|
|
||||||
call _isr
|
|
||||||
|
|
||||||
pop eax
|
|
||||||
|
|
||||||
pop es
|
|
||||||
pop ds
|
|
||||||
popa
|
|
||||||
|
|
||||||
iret
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Binary file not shown.
Symlink
+1
@@ -0,0 +1 @@
|
|||||||
|
test_file
|
||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
-47
@@ -1,47 +0,0 @@
|
|||||||
//k_defines.h
|
|
||||||
//03/17/03 Josh Holtrop
|
|
||||||
|
|
||||||
#define PIC1 0x20
|
|
||||||
#define PIC2 0xA0
|
|
||||||
#define PIC1_COMMAND PIC1
|
|
||||||
#define PIC1_DATA (PIC1+1)
|
|
||||||
#define PIC2_COMMAND PIC2
|
|
||||||
#define PIC2_DATA (PIC2+1)
|
|
||||||
#define PIC_EOI 0x20
|
|
||||||
|
|
||||||
#define ICW1_ICW4 0x01 /* ICW4 (not) needed */
|
|
||||||
#define ICW1_SINGLE 0x02 /* Single (cascade) mode */
|
|
||||||
#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */
|
|
||||||
#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */
|
|
||||||
#define ICW1_INIT 0x10 /* Initialization - required! */
|
|
||||||
|
|
||||||
#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */
|
|
||||||
#define ICW4_AUTO 0x02 /* Auto (normal) EOI */
|
|
||||||
#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */
|
|
||||||
#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */
|
|
||||||
#define ICW4_SFNM 0x10 /* Special fully nested (not) */
|
|
||||||
|
|
||||||
#define BLUE_TXT 0x01
|
|
||||||
#define RED_TXT 0x04
|
|
||||||
#define WHITE_TXT 0x07
|
|
||||||
#define CYAN_TXT 0x0B
|
|
||||||
#define YELLOW_TXT 0x0E
|
|
||||||
#define BRWHITE_TXT 0x0F
|
|
||||||
|
|
||||||
#define FREERAM_START 0x268000
|
|
||||||
|
|
||||||
#define KERNEL_PID 0x02
|
|
||||||
|
|
||||||
typedef unsigned char byte;
|
|
||||||
typedef unsigned short word;
|
|
||||||
typedef unsigned int dword;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
dword lowdword;
|
|
||||||
dword highdword;
|
|
||||||
} __attribute__((packed)) qword;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-62
@@ -1,62 +0,0 @@
|
|||||||
|
|
||||||
%include "bootdef.inc"
|
|
||||||
|
|
||||||
%define GDT 0x140000
|
|
||||||
%define IDT 0x150000
|
|
||||||
|
|
||||||
[global start]
|
|
||||||
[extern _isr]
|
|
||||||
[extern _k_init]
|
|
||||||
|
|
||||||
bits 32
|
|
||||||
|
|
||||||
start:
|
|
||||||
cli ;if they weren't already off
|
|
||||||
mov edi, GDT
|
|
||||||
mov esi, gdt
|
|
||||||
mov ecx, gdt_end-gdt
|
|
||||||
copy_gdt:
|
|
||||||
lodsb
|
|
||||||
stosb
|
|
||||||
loop copy_gdt
|
|
||||||
|
|
||||||
mov edi, IDT ;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
|
|
||||||
|
|
||||||
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, 0x1ffffc ;stack just under 2mb, moves downward
|
|
||||||
lidt [idtr] ;load idt
|
|
||||||
|
|
||||||
call _k_init
|
|
||||||
hlt ;halt processor when k_init is done
|
|
||||||
jmp $ ;shouldn't get here...
|
|
||||||
|
|
||||||
%include "gdt.inc"
|
|
||||||
%include "idt.inc"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
//kernel.c
|
|
||||||
//08/13/03 Josh Holtrop
|
|
||||||
//Holtrop's Operating System
|
|
||||||
|
|
||||||
#define VXR video_mode.XResolution
|
|
||||||
#define VYR video_mode.YResolution
|
|
||||||
|
|
||||||
#include "k_defines.h"
|
|
||||||
|
|
||||||
#include "lib/string.h"
|
|
||||||
#include "lib/io.h"
|
|
||||||
|
|
||||||
#include "functions.h"
|
|
||||||
#include "video.h"
|
|
||||||
#include "mm.h"
|
|
||||||
#include "keyboard.h"
|
|
||||||
#include "mouse.h"
|
|
||||||
|
|
||||||
void isr(dword num);
|
|
||||||
void k_init();
|
|
||||||
|
|
||||||
#include "mouse.c"
|
|
||||||
#include "keyboard.c"
|
|
||||||
#include "mm.c"
|
|
||||||
#include "functions.c"
|
|
||||||
#include "video.c"
|
|
||||||
|
|
||||||
dword timer = 0;
|
|
||||||
|
|
||||||
void k_init()
|
|
||||||
{
|
|
||||||
console_cls();
|
|
||||||
remap_pics(0x20, 0x28);
|
|
||||||
//set timer : 2e9c = 100hz
|
|
||||||
outportb(0x43, 0x34);
|
|
||||||
outportb(0x40, 0x9c); //lsb
|
|
||||||
outportb(0x40, 0x2e); //msb
|
|
||||||
video_init((ModeInfoBlock *) 0x90306);
|
|
||||||
video_rectf(VXR*3/11, 0, VXR*4/11, VYR-1, 0x00000088); //test rectangles, draws "HOS"
|
|
||||||
video_rectf(VXR*7/11, 0, VXR*8/11, VYR-1, 0x00000088);
|
|
||||||
video_rectf(VXR/11, 0, VXR*2/11, VYR*2/5, 0x00000088);
|
|
||||||
video_rectf(VXR/11, VYR*3/5, VXR*2/11, VYR-1, 0x00000088);
|
|
||||||
video_rectf(VXR*5/11, VYR/5, VXR*6/11, VYR*4/5, 0x00000088);
|
|
||||||
video_rectf(VXR*9/11, VYR/5, VXR-1, VYR*2/5, 0x00000088);
|
|
||||||
video_rectf(VXR*8/11, VYR*3/5, VXR*10/11, VYR*4/5, 0x00000088);
|
|
||||||
|
|
||||||
video_vert(10, 10, 16, 0x00ffff00); //should be yellow 'H'
|
|
||||||
video_horiz(13, 10, 14, 0x00ffff00);
|
|
||||||
video_vert(14, 10, 16, 0x00ffff00);
|
|
||||||
|
|
||||||
video_horiz(10, 17, 21, 0x00ffff00);
|
|
||||||
video_vert(19, 10, 16, 0x00ffff00);
|
|
||||||
video_horiz(16, 17, 21, 0x00ffff00);
|
|
||||||
|
|
||||||
int a, b;
|
|
||||||
for (a = 0; a < 256; a++)
|
|
||||||
{
|
|
||||||
for (b = 0; b < 256; b++)
|
|
||||||
{
|
|
||||||
video_pset(a+5, b+30, (a<<16)|(b<<8));
|
|
||||||
video_pset(a+270, b+30, (a<<8)|(b));
|
|
||||||
video_pset(a+535, b+30, (a<<16)|(b));
|
|
||||||
|
|
||||||
video_pset(a+5, b+290, (a<<16)|(b<<8)|0x000000ff);
|
|
||||||
video_pset(a+270, b+290, (a<<8)|(b)|0x00ff0000);
|
|
||||||
video_pset(a+535, b+290, (a<<16)|(b)|0x0000ff00);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mm_init();
|
|
||||||
mouse_init();
|
|
||||||
enable_ints();
|
|
||||||
printf("Memory available to OS: %d MB (Bytes: %d)\n", mm_totalmem/0x100000, mm_totalmem);
|
|
||||||
pic1_mask(0); //unmask IRQ's 0-7
|
|
||||||
pic2_mask(0); //unmask IRQ's 8-15
|
|
||||||
dword key = 0;
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
key = kbdWaitKey();
|
|
||||||
putc(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void isr(dword num)
|
|
||||||
{
|
|
||||||
switch(num)
|
|
||||||
{
|
|
||||||
case 0x20: // IRQ0 - timer interrupt
|
|
||||||
timer++;
|
|
||||||
(*(byte *)0xb8000)++;
|
|
||||||
eoi();
|
|
||||||
break;
|
|
||||||
case 0x21: // IRQ1 - keyboard interrupt
|
|
||||||
isr_keyboard(); //isr_keybard() takes care of calling eoi()
|
|
||||||
break;
|
|
||||||
case 0x2C: // IRQ12 - PS/2 mouse
|
|
||||||
isr_mouse();
|
|
||||||
eoi2();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printf("Interrupt %d (0x%x) Unhandled!!\n", num, num);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
+129
@@ -0,0 +1,129 @@
|
|||||||
|
# Makefile for HOS
|
||||||
|
# Josh Holtrop
|
||||||
|
# Created: 07/08/04
|
||||||
|
# Modified: 06/13/05
|
||||||
|
|
||||||
|
# Assembler Information:
|
||||||
|
NASM=nasm
|
||||||
|
NASM_FLAGS=-f elf32
|
||||||
|
|
||||||
|
# C/C++ Information:
|
||||||
|
CPPFLAGS=-ffreestanding -fno-builtin -nostdlib -nostartfiles -nodefaultlibs -I. -Wall -m32 -fno-pic
|
||||||
|
# -S -masm=intel
|
||||||
|
CC=gcc
|
||||||
|
CXX=g++
|
||||||
|
CXXFLAGS=-fno-rtti -fno-exceptions -D_HOS_CPP_ -std=gnu++98
|
||||||
|
|
||||||
|
# Linker Information:
|
||||||
|
LD=gcc
|
||||||
|
LDFLAGS=-ffreestanding -fno-builtin -nostartfiles -nodefaultlibs -nostdlib -Wl,--no-demangle -T link.ld -m32
|
||||||
|
LIBS=-static-libgcc
|
||||||
|
|
||||||
|
# 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) -Wl,-Map -Wl,kernel.map $(OBJS) -o kernel.bin $(LIBS)
|
||||||
|
@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 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
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
# 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
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
// 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
@@ -0,0 +1,236 @@
|
|||||||
|
;boot.asm
|
||||||
|
;Author: Josh Holtrop
|
||||||
|
;Date: 07/08/04
|
||||||
|
;Modified: 11/01/05
|
||||||
|
|
||||||
|
|
||||||
|
%define MULTIBOOT_MAGIC 0x1BADB002
|
||||||
|
%define MULTIBOOT_FLAGS 0x00010003
|
||||||
|
|
||||||
|
%define VIRT_OFFSET 0xC0000000 ;3gb virtual address
|
||||||
|
%define PHYS_START 0x00100000 ;1mb physical address
|
||||||
|
%define VIRT_STACK_TOP 0xD0000000 ;3gb+256mb virtual address
|
||||||
|
%define GDT_P PHYS_START ;1mb physical - Global Descriptor Table space
|
||||||
|
%define GDT_V GDT_P+VIRT_OFFSET
|
||||||
|
%define IDT_P PHYS_START+0x2000 ;1mb+8kb - Interrupt Descriptor Table space
|
||||||
|
%define IDT_V IDT_P+VIRT_OFFSET
|
||||||
|
%define PDBR_P PHYS_START+0x4000 ;1mb+16kb - Page Directory Base Register (first PD)
|
||||||
|
%define PDBR_V PDBR_P+VIRT_OFFSET
|
||||||
|
%define LOPT_P PHYS_START+0x5000 ;1mb+20kb - LOw Page Table for mapping first 4mb
|
||||||
|
%define LOPT_V LOPT_P+VIRT_OFFSET
|
||||||
|
%define PT_STACK_P PHYS_START+0x6000 ;1mb+24kb - page table for initial kernel stack pages (under 0xD0000000)
|
||||||
|
%define PT_STACK_V PT_STACK_P+VIRT_OFFSET
|
||||||
|
%define STACK_P PHYS_START+0x7000 ;1mb+28kb - initial 4kb kernel stack page
|
||||||
|
%define STACK_V STACK_P+VIRT_OFFSET
|
||||||
|
%define KERNEL_P PHYS_START+0x8000 ;1mb+32kb - the kernel's physical address
|
||||||
|
%define KERNEL_V KERNEL_P+VIRT_OFFSET ;3gb+1mb+32kb, the virtual address of the kernel
|
||||||
|
|
||||||
|
extern k_init, isr, k_mbsave, end, rm_params, initrd, tss0
|
||||||
|
|
||||||
|
[bits 32]
|
||||||
|
|
||||||
|
[global start]
|
||||||
|
start:
|
||||||
|
|
||||||
|
multiboot_header:
|
||||||
|
dd MULTIBOOT_MAGIC ;magic
|
||||||
|
dd MULTIBOOT_FLAGS ;flags
|
||||||
|
dd -(MULTIBOOT_MAGIC + MULTIBOOT_FLAGS) ;checksum
|
||||||
|
|
||||||
|
dd 0x100000000+multiboot_header-VIRT_OFFSET ;header_addr
|
||||||
|
dd 0x100000000+start-VIRT_OFFSET ;load_addr
|
||||||
|
dd 0 ;load_end_addr
|
||||||
|
dd 0x100000000+end-VIRT_OFFSET ;bss_end_addr
|
||||||
|
dd 0x100000000+multiboot_entry-VIRT_OFFSET ;entry_addr
|
||||||
|
|
||||||
|
; dd 1 ;mode_type
|
||||||
|
; dd 80 ;width
|
||||||
|
; dd 25 ;height
|
||||||
|
; dd 0 ;depth
|
||||||
|
|
||||||
|
[global multiboot_entry]
|
||||||
|
multiboot_entry:
|
||||||
|
;This is where the kernel begins execution from the bootloader.
|
||||||
|
;At this point, a temporary gdt is set up to "map" 0xC000_0000 to 0x0.
|
||||||
|
cli ;should already be off...
|
||||||
|
lgdt [0x100000000+gdtrbs32-VIRT_OFFSET]
|
||||||
|
jmp KERNEL_CODE_BS32:segmented_start
|
||||||
|
segmented_start:
|
||||||
|
mov cx, KERNEL_DATA_BS32
|
||||||
|
mov ss, cx
|
||||||
|
mov ds, cx
|
||||||
|
mov es, cx
|
||||||
|
mov gs, cx
|
||||||
|
mov fs, cx
|
||||||
|
mov esp, STACK_V+0x1000 ;ok, now we can access our data
|
||||||
|
|
||||||
|
;Then the multiboot info structures are saved to local data variables.
|
||||||
|
add ebx, VIRT_OFFSET
|
||||||
|
push eax
|
||||||
|
push ebx ;pointer to multiboot info structure
|
||||||
|
call k_mbsave ;save multiboot info structures
|
||||||
|
add esp, 8
|
||||||
|
|
||||||
|
cmp eax, 0 ; eax = pointer to mb_module_t struct for rmmod
|
||||||
|
jz pm_return
|
||||||
|
|
||||||
|
;go back to real mode to initialize video mode
|
||||||
|
mov ebx, eax ; pointer to mb_module_t
|
||||||
|
mov ecx, [ebx+4] ; end of module
|
||||||
|
mov eax, [ebx] ; start of module
|
||||||
|
mov esi, eax ; start of module
|
||||||
|
sub ecx, eax ; ecx = length of rmmod
|
||||||
|
shr ecx, 2 ; ecx = length of rmmod in dwords
|
||||||
|
mov edi, 0xC0005000 ; where to copy rmmod to (0x5000 physical)
|
||||||
|
|
||||||
|
rep movsd ; copy rmmod to first 1mb
|
||||||
|
|
||||||
|
mov ebx, pm_return ; return address
|
||||||
|
mov ecx, rm_params ; put real mode params here (video mode etc...)
|
||||||
|
sub ecx, VIRT_OFFSET
|
||||||
|
|
||||||
|
jmp 0xC0005010 ; jump to rmmod
|
||||||
|
|
||||||
|
;Next we enable paging with the first 4mb mapped 1:1 virtual:physical
|
||||||
|
; and with the 4mb starting at 0xC000_0000 mapped to the first 4mb physical.
|
||||||
|
pm_return:
|
||||||
|
mov esp, STACK_V+0x1000 ;ok, now we can access our data again
|
||||||
|
xor eax, eax
|
||||||
|
mov edi, PDBR_V
|
||||||
|
mov ecx, 1024 ;clear the PDBR
|
||||||
|
rep stosd
|
||||||
|
mov edi, PT_STACK_V
|
||||||
|
mov ecx, 1024 ;clear the PT_STACK
|
||||||
|
rep stosd
|
||||||
|
mov [PDBR_V], dword LOPT_P|0x03 ;store the physical address of the LOw Page Table | (read/write, present)
|
||||||
|
mov [PDBR_V+0xC00], dword LOPT_P|0x03 ;store the physical address of the LOw Page Table | (read/write, present)
|
||||||
|
mov [PDBR_V+0xCFC], dword PT_STACK_P|0x03 ;store the physical address of the initial stack page page table | (read/write, present)
|
||||||
|
mov [PDBR_V+0xFFC], dword PDBR_P|0x03 ;store the physical address of the page directory (identity map) | (read/write, present)
|
||||||
|
mov [PT_STACK_V+0xFFC], dword STACK_P|0x03 ;store the physical address of the initial stack page | (read/write, present)
|
||||||
|
|
||||||
|
mov edi, LOPT_V
|
||||||
|
mov ecx, 1024
|
||||||
|
mov eax, 0x03 ;starting physical address = 0x0 | (read/write, present flags)
|
||||||
|
fill_lopt_loop: ;fill the page table
|
||||||
|
stosd
|
||||||
|
add eax, 4096 ;increment next phsyical address by 4kb
|
||||||
|
loop fill_lopt_loop
|
||||||
|
|
||||||
|
mov eax, PDBR_P
|
||||||
|
mov cr3, eax ;store the Page Directory Base Address
|
||||||
|
mov eax, cr0
|
||||||
|
or eax, 0x80000000 ;set Page Enable bit
|
||||||
|
mov cr0, eax ;now paging is active!
|
||||||
|
|
||||||
|
mov edi, GDT_V
|
||||||
|
mov esi, gdt
|
||||||
|
mov ecx, gdt_end-gdt
|
||||||
|
rep movsb
|
||||||
|
|
||||||
|
mov edi, IDT_V ;destination
|
||||||
|
mov esi, isr_0 ;address of isr0
|
||||||
|
mov edx, isr_1-isr_0 ;distance between isr labels
|
||||||
|
mov ecx, 50 ;number of isrlabels
|
||||||
|
fill_idt:
|
||||||
|
mov ebx, esi
|
||||||
|
mov ax, si
|
||||||
|
stosw ;0 offset 15:0
|
||||||
|
mov ax, KERNEL_CODE
|
||||||
|
stosw ;2 selector 15:0
|
||||||
|
mov ax, 0x8E00
|
||||||
|
stosw ;4 [P][DPL][0][TYPE][0][0][0][0][0][0][0][0]
|
||||||
|
shr esi, 16
|
||||||
|
mov ax, si
|
||||||
|
stosw ;6 offset 31:16
|
||||||
|
mov esi, ebx
|
||||||
|
add esi, edx
|
||||||
|
loop fill_idt
|
||||||
|
mov word [IDT_V+0x30*8+4], 0xEE00 ;interrupt 0x30 has user priviledges
|
||||||
|
|
||||||
|
;Then we can start using our "real" gdt, then unmap the lower 4mb.
|
||||||
|
lgdt [gdtr] ;load gdt
|
||||||
|
jmp KERNEL_CODE:newgdtcontinue
|
||||||
|
newgdtcontinue:
|
||||||
|
mov ax, KERNEL_DATA
|
||||||
|
mov es, ax
|
||||||
|
mov ds, ax
|
||||||
|
mov gs, ax
|
||||||
|
mov fs, ax
|
||||||
|
mov ss, ax
|
||||||
|
mov esp, VIRT_STACK_TOP ;stack just under 3gb+256mb, moves downward
|
||||||
|
lidt [idtr] ;load idt
|
||||||
|
mov [PDBR_V], dword 0 ;unmap 0x0, we are running completely paged at 0xC000_0000
|
||||||
|
|
||||||
|
mov edi, GDT_V + TSS0_SEG + 2 ; copy tss0 base address
|
||||||
|
mov eax, tss0 ; into the GDT descrtiptor
|
||||||
|
stosw ; for TSS0
|
||||||
|
shr eax, 16
|
||||||
|
stosb
|
||||||
|
add edi, 2
|
||||||
|
shr eax, 8
|
||||||
|
stosb
|
||||||
|
|
||||||
|
call k_init ;C kernel initialization
|
||||||
|
|
||||||
|
mov ax, TSS0_SEG
|
||||||
|
ltr ax
|
||||||
|
|
||||||
|
mov eax, esp
|
||||||
|
push KERNEL_DATA
|
||||||
|
push eax
|
||||||
|
|
||||||
|
idle_loop: ; system idle loop
|
||||||
|
sti
|
||||||
|
hlt
|
||||||
|
jmp idle_loop
|
||||||
|
|
||||||
|
;-------------------------------------------------------
|
||||||
|
gdtrbs32:
|
||||||
|
dw gdt_endbs32-gdtbs32-1
|
||||||
|
dd 0x100000000+gdtbs32-VIRT_OFFSET
|
||||||
|
gdtbs32: ; 0 = null descriptor
|
||||||
|
dd 0
|
||||||
|
dd 0
|
||||||
|
|
||||||
|
;a base of 0x4000_0000, when added to 0xC000_0000 will produce 0x0000_0000 physical before paging in effect
|
||||||
|
KERNEL_CODE_BS32 equ $-gdtbs32 ; 8
|
||||||
|
db 0xff ;limit 7:0
|
||||||
|
db 0xff ;limit 15:8
|
||||||
|
db 0x00 ;base 7:0
|
||||||
|
db 0x00 ;base 15:8
|
||||||
|
db 0x00 ;base 23:16
|
||||||
|
db 0x9a ;access
|
||||||
|
db 0xcf ;flags / limit 19:16
|
||||||
|
db 0x40 ;base 31:24
|
||||||
|
|
||||||
|
KERNEL_DATA_BS32 equ $-gdtbs32 ; 16
|
||||||
|
db 0xff ;limit 7:0
|
||||||
|
db 0xff ;limit 15:8
|
||||||
|
db 0x00 ;base 7:0
|
||||||
|
db 0x00 ;base 15:8
|
||||||
|
db 0x00 ;base 23:16
|
||||||
|
db 0x92 ;access
|
||||||
|
db 0xcf ;flags / limit 19:16
|
||||||
|
db 0x40 ;base 31:24
|
||||||
|
|
||||||
|
KERNEL_CODE_BS6_ equ $-gdtbs32 ; 24
|
||||||
|
dw 0xffff ;limit 15:0
|
||||||
|
dw 0x0000 ;base 15:0
|
||||||
|
db 0x00 ;base 23:16
|
||||||
|
db 0x9A ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A])
|
||||||
|
db 0x00 ;flags ([G][D/B][0][0]) / limit 19:16
|
||||||
|
db 0x00 ;base 31:24
|
||||||
|
|
||||||
|
KERNEL_DATA_BS16 equ $-gdtbs32 ; 32
|
||||||
|
dw 0xffff ;limit 15:0
|
||||||
|
dw 0x0000 ;base 15:0
|
||||||
|
db 0x00 ;base 23:16
|
||||||
|
db 0x92 ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A])
|
||||||
|
db 0x00 ;flags ([G][D/B][0][0]) / limit 19:16
|
||||||
|
db 0x00 ;base 31:24
|
||||||
|
|
||||||
|
gdt_endbs32:
|
||||||
|
|
||||||
|
%include "gdt.inc"
|
||||||
|
%include "idt.inc"
|
||||||
|
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// 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,8 +1,17 @@
|
|||||||
// mouse.c
|
// mouse.c
|
||||||
// 10/03/03
|
|
||||||
// Author: Josh Holtrop
|
// 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()
|
void mouse_init()
|
||||||
{
|
{
|
||||||
outportb(0x64, 0x20); //tell keyboard controller we are going to read keyboard controller command byte
|
outportb(0x64, 0x20); //tell keyboard controller we are going to read keyboard controller command byte
|
||||||
@@ -15,17 +24,17 @@ void mouse_init()
|
|||||||
outportb(0x64, 0xD4); //send command to mouse, not kbd
|
outportb(0x64, 0xD4); //send command to mouse, not kbd
|
||||||
outportb(0x60, 0xF4); //enable data reporting
|
outportb(0x60, 0xF4); //enable data reporting
|
||||||
|
|
||||||
|
mouse_bytesRead = 0;
|
||||||
|
|
||||||
//outportb(0x64, 0xD4);
|
//outportb(0x64, 0xD4);
|
||||||
//outportb(0x60, 0xE7); //scaling 2:1
|
//outportb(0x60, 0xE7); //scaling 2:1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//This method is called when a mouse interrupt occurs
|
||||||
void isr_mouse()
|
void isr_mouse()
|
||||||
{
|
{
|
||||||
byte inb = inportb(0x60); //read mouse byte
|
byte inb = inportb(0x60); //read mouse byte
|
||||||
//printf("InB: %x\n", inb);
|
|
||||||
//return;
|
|
||||||
if ((inb == 0xFA) && (mouse_bytesRead < 1)) //ACK
|
if ((inb == 0xFA) && (mouse_bytesRead < 1)) //ACK
|
||||||
return;
|
return;
|
||||||
mouse_inbuffer[mouse_bytesRead] = inb;
|
mouse_inbuffer[mouse_bytesRead] = inb;
|
||||||
@@ -35,22 +44,9 @@ void isr_mouse()
|
|||||||
mouse_bytesRead = 0;
|
mouse_bytesRead = 0;
|
||||||
int adjx = (char) mouse_inbuffer[1];
|
int adjx = (char) mouse_inbuffer[1];
|
||||||
int adjy = (char) mouse_inbuffer[2];
|
int adjy = (char) mouse_inbuffer[2];
|
||||||
mouse_x += adjx;
|
// TODO: do something with adjx, adjy...
|
||||||
mouse_y -= adjy; //-= because screen y coordinates are opposite mouse y coordinates
|
|
||||||
if (mouse_inbuffer[0] & 0x01) //left button
|
|
||||||
{
|
|
||||||
video_pset(VXR/2+mouse_x, VYR/2+mouse_y, 0x00FFFFFF);
|
|
||||||
printf("X: %d, Y: %d\n", mouse_x, mouse_y);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
video_pset(VXR/2+mouse_x, VYR/2+mouse_y, 0x00000000);
|
|
||||||
printf("X: %d, Y: %d\n", mouse_x, mouse_y);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
@@ -0,0 +1,274 @@
|
|||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
// 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; }
|
||||||
|
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
// 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 */
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
// 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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// 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;}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
// 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
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// 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; }
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// 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; }
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
// 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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// 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
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
// 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];
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
// 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
|
||||||
@@ -0,0 +1,238 @@
|
|||||||
|
// 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 */
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
// 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
|
||||||
@@ -0,0 +1,228 @@
|
|||||||
|
// 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);
|
||||||
|
lockit(&Ext2OpenFileListLock);
|
||||||
|
if ((mode & VFS_MODE_RW_MASK) == VFS_MODE_WRITE)
|
||||||
|
{
|
||||||
|
if ((mode & VFS_MODE_WRITE_MASK) == VFS_MODE_TRUNCATE)
|
||||||
|
{
|
||||||
|
/* file opened for write/truncate
|
||||||
|
* tell any open files that it's been truncated, then
|
||||||
|
* tell ext2 filesystem to free its blocks
|
||||||
|
*/
|
||||||
|
u32_t size = Ext2OpenFileList->size();
|
||||||
|
for (u32_t i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
if ((*Ext2OpenFileList)[i].inode == inum)
|
||||||
|
(*Ext2OpenFileList)[i].ofile->notifyTruncated();
|
||||||
|
}
|
||||||
|
fs->truncateInode(inum);
|
||||||
|
fs->readInode(inum, &myInode); /* re-read inode */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
myPosition = myInode.i_size;
|
||||||
|
}
|
||||||
|
if (Ext2OpenFileList == NULL)
|
||||||
|
Ext2OpenFileList = new vector<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 */
|
||||||
|
lockit(&Ext2OpenFileListLock);
|
||||||
|
u32_t size = Ext2OpenFileList->size();
|
||||||
|
for (u32_t i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
if ((*Ext2OpenFileList)[i].ofile == this)
|
||||||
|
{
|
||||||
|
Ext2OpenFileList->remove(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unlock(&Ext2OpenFileListLock);
|
||||||
|
|
||||||
|
/* write back any open caches if in write mode */
|
||||||
|
if ( !myBeenTruncated && ((myMode & VFS_MODE_RW_MASK) == VFS_MODE_WRITE) )
|
||||||
|
{
|
||||||
|
if (myBlockCacheStatus == 2)
|
||||||
|
myCache->writeBlock(myBlockCacheBlock, myBlockCache);
|
||||||
|
myFS->writeInode(myInum, &myInode);
|
||||||
|
}
|
||||||
|
/* free the memory we used */
|
||||||
|
delete myCache;
|
||||||
|
delete[] myBlockCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* seek to a certain position in the file (only for reading) */
|
||||||
|
int Ext2OpenFile::seek(int pos, int mode)
|
||||||
|
{
|
||||||
|
if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_READ)
|
||||||
|
return -1;
|
||||||
|
if (mode == SEEK_ABSOLUTE)
|
||||||
|
{
|
||||||
|
if (pos < 0)
|
||||||
|
return -2;
|
||||||
|
if ((u32_t)pos >= myInode.i_size)
|
||||||
|
return -3;
|
||||||
|
myPosition = pos;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (mode == SEEK_RELATIVE)
|
||||||
|
{
|
||||||
|
if (myPosition + pos < 0)
|
||||||
|
return -2;
|
||||||
|
if (myPosition + pos >= myInode.i_size)
|
||||||
|
return -3;
|
||||||
|
myPosition += pos;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (mode == SEEK_END)
|
||||||
|
{
|
||||||
|
if (myInode.i_size + pos < 0)
|
||||||
|
return -2;
|
||||||
|
if (myInode.i_size + pos >= myInode.i_size)
|
||||||
|
return -3;
|
||||||
|
myPosition = myInode.i_size + pos;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read a byte from the current file position, return error code/EOF */
|
||||||
|
int Ext2OpenFile::read()
|
||||||
|
{
|
||||||
|
if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_READ)
|
||||||
|
return -1;
|
||||||
|
if (myBeenTruncated || myPosition >= myInode.i_size)
|
||||||
|
return EOF;
|
||||||
|
u32_t theBlock = myPosition / myBlockSize;
|
||||||
|
updateCache(theBlock);
|
||||||
|
return myBlockCache[myPosition++ % myBlockSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read num bytes from the current file position, put in buf
|
||||||
|
* return: number of bytes read (>=0) or error code (<0)
|
||||||
|
*/
|
||||||
|
int Ext2OpenFile::read(void *buf, u32_t num)
|
||||||
|
{
|
||||||
|
if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_READ)
|
||||||
|
return -1;
|
||||||
|
if (myBeenTruncated || myPosition >= myInode.i_size)
|
||||||
|
return EOF;
|
||||||
|
if (myPosition + num > myInode.i_size)
|
||||||
|
num = myInode.i_size - myPosition;
|
||||||
|
u32_t bytesRead = 0;
|
||||||
|
u32_t bytesIntoFirstBlock = myPosition % myBlockSize;
|
||||||
|
if (bytesIntoFirstBlock)
|
||||||
|
{
|
||||||
|
updateCache(myPosition / myBlockSize);
|
||||||
|
bytesRead = min(myBlockSize - bytesIntoFirstBlock, num);
|
||||||
|
memcpy(buf, myBlockCache + bytesIntoFirstBlock, bytesRead);
|
||||||
|
myPosition += bytesRead;
|
||||||
|
}
|
||||||
|
while (bytesRead < num)
|
||||||
|
{
|
||||||
|
updateCache(myPosition / myBlockSize);
|
||||||
|
u32_t bytesToRead = min(num - bytesRead, myBlockSize);
|
||||||
|
memcpy((u8_t *)buf + bytesRead, myBlockCache, bytesToRead);
|
||||||
|
bytesRead += bytesToRead;
|
||||||
|
myPosition += bytesToRead;
|
||||||
|
}
|
||||||
|
return bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write a byte to the current file position */
|
||||||
|
int Ext2OpenFile::write(int chr)
|
||||||
|
{
|
||||||
|
if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_WRITE)
|
||||||
|
return -1;
|
||||||
|
if (myBeenTruncated)
|
||||||
|
return EOF;
|
||||||
|
u32_t theBlock = myPosition / myBlockSize;
|
||||||
|
updateCache(theBlock);
|
||||||
|
myBlockCache[myPosition++ % myBlockSize] = chr;
|
||||||
|
myBlockCacheStatus = 2;
|
||||||
|
myInode.i_size++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write num bytes from buf to the current file position
|
||||||
|
* return: number of bytes written (>=0) or error code (<0)
|
||||||
|
*/
|
||||||
|
int Ext2OpenFile::write(void *buf, u32_t num)
|
||||||
|
{
|
||||||
|
if (myBeenTruncated)
|
||||||
|
return -1;
|
||||||
|
if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_WRITE)
|
||||||
|
return -2;
|
||||||
|
u32_t bytesIntoFirstBlock = myPosition % myBlockSize;
|
||||||
|
u32_t bytesWritten = 0;
|
||||||
|
if (bytesIntoFirstBlock)
|
||||||
|
{
|
||||||
|
updateCache(myPosition / myBlockSize);
|
||||||
|
bytesWritten = min(myBlockSize - bytesIntoFirstBlock, num);
|
||||||
|
memcpy(myBlockCache + bytesIntoFirstBlock, buf, bytesWritten);
|
||||||
|
myBlockCacheStatus = 2;
|
||||||
|
myPosition += bytesWritten;
|
||||||
|
}
|
||||||
|
while (bytesWritten < num)
|
||||||
|
{
|
||||||
|
updateCache(myPosition / myBlockSize);
|
||||||
|
u32_t bytesToWrite = min(num - bytesWritten, myBlockSize);
|
||||||
|
memcpy(myBlockCache, (u8_t *)buf + bytesWritten, bytesToWrite);
|
||||||
|
myBlockCacheStatus = 2;
|
||||||
|
bytesWritten += bytesToWrite;
|
||||||
|
myPosition += bytesToWrite;
|
||||||
|
}
|
||||||
|
myInode.i_size += bytesWritten;
|
||||||
|
return bytesWritten;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ext2OpenFile::updateCache(u32_t blockNum)
|
||||||
|
{
|
||||||
|
if (myBlockCacheStatus && myBlockCacheBlock == blockNum)
|
||||||
|
return;
|
||||||
|
if (myBlockCacheStatus == 2)
|
||||||
|
myCache->writeBlock(myBlockCacheBlock, myBlockCache);
|
||||||
|
myCache->readBlock(blockNum, myBlockCache);
|
||||||
|
myBlockCacheStatus = 1;
|
||||||
|
myBlockCacheBlock = blockNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ext2OpenFile::notifyTruncated()
|
||||||
|
{
|
||||||
|
myBeenTruncated = 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
// 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
|
||||||
@@ -0,0 +1,599 @@
|
|||||||
|
// 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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,204 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
@@ -0,0 +1,762 @@
|
|||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,241 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
@@ -0,0 +1,332 @@
|
|||||||
|
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,241 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// 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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// 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()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
@@ -0,0 +1,413 @@
|
|||||||
|
// 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
@@ -0,0 +1,129 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
@@ -0,0 +1,432 @@
|
|||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
//functions.h
|
||||||
|
//05/07/03 Josh Holtrop
|
||||||
|
//for HOS
|
||||||
|
//Modified: 02/26/04
|
||||||
|
|
||||||
|
#ifndef __HOS_FUNCTIONS__
|
||||||
|
#define __HOS_FUNCTIONS__ __HOS_FUNCTIONS__
|
||||||
|
|
||||||
|
#include "hos_defines.h"
|
||||||
|
#include "sys/io.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
extern u32_t _code;
|
||||||
|
extern u32_t _bss;
|
||||||
|
extern u32_t _end;
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//Enables (SeTs) Interrupt Flag on the processor
|
||||||
|
static inline void enable_ints()
|
||||||
|
{
|
||||||
|
asm("sti");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Disables (CLears) Interrupt Flag on the processor
|
||||||
|
static inline void disable_ints()
|
||||||
|
{
|
||||||
|
asm("cli");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Restarts the computer
|
||||||
|
static inline void restart()
|
||||||
|
{
|
||||||
|
enable_ints();
|
||||||
|
byte temp;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
temp = inportb(0x64);
|
||||||
|
if (temp & 1)
|
||||||
|
inportb(0x60);
|
||||||
|
} while(temp & 2);
|
||||||
|
|
||||||
|
|
||||||
|
outportb (0x64, 0xfe);
|
||||||
|
for (;;) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Halts (freezes) the computer
|
||||||
|
static inline void halt()
|
||||||
|
{
|
||||||
|
asm("cli");
|
||||||
|
asm("hlt");
|
||||||
|
while (1) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Initializes 8253 Programmable Interrupt Timer
|
||||||
|
static inline void timer_init(u32_t freq)
|
||||||
|
{
|
||||||
|
u32_t wait = 1193180 / freq; //how many ticks the PIT must wait before issuing an interrupt
|
||||||
|
outportb(0x43, 0x34);
|
||||||
|
outportb(0x40, wait); //lsb
|
||||||
|
outportb(0x40, wait >> 8); //msb
|
||||||
|
}
|
||||||
|
|
||||||
|
//Returns the size of the kernel (code & data & bss)
|
||||||
|
// - this should be 4kb aligned per the linker script
|
||||||
|
// - this is the amount of RAM the kernel code, data, & bss take
|
||||||
|
static inline u32_t kernel_size_used()
|
||||||
|
{
|
||||||
|
return (u32_t)(&_end)-(u32_t)(&_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Returns the size of the kernel (code & data)
|
||||||
|
// - this does not include the bss section
|
||||||
|
// - this should be 4kb aligned per the linker script
|
||||||
|
// - this should be the size of kernel.bin
|
||||||
|
static inline u32_t kernel_size()
|
||||||
|
{
|
||||||
|
return (u32_t)(&_bss)-(u32_t)(&_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
//converts a binary-coded-decimal byte to its decimal equivalent
|
||||||
|
static inline byte bcd2byte(byte bcd)
|
||||||
|
{
|
||||||
|
return (10 * ((bcd & 0xF0) >> 4)) + (bcd & 0x0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
//converts a binary-coded-decimal byte to its decimal equivalent
|
||||||
|
static inline byte byte2bcd(byte bite)
|
||||||
|
{
|
||||||
|
return ((bite / 10) << 4) | (bite % 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the maximum of two values
|
||||||
|
static inline u32_t max(u32_t v1, u32_t v2)
|
||||||
|
{
|
||||||
|
return ( (v2 > v1) ? v2 : v1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the minimum of two values
|
||||||
|
static inline u32_t min(u32_t v1, u32_t v2)
|
||||||
|
{
|
||||||
|
return ( (v2 > v1) ? v1 : v2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
;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:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
// hos_defines.h
|
||||||
|
// Author: Josh Holtrop
|
||||||
|
// Date: 08/15/04
|
||||||
|
// Modified: 08/16/04
|
||||||
|
|
||||||
|
#ifndef __HOS_DEFINES_H__
|
||||||
|
#define __HOS_DEFINES_H__ __HOS_DEFINES_H__
|
||||||
|
|
||||||
|
#define PARALLEL_DEBUG
|
||||||
|
|
||||||
|
#define HOS_TIMER_FREQ 1000
|
||||||
|
#define KERNEL_MSG_CONSOLE 11
|
||||||
|
|
||||||
|
#define VIRT_OFFSET 0xC0000000
|
||||||
|
#define PHYS_LOAD 0x00108000
|
||||||
|
#define PDBR 0x00104000
|
||||||
|
#define VIRT_STACK_TOP 0xD0000000
|
||||||
|
#define HEAP_START 0xD0000000
|
||||||
|
#define HEAP_LENGTH 0x20000000
|
||||||
|
|
||||||
|
#define CONSOLE_MEMORY 0xC00B8000
|
||||||
|
#define BIOS_CHAR_MAP 0xC00FFA6E
|
||||||
|
#define LFB_MEMORY 0xF0000000
|
||||||
|
|
||||||
|
#define SEG_KERNEL_CODE 8
|
||||||
|
#define SEG_KERNEL_DATA 16
|
||||||
|
#define SEG_USER_CODE 24
|
||||||
|
#define SEG_USER_DATA 32
|
||||||
|
#define SEG_TSS0 40
|
||||||
|
|
||||||
|
#define MAX_MODULES 16
|
||||||
|
#define MAX_MMAP 16
|
||||||
|
|
||||||
|
#define NULL 0
|
||||||
|
|
||||||
|
#define HOS_INIT_TASK "/bin/init"
|
||||||
|
|
||||||
|
#define New(x) kcalloc(1, sizeof(x))
|
||||||
|
|
||||||
|
typedef unsigned long long u64_t;
|
||||||
|
typedef unsigned int u32_t;
|
||||||
|
typedef unsigned short u16_t;
|
||||||
|
typedef unsigned char u8_t;
|
||||||
|
typedef unsigned char byte;
|
||||||
|
typedef int lock_t;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
extern u32_t _end;
|
||||||
|
extern u32_t _bss;
|
||||||
|
extern u32_t start;
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+117
@@ -0,0 +1,117 @@
|
|||||||
|
;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
|
||||||
|
|
||||||
+288
@@ -0,0 +1,288 @@
|
|||||||
|
/* 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
@@ -0,0 +1,362 @@
|
|||||||
|
; lang.asm
|
||||||
|
; Josh Holtrop
|
||||||
|
; Created: 10/23/03
|
||||||
|
; Modified: 12/30/04
|
||||||
|
|
||||||
|
[bits 32]
|
||||||
|
|
||||||
|
%macro jzfar 1
|
||||||
|
jnz %%skip
|
||||||
|
jmp %1
|
||||||
|
%%skip:
|
||||||
|
|
||||||
|
%endmacro
|
||||||
|
|
||||||
|
;implements a lock
|
||||||
|
[global lockit]
|
||||||
|
lockit:
|
||||||
|
push ebp
|
||||||
|
mov ebp, esp
|
||||||
|
push eax
|
||||||
|
push ebx
|
||||||
|
push esi
|
||||||
|
|
||||||
|
mov esi, [ebp + 8]
|
||||||
|
_lock_loop0:
|
||||||
|
xor eax, eax
|
||||||
|
mov ebx, 1
|
||||||
|
cmpxchg [esi], ebx
|
||||||
|
jnz _lock_loop0 ; failed to acquire lock
|
||||||
|
|
||||||
|
pop esi
|
||||||
|
pop ebx
|
||||||
|
pop eax
|
||||||
|
pop ebp
|
||||||
|
ret
|
||||||
|
|
||||||
|
;releases a lock
|
||||||
|
[global unlock]
|
||||||
|
unlock:
|
||||||
|
push ebp
|
||||||
|
mov ebp, esp
|
||||||
|
push esi
|
||||||
|
|
||||||
|
mov esi, [ebp + 8]
|
||||||
|
mov [esi], dword 0
|
||||||
|
|
||||||
|
pop esi
|
||||||
|
pop ebp
|
||||||
|
ret
|
||||||
|
|
||||||
|
;returns the value in the CR0 register
|
||||||
|
;extern dword read_cr0();
|
||||||
|
[global read_cr0]
|
||||||
|
read_cr0:
|
||||||
|
mov eax, cr0;
|
||||||
|
ret
|
||||||
|
|
||||||
|
;stores the parameter to the CR0 register
|
||||||
|
;extern dword write_cr0(dword cr0);
|
||||||
|
[global write_cr0]
|
||||||
|
write_cr0:
|
||||||
|
push ebp
|
||||||
|
mov ebp, esp
|
||||||
|
mov eax, [ebp+8]
|
||||||
|
mov cr0, eax
|
||||||
|
pop ebp
|
||||||
|
ret
|
||||||
|
|
||||||
|
;returns the value in the CR2 register
|
||||||
|
;extern dword read_cr2();
|
||||||
|
[global read_cr2]
|
||||||
|
read_cr2:
|
||||||
|
mov eax, cr2;
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;returns the value in the CR3 register
|
||||||
|
;extern dword read_cr3();
|
||||||
|
[global read_cr3]
|
||||||
|
read_cr3:
|
||||||
|
mov eax, cr3;
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
;stores the parameter to the CR3 register
|
||||||
|
;extern dword write_cr3(dword cr3);
|
||||||
|
[global write_cr3]
|
||||||
|
write_cr3:
|
||||||
|
push ebp
|
||||||
|
mov ebp, esp
|
||||||
|
mov eax, [ebp+8]
|
||||||
|
mov cr3, eax
|
||||||
|
pop ebp
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
; read ss register
|
||||||
|
[global read_ss]
|
||||||
|
read_ss:
|
||||||
|
mov ax, ss
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
;copies a string from the source to the destination parameter
|
||||||
|
;extern void strcpy(char *dest, char *src);
|
||||||
|
[global strcpy]
|
||||||
|
strcpy:
|
||||||
|
push ebp
|
||||||
|
mov ebp, esp
|
||||||
|
push esi
|
||||||
|
push edi
|
||||||
|
mov edi, [ebp+8]
|
||||||
|
mov esi, [ebp+12]
|
||||||
|
strcpyloop:
|
||||||
|
lodsb
|
||||||
|
stosb
|
||||||
|
or al, al
|
||||||
|
jnz strcpyloop
|
||||||
|
pop edi
|
||||||
|
pop esi
|
||||||
|
pop ebp
|
||||||
|
ret
|
||||||
|
|
||||||
|
;copies memory of n bytes from src to destination
|
||||||
|
;void memcpy(void *dest, void *src, dword n);
|
||||||
|
[global memcpy]
|
||||||
|
memcpy:
|
||||||
|
push ebp
|
||||||
|
mov ebp, esp
|
||||||
|
push esi
|
||||||
|
push edi
|
||||||
|
push ecx
|
||||||
|
mov edi, [ebp+8]
|
||||||
|
mov esi, [ebp+12]
|
||||||
|
mov ecx, [ebp+16]
|
||||||
|
|
||||||
|
cld
|
||||||
|
rep movsb
|
||||||
|
|
||||||
|
pop ecx
|
||||||
|
pop edi
|
||||||
|
pop esi
|
||||||
|
pop ebp
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
;copies memory of n words (n*2 bytes) from src to destination
|
||||||
|
;void memcpyw(void *dest, void *src, dword n);
|
||||||
|
[global memcpyw]
|
||||||
|
memcpyw:
|
||||||
|
push ebp
|
||||||
|
mov ebp, esp
|
||||||
|
push esi
|
||||||
|
push edi
|
||||||
|
push ecx
|
||||||
|
mov edi, [ebp+8]
|
||||||
|
mov esi, [ebp+12]
|
||||||
|
mov ecx, [ebp+16]
|
||||||
|
|
||||||
|
cld
|
||||||
|
rep movsw
|
||||||
|
|
||||||
|
pop ecx
|
||||||
|
pop edi
|
||||||
|
pop esi
|
||||||
|
pop ebp
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
;copies memory of n dwords (n*4 bytes) from src to destination
|
||||||
|
;void memcpyd(void *dest, void *src, dword n);
|
||||||
|
[global memcpyd]
|
||||||
|
memcpyd:
|
||||||
|
push ebp
|
||||||
|
mov ebp, esp
|
||||||
|
push esi
|
||||||
|
push edi
|
||||||
|
push ecx
|
||||||
|
mov edi, [ebp+8]
|
||||||
|
mov esi, [ebp+12]
|
||||||
|
mov ecx, [ebp+16]
|
||||||
|
|
||||||
|
cld
|
||||||
|
rep movsd
|
||||||
|
|
||||||
|
pop ecx
|
||||||
|
pop edi
|
||||||
|
pop esi
|
||||||
|
pop ebp
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
;sets num bytes at buffer to the value of c
|
||||||
|
;void *memset(void *buffer, int c, int num);
|
||||||
|
[global memset]
|
||||||
|
memset:
|
||||||
|
push ebp
|
||||||
|
mov ebp, esp
|
||||||
|
push edi
|
||||||
|
push ecx
|
||||||
|
mov edi, [ebp+8]
|
||||||
|
push edi ;save for return address
|
||||||
|
mov eax, [ebp+12]
|
||||||
|
mov ecx, [ebp+16]
|
||||||
|
|
||||||
|
rep stosb
|
||||||
|
|
||||||
|
pop eax
|
||||||
|
pop ecx
|
||||||
|
pop edi
|
||||||
|
pop ebp
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
;sets num words at buffer to the value of c
|
||||||
|
;void *memsetw(void *buffer, int c, int num);
|
||||||
|
[global memsetw]
|
||||||
|
memsetw:
|
||||||
|
push ebp
|
||||||
|
mov ebp, esp
|
||||||
|
push edi
|
||||||
|
push ecx
|
||||||
|
mov edi, [ebp+8]
|
||||||
|
push edi ;save for return address
|
||||||
|
mov eax, [ebp+12]
|
||||||
|
mov ecx, [ebp+16]
|
||||||
|
|
||||||
|
rep stosw
|
||||||
|
|
||||||
|
pop eax
|
||||||
|
pop ecx
|
||||||
|
pop edi
|
||||||
|
pop ebp
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
;sets num dwords at buffer to the value of c
|
||||||
|
;void *memsetd(void *buffer, int c, int num);
|
||||||
|
[global memsetd]
|
||||||
|
memsetd:
|
||||||
|
push ebp
|
||||||
|
mov ebp, esp
|
||||||
|
push edi
|
||||||
|
push ecx
|
||||||
|
mov edi, [ebp+8]
|
||||||
|
push edi ;save for return address
|
||||||
|
mov eax, [ebp+12]
|
||||||
|
mov ecx, [ebp+16]
|
||||||
|
|
||||||
|
rep stosd
|
||||||
|
|
||||||
|
pop eax
|
||||||
|
pop ecx
|
||||||
|
pop edi
|
||||||
|
pop ebp
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
;returns the number of characters in a string
|
||||||
|
;extern dword strlen(char *str);
|
||||||
|
[global strlen]
|
||||||
|
strlen:
|
||||||
|
push ebp
|
||||||
|
mov ebp, esp
|
||||||
|
push esi
|
||||||
|
push ebx
|
||||||
|
mov esi, [ebp+8]
|
||||||
|
xor ebx, ebx
|
||||||
|
strlenloop:
|
||||||
|
lodsb
|
||||||
|
or al, al
|
||||||
|
jz strlendone
|
||||||
|
inc ebx
|
||||||
|
jmp strlenloop
|
||||||
|
strlendone:
|
||||||
|
mov eax, ebx
|
||||||
|
pop ebx
|
||||||
|
pop esi
|
||||||
|
pop ebp
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
;this function invalidates the page directory/table entry that
|
||||||
|
; would be used to access the memory address given in the parameter
|
||||||
|
;extern void invlpg_(dword addr);
|
||||||
|
[global invlpg_]
|
||||||
|
invlpg_:
|
||||||
|
mov eax, [esp+4]
|
||||||
|
invlpg [eax]
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
;
|
||||||
|
;void writeCursorPosition(word pos)
|
||||||
|
;
|
||||||
|
[global writeCursorPosition]
|
||||||
|
writeCursorPosition:
|
||||||
|
push ebp
|
||||||
|
mov ebp, esp
|
||||||
|
|
||||||
|
push eax
|
||||||
|
push ebx
|
||||||
|
push edx
|
||||||
|
|
||||||
|
mov eax, [ebp+8] ;cursor position in ax
|
||||||
|
|
||||||
|
mov bl, al
|
||||||
|
mov dx, 0x03D4
|
||||||
|
mov al, 0x0E
|
||||||
|
out dx, al
|
||||||
|
|
||||||
|
inc dx
|
||||||
|
mov al, ah
|
||||||
|
out dx, al
|
||||||
|
|
||||||
|
dec dx
|
||||||
|
mov al, 0x0F
|
||||||
|
out dx, al
|
||||||
|
|
||||||
|
inc dx
|
||||||
|
mov al, bl
|
||||||
|
out dx, al
|
||||||
|
|
||||||
|
pop edx
|
||||||
|
pop ebx
|
||||||
|
pop eax
|
||||||
|
pop ebp
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
;
|
||||||
|
;word getCursorPosition()
|
||||||
|
;
|
||||||
|
[global getCursorPosition]
|
||||||
|
getCursorPosition:
|
||||||
|
push ebx
|
||||||
|
push edx
|
||||||
|
|
||||||
|
xor eax, eax
|
||||||
|
mov dx, 0x03D4
|
||||||
|
mov al, 0x0E
|
||||||
|
out dx, al
|
||||||
|
|
||||||
|
inc dx
|
||||||
|
in al, dx
|
||||||
|
mov bl, al
|
||||||
|
|
||||||
|
dec dx
|
||||||
|
mov al, 0x0F
|
||||||
|
out dx, al
|
||||||
|
|
||||||
|
inc dx
|
||||||
|
in al, dx
|
||||||
|
mov ah, bl
|
||||||
|
|
||||||
|
pop edx
|
||||||
|
pop ebx
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
// lang.h
|
||||||
|
// Author: Josh Holtrop
|
||||||
|
// Created: 02/26/04
|
||||||
|
// Modified: 12/30/04
|
||||||
|
|
||||||
|
#ifndef __HOS_LANG__
|
||||||
|
#define __HOS_LANG__ __HOS_LANG__
|
||||||
|
|
||||||
|
#include "hos_defines.h"
|
||||||
|
|
||||||
|
/* lang.asm */
|
||||||
|
void lockit(lock_t *addr);
|
||||||
|
void unlock(lock_t *addr);
|
||||||
|
u32_t read_cr0();
|
||||||
|
u32_t write_cr0(u32_t cr0);
|
||||||
|
u32_t read_cr2();
|
||||||
|
u32_t read_cr3();
|
||||||
|
u32_t write_cr3(u32_t cr3);
|
||||||
|
u32_t read_ss();
|
||||||
|
void writeCursorPosition(u32_t pos);
|
||||||
|
u32_t getCursorPosition();
|
||||||
|
void strcpy(char *dest, const char *src);
|
||||||
|
void memcpy(void *dest, const void *src, u32_t n);
|
||||||
|
void memcpyw(void *dest, const void *src, u32_t n);
|
||||||
|
void memcpyd(void *dest, const void *src, u32_t n);
|
||||||
|
void *memset(void *buffer, int c, int num);
|
||||||
|
void *memsetw(void *buffer, int c, int num);
|
||||||
|
void *memsetd(void *buffer, int c, int num);
|
||||||
|
u32_t strlen(const char *str);
|
||||||
|
void invlpg_(u32_t addr);
|
||||||
|
|
||||||
|
/* lang.c */
|
||||||
|
int strcmp(char *str1, char *str2);
|
||||||
|
int strncmp(char *str1, char *str2, int n);
|
||||||
|
int str_change(char *str, char ch1, char ch2);
|
||||||
|
int str_count(char *str, char lookfor);
|
||||||
|
int str_split(char *str, char splitchar);
|
||||||
|
char *str_advance(char *str);
|
||||||
|
void strcat(char *dest, char *src);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
// Author: Josh Holtrop
|
||||||
|
// Date: 05/10/05
|
||||||
|
// Adds C++ support for new, delete functions
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include "hos_defines.h"
|
||||||
|
#include "mm/vmm.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
//overload the operator "new"
|
||||||
|
void * operator new (u32_t size)
|
||||||
|
{ return kmalloc(size); }
|
||||||
|
|
||||||
|
//overload the operator "new[]"
|
||||||
|
void * operator new[] (u32_t size)
|
||||||
|
{ return kmalloc(size); }
|
||||||
|
|
||||||
|
//overload the operator "delete"
|
||||||
|
void operator delete (void *p)
|
||||||
|
{ kfree(p); }
|
||||||
|
|
||||||
|
//overload the operator "delete[]"
|
||||||
|
void operator delete[] (void *p)
|
||||||
|
{ kfree(p); }
|
||||||
@@ -0,0 +1,258 @@
|
|||||||
|
|
||||||
|
// string.cpp
|
||||||
|
// implements c++ string object for HOS
|
||||||
|
// Author: Josh Holtrop
|
||||||
|
// Date: 06/01/04
|
||||||
|
// Modified: 05/10/05
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include "string.h" //string class declaration
|
||||||
|
#include "lang/lang.h" //memcpy(void *dest, void *src, int n), strlen(char *str)
|
||||||
|
}
|
||||||
|
|
||||||
|
string::string()
|
||||||
|
{
|
||||||
|
myLength = 0;
|
||||||
|
myChars = new char; //myChars must be a valid pointer at all times
|
||||||
|
*myChars = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
string::~string()
|
||||||
|
{
|
||||||
|
delete[] myChars;
|
||||||
|
}
|
||||||
|
|
||||||
|
string::string(const string & orig)
|
||||||
|
{
|
||||||
|
myLength = orig.myLength;
|
||||||
|
myChars = new char[myLength + 1];
|
||||||
|
memcpy(myChars, orig.myChars, myLength + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
string::string(const char *cstring)
|
||||||
|
{
|
||||||
|
myLength = strlen(cstring);
|
||||||
|
myChars = new char[myLength + 1];
|
||||||
|
memcpy(myChars, cstring, myLength + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
string & string::operator=(const string & orig)
|
||||||
|
{
|
||||||
|
if (this != &orig)
|
||||||
|
{
|
||||||
|
delete[] myChars;
|
||||||
|
myLength = orig.myLength;
|
||||||
|
myChars = new char[myLength + 1];
|
||||||
|
memcpy(myChars, orig.myChars, myLength + 1);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
string & string::operator=(const char *cstring)
|
||||||
|
{
|
||||||
|
if (myChars != cstring)
|
||||||
|
{
|
||||||
|
delete[] myChars;
|
||||||
|
myLength = strlen(cstring);
|
||||||
|
myChars = new char[myLength + 1];
|
||||||
|
memcpy(myChars, cstring, myLength + 1);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
char * string::data() const { return myChars; }
|
||||||
|
|
||||||
|
int string::size() const { return myLength; }
|
||||||
|
|
||||||
|
string & string::operator+=(const string & str)
|
||||||
|
{
|
||||||
|
char *newStr = new char[myLength + str.myLength + 1];
|
||||||
|
memcpy(newStr, myChars, myLength);
|
||||||
|
memcpy(newStr + myLength, str.myChars, str.myLength + 1);
|
||||||
|
delete[] myChars;
|
||||||
|
myChars = newStr;
|
||||||
|
myLength += str.myLength;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
string & string::operator+=(const char *cstring)
|
||||||
|
{
|
||||||
|
char *newStr = new char[myLength + strlen(cstring) + 1];
|
||||||
|
memcpy(newStr, myChars, myLength);
|
||||||
|
memcpy(newStr + myLength, cstring, strlen(cstring) + 1);
|
||||||
|
delete[] myChars;
|
||||||
|
myChars = newStr;
|
||||||
|
myLength += strlen(cstring);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
string & string::operator+=(char chr)
|
||||||
|
{
|
||||||
|
myLength++;
|
||||||
|
char *newStr = new char[myLength + 1];
|
||||||
|
memcpy(newStr, myChars, myLength);
|
||||||
|
newStr[myLength - 1] = chr;
|
||||||
|
newStr[myLength] = 0;
|
||||||
|
delete[] myChars;
|
||||||
|
myChars = newStr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
string string::operator+(const string & str)
|
||||||
|
{ return string(*this, str); }
|
||||||
|
|
||||||
|
string string::operator+(const char *cstring)
|
||||||
|
{ return string(*this, cstring); }
|
||||||
|
|
||||||
|
string string::operator+(char chr)
|
||||||
|
{ return string(*this, chr); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
string::string(const string & str1, const string & str2)
|
||||||
|
{
|
||||||
|
myLength = str1.myLength + str2.myLength;
|
||||||
|
myChars = new char[myLength + 1];
|
||||||
|
memcpy(myChars, str1.myChars, str1.myLength);
|
||||||
|
memcpy(myChars + str1.myLength, str2.myChars, str2.myLength + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
string::string(const string & str1, const char *cstring)
|
||||||
|
{
|
||||||
|
myLength = str1.myLength + strlen(cstring);
|
||||||
|
myChars = new char[myLength + 1];
|
||||||
|
memcpy(myChars, str1.myChars, str1.myLength);
|
||||||
|
memcpy(myChars + str1.myLength, cstring, strlen(cstring) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
string::string(const char *cstring, const string & str)
|
||||||
|
{
|
||||||
|
myLength = str.myLength + strlen(cstring);
|
||||||
|
myChars = new char[myLength + 1];
|
||||||
|
memcpy(myChars, cstring, strlen(cstring));
|
||||||
|
memcpy(myChars + strlen(cstring), str.myChars, str.myLength + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
string::string(const string & str1, char chr)
|
||||||
|
{
|
||||||
|
myLength = str1.myLength + 1;
|
||||||
|
myChars = new char[myLength + 1];
|
||||||
|
memcpy(myChars, str1.myChars, myLength);
|
||||||
|
myChars[myLength - 1] = chr;
|
||||||
|
myChars[myLength] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
string::string(char chr, const string & str1)
|
||||||
|
{
|
||||||
|
myLength = str1.myLength + 1;
|
||||||
|
myChars = new char[myLength + 1];
|
||||||
|
memcpy(myChars + 1, str1.myChars, myLength + 1);
|
||||||
|
*myChars = chr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char & string::operator[](unsigned int index) const
|
||||||
|
{
|
||||||
|
if (index < myLength)
|
||||||
|
return myChars[index];
|
||||||
|
return *myChars; //if index is invalid, return a pointer to the trailing 0
|
||||||
|
}
|
||||||
|
|
||||||
|
char & string::operator[](unsigned int index)
|
||||||
|
{
|
||||||
|
if (index < myLength)
|
||||||
|
return myChars[index];
|
||||||
|
return *myChars; //if index is invalid, return a pointer to the trailing 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool string::operator==(const string & second) const
|
||||||
|
{
|
||||||
|
if (myLength != second.myLength)
|
||||||
|
return false;
|
||||||
|
for (unsigned int i = 0; i < myLength; i++)
|
||||||
|
{
|
||||||
|
if (myChars[i] != second.myChars[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool string::operator==(const char *cstring) const
|
||||||
|
{
|
||||||
|
if (myLength != strlen(cstring))
|
||||||
|
return false;
|
||||||
|
for (unsigned int i = 0; i < myLength; i++)
|
||||||
|
{
|
||||||
|
if (myChars[i] != cstring[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool string::operator!=(const string & second) const
|
||||||
|
{ return !operator==(second); }
|
||||||
|
|
||||||
|
bool string::operator!=(const char *cstring) const
|
||||||
|
{ return !operator==(cstring); }
|
||||||
|
|
||||||
|
bool string::operator<(const string & second) const
|
||||||
|
{
|
||||||
|
char *c1 = myChars, *c2 = second.myChars;
|
||||||
|
while (*c1 == *c2 && *c1)
|
||||||
|
{
|
||||||
|
c1++;
|
||||||
|
c2++;
|
||||||
|
}
|
||||||
|
return *c1 < *c2;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool string::operator>(const string & second) const
|
||||||
|
{
|
||||||
|
char *c1 = myChars, *c2 = second.myChars;
|
||||||
|
while (*c1 == *c2 && *c1)
|
||||||
|
{
|
||||||
|
c1++;
|
||||||
|
c2++;
|
||||||
|
}
|
||||||
|
return *c1 > *c2;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool string::operator<(const char *cstring) const
|
||||||
|
{
|
||||||
|
char *c1 = myChars;
|
||||||
|
while (*c1 == *cstring && *c1)
|
||||||
|
{
|
||||||
|
c1++;
|
||||||
|
cstring++;
|
||||||
|
}
|
||||||
|
return *c1 < *cstring;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool string::operator>(const char *cstring) const
|
||||||
|
{
|
||||||
|
char *c1 = myChars;
|
||||||
|
while (*c1 == *cstring && *c1)
|
||||||
|
{
|
||||||
|
c1++;
|
||||||
|
cstring++;
|
||||||
|
}
|
||||||
|
return *c1 > *cstring;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool string::operator<=(const string & second) const
|
||||||
|
{ return !operator>(second); }
|
||||||
|
|
||||||
|
bool string::operator>=(const string & second) const
|
||||||
|
{ return !operator<(second); }
|
||||||
|
|
||||||
|
bool string::operator<=(const char *cstring) const
|
||||||
|
{ return operator<(cstring) || operator==(cstring); }
|
||||||
|
|
||||||
|
bool string::operator>=(const char *cstring) const
|
||||||
|
{ return operator>(cstring) || operator==(cstring); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
|
||||||
|
// string.h
|
||||||
|
// implements c++ string object for HOS
|
||||||
|
// Author: Josh Holtrop
|
||||||
|
// Date: 06/01/04
|
||||||
|
// Modified: 05/10/05
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __HOS_STRING__
|
||||||
|
#define __HOS_STRING__ __HOS_STRING__
|
||||||
|
|
||||||
|
class string
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/* myChars is a pointer to a character array
|
||||||
|
* It will always be a valid pointer, not null.
|
||||||
|
* The constructor is responsible for initializing
|
||||||
|
* it to point to a 1-char array with myChars[0] == 0 */
|
||||||
|
char * myChars;
|
||||||
|
|
||||||
|
/* myLength holds how many characters are in the
|
||||||
|
* string, not including the trailing null value
|
||||||
|
* (ASCII 0 character) */
|
||||||
|
unsigned int myLength;
|
||||||
|
public:
|
||||||
|
/* Basic constructors */
|
||||||
|
string();
|
||||||
|
~string();
|
||||||
|
|
||||||
|
/* Copy constructor */
|
||||||
|
string(const string & orig);
|
||||||
|
|
||||||
|
/* Construct strings from c-style strings:
|
||||||
|
* Allows declarations like string s = "data"; */
|
||||||
|
string(const char *cstring);
|
||||||
|
|
||||||
|
/* Assignment operators */
|
||||||
|
string & operator=(const string & orig);
|
||||||
|
string & operator=(const char *cstring);
|
||||||
|
|
||||||
|
/* Boolean comparison operators */
|
||||||
|
bool operator==(const string & second) const;
|
||||||
|
bool operator==(const char *cstring) const;
|
||||||
|
bool operator!=(const string & second) const;
|
||||||
|
bool operator!=(const char *cstring) const;
|
||||||
|
bool operator<(const string & second) const;
|
||||||
|
bool operator>(const string & second) const;
|
||||||
|
bool operator<(const char *cstring) const;
|
||||||
|
bool operator>(const char *cstring) const;
|
||||||
|
bool operator<=(const string & second) const;
|
||||||
|
bool operator>=(const string & second) const;
|
||||||
|
bool operator<=(const char *cstring) const;
|
||||||
|
bool operator>=(const char *cstring) const;
|
||||||
|
|
||||||
|
/* Construct strings made up of combinations of other
|
||||||
|
* strings, c-style strings, and characters */
|
||||||
|
string(const string & str1, const string & str2);
|
||||||
|
string(const string & str1, const char *cstring);
|
||||||
|
string(const char *cstring, const string & str);
|
||||||
|
string(const string & str1, char chr);
|
||||||
|
string(char chr, const string & str1);
|
||||||
|
|
||||||
|
/* Append operators */
|
||||||
|
string & operator+=(const string & str);
|
||||||
|
string & operator+=(const char *cstring);
|
||||||
|
string & operator+=(char chr);
|
||||||
|
|
||||||
|
string operator+(const string & str);
|
||||||
|
string operator+(const char *cstring);
|
||||||
|
string operator+(char chr);
|
||||||
|
|
||||||
|
/* Direct character-access operators */
|
||||||
|
const char & operator[](unsigned int index) const;
|
||||||
|
char & operator[](unsigned int index);
|
||||||
|
|
||||||
|
/* Returns handle to actual character-array for programs
|
||||||
|
* that need raw data instead of a string object */
|
||||||
|
char * data() const;
|
||||||
|
|
||||||
|
/* Returns the size of the string. This is myLength
|
||||||
|
* and is the number of characters in the string
|
||||||
|
* not counting the trailing null (ASCII 0) character */
|
||||||
|
int size() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static inline bool operator==(char *cstring, const string & str)
|
||||||
|
{ return str == cstring; }
|
||||||
|
|
||||||
|
static inline bool operator!=(char *cstring, const string & str)
|
||||||
|
{ return str != cstring; }
|
||||||
|
|
||||||
|
static inline bool operator<(const char *cstring, const string & str)
|
||||||
|
{ return str > cstring; }
|
||||||
|
|
||||||
|
static inline bool operator>(const char *cstring, const string & str)
|
||||||
|
{ return str < cstring; }
|
||||||
|
|
||||||
|
static inline bool operator<=(const char *cstring, const string & str)
|
||||||
|
{ return str >= cstring; }
|
||||||
|
|
||||||
|
static inline bool operator>=(const char *cstring, const string & str)
|
||||||
|
{ return str <= cstring; }
|
||||||
|
|
||||||
|
static inline string operator+(const char *cstring, const string & str)
|
||||||
|
{ return string(cstring, str); }
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
|
||||||
|
// vector.h
|
||||||
|
// implements c++ vector object for HOS
|
||||||
|
// Author: Josh Holtrop
|
||||||
|
// Date: 05/30/05
|
||||||
|
// Modified: 05/30/05
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __HOS_VECTOR__
|
||||||
|
#define __HOS_VECTOR__ __HOS_VECTOR__
|
||||||
|
|
||||||
|
#include "hos_defines.h"
|
||||||
|
|
||||||
|
template<typename type>
|
||||||
|
class vector
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
typedef type * type_ptr_t;
|
||||||
|
|
||||||
|
/* Pointers to vector elements */
|
||||||
|
type **myData;
|
||||||
|
|
||||||
|
/* How many elements are present */
|
||||||
|
unsigned int mySize;
|
||||||
|
|
||||||
|
/* How many elements there are pointers for */
|
||||||
|
unsigned int myAllocated;
|
||||||
|
|
||||||
|
/* Causes the vector to double in its allocated size */
|
||||||
|
void grow()
|
||||||
|
{
|
||||||
|
myAllocated <<= 1;
|
||||||
|
if (myAllocated == 0)
|
||||||
|
myAllocated = 1;
|
||||||
|
type **data_new = new type_ptr_t[myAllocated];
|
||||||
|
for (unsigned int i = 0; i < mySize; i++)
|
||||||
|
data_new[i] = myData[i];
|
||||||
|
if (myData)
|
||||||
|
delete[] myData;
|
||||||
|
myData = data_new;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/* Constructors/Destructor */
|
||||||
|
vector<type>()
|
||||||
|
{
|
||||||
|
myData = NULL;
|
||||||
|
mySize = 0;
|
||||||
|
myAllocated = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<type>(unsigned int size)
|
||||||
|
{
|
||||||
|
myData = new type_ptr_t[size];
|
||||||
|
mySize = 0;
|
||||||
|
myAllocated = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<type>(const vector<type> & v1)
|
||||||
|
{
|
||||||
|
mySize = v1.mySize;
|
||||||
|
myAllocated = v1.myAllocated;
|
||||||
|
myData = new type_ptr_t[myAllocated];
|
||||||
|
for (u32_t i = 0; i < mySize; i++)
|
||||||
|
myData[i] = new type(*v1.myData[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
~vector<type>()
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < mySize; i++)
|
||||||
|
delete myData[i];
|
||||||
|
delete[] myData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assignment operator */
|
||||||
|
vector<type> & operator=(const vector<type> & v1)
|
||||||
|
{
|
||||||
|
mySize = v1.mySize;
|
||||||
|
myAllocated = v1.myAllocated;
|
||||||
|
myData = new type_ptr_t[myAllocated];
|
||||||
|
for (u32_t i = 0; i < mySize; i++)
|
||||||
|
myData[i] = new type(*v1.myData[i]);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the size of the vector */
|
||||||
|
unsigned int size() const
|
||||||
|
{
|
||||||
|
return mySize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add an element to the end of the vector */
|
||||||
|
vector<type> & add(type elem)
|
||||||
|
{
|
||||||
|
while (mySize >= myAllocated)
|
||||||
|
grow();
|
||||||
|
myData[mySize++] = new type(elem);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove an element from the vector */
|
||||||
|
vector<type> & remove(unsigned int index)
|
||||||
|
{
|
||||||
|
if (index < mySize)
|
||||||
|
{
|
||||||
|
delete myData[index];
|
||||||
|
for (unsigned int i = index; i < (mySize - 1); i++)
|
||||||
|
myData[i] = myData[i+1];
|
||||||
|
mySize--;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert an element into a position in the vector */
|
||||||
|
vector<type> & insert(type elem, unsigned int position)
|
||||||
|
{
|
||||||
|
if (position <= mySize)
|
||||||
|
{
|
||||||
|
if (mySize >= myAllocated)
|
||||||
|
grow();
|
||||||
|
for (unsigned int i = mySize; i > position; i--)
|
||||||
|
myData[i] = myData[i-1];
|
||||||
|
myData[position] = new type(elem);
|
||||||
|
mySize++;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Direct access operators */
|
||||||
|
const type & operator[](unsigned int index) const
|
||||||
|
{
|
||||||
|
return *myData[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
type & operator[](unsigned int index)
|
||||||
|
{
|
||||||
|
return *myData[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns pointer to data */
|
||||||
|
type **data()
|
||||||
|
{
|
||||||
|
return myData;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -2,18 +2,22 @@ OUTPUT_FORMAT("binary")
|
|||||||
ENTRY(start)
|
ENTRY(start)
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
.text 0x100000 : {
|
.text 0xC0108000 : {
|
||||||
code = .; _code = .; __code = .;
|
code = .; _code = .; __code = .;
|
||||||
*(.text)
|
*(.text)
|
||||||
|
*(.eh_frame*)
|
||||||
|
}
|
||||||
|
.gnulinkonce : {
|
||||||
|
*(.gnu.linkonce*)
|
||||||
. = ALIGN(4096);
|
. = ALIGN(4096);
|
||||||
}
|
}
|
||||||
.data : {
|
.data : {
|
||||||
data = .; _data = .; __data = .;
|
data = .; _data = .; __data = .;
|
||||||
*(.data)
|
*(.data*)
|
||||||
|
*(.rodata*)
|
||||||
. = ALIGN(4096);
|
. = ALIGN(4096);
|
||||||
}
|
}
|
||||||
.bss :
|
.bss : {
|
||||||
{
|
|
||||||
bss = .; _bss = .; __bss = .;
|
bss = .; _bss = .; __bss = .;
|
||||||
*(.bss)
|
*(.bss)
|
||||||
. = ALIGN(4096);
|
. = ALIGN(4096);
|
||||||
+155
@@ -0,0 +1,155 @@
|
|||||||
|
// mm.c
|
||||||
|
// Author: Josh Holtrop
|
||||||
|
// Created: 09/01/03
|
||||||
|
// Modified: 08/19/04
|
||||||
|
|
||||||
|
#include "kernel.h"
|
||||||
|
#include "mm/mm.h"
|
||||||
|
#include "multiboot.h"
|
||||||
|
#include "hos_defines.h"
|
||||||
|
|
||||||
|
extern mb_info_t mb_info_block;
|
||||||
|
extern mb_mmap_t mb_mmap[MAX_MMAP];
|
||||||
|
extern u32_t mmap_entries;
|
||||||
|
extern mb_module_t mb_modules[MAX_MODULES];
|
||||||
|
|
||||||
|
u32_t mm_totalmem;
|
||||||
|
u32_t mm_megabytes;
|
||||||
|
u32_t mm_freepages;
|
||||||
|
u32_t mm_first_free_byte;
|
||||||
|
byte page_bitmap[MM_BITMAP_SIZE]; //used to store a bit for each page that is used, 0 if available
|
||||||
|
//0x20000*(8 bits/byte)=0x100000 pages in 4gb total
|
||||||
|
|
||||||
|
//This function initializes the memory manager's linked list, filling it with the
|
||||||
|
// memory areas returned by bios interrupt 0x8E20
|
||||||
|
void mm_init()
|
||||||
|
{
|
||||||
|
u32_t a;
|
||||||
|
for (a = 0; a < MM_BITMAP_SIZE; a++) //mark all pages used
|
||||||
|
{
|
||||||
|
page_bitmap[a] = 0xFF;
|
||||||
|
}
|
||||||
|
for (a = 0; a < mmap_entries; a++) //free BIOS #1 areas
|
||||||
|
{
|
||||||
|
if (mb_mmap[a].type == 1) // (1) mem free to OS
|
||||||
|
{
|
||||||
|
mm_totalmem += mb_mmap[a].length;
|
||||||
|
u32_t freethis = mb_mmap[a].base;
|
||||||
|
u32_t limit = mb_mmap[a].base + mb_mmap[a].length - 4096;
|
||||||
|
while (freethis <= limit)
|
||||||
|
{
|
||||||
|
if (freethis >= PHYS_LOAD) //above physical kernel load point
|
||||||
|
mm_pfree(freethis);
|
||||||
|
freethis += 4096;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mm_preserven(PHYS_LOAD, (((u32_t)&_end - (u32_t)&start) >> 12) + 1); //reserve kernel memory
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < mb_info_block.mods_count; i++) //reserve module memory
|
||||||
|
{
|
||||||
|
mm_preserven(mb_modules[i].mod_start - VIRT_OFFSET, (mb_modules[i].mod_end - mb_modules[i].mod_start + 4095) >> 12);
|
||||||
|
}
|
||||||
|
mm_megabytes = (mm_totalmem >> 20) + ((mm_totalmem % 0x100000) ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function frees a certain number of pages starting at the address
|
||||||
|
// specified in base for a length of pages pages
|
||||||
|
void mm_pfreen(u32_t base, u32_t pages)
|
||||||
|
{
|
||||||
|
//convert pages to max address
|
||||||
|
for (pages = base + (pages << 12); base < pages; base += 4096)
|
||||||
|
mm_pfree(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function frees a single page
|
||||||
|
void mm_pfree(u32_t base)
|
||||||
|
{
|
||||||
|
// u32_t pageNumber = base >> 12; // >>12 == /4096
|
||||||
|
u32_t byteNumber = base >> 15; //pageNumber >> 3; //pageNumber/8
|
||||||
|
u32_t bitNumber = (base >> 12) & 0x07; //pageNumber % 8;
|
||||||
|
page_bitmap[byteNumber] = page_bitmap[byteNumber] & ((0x01 << bitNumber) ^ 0xFF);
|
||||||
|
mm_freepages++;
|
||||||
|
if (byteNumber < mm_first_free_byte)
|
||||||
|
mm_first_free_byte = byteNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function reserves a certain number of pages starting at the address
|
||||||
|
// specified in base for a length of pages pages
|
||||||
|
void mm_preserven(u32_t base, u32_t pages)
|
||||||
|
{
|
||||||
|
//convert pages to max address
|
||||||
|
for (pages = base + (pages << 12); base < pages; base += 4096)
|
||||||
|
mm_preserve(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function reserves a single page
|
||||||
|
void mm_preserve(u32_t base)
|
||||||
|
{
|
||||||
|
// u32_t pageNumber = base >> 12; // >>12 == /4096
|
||||||
|
u32_t byteNumber = base >> 15; //pageNumber >> 3; //pageNumber/8
|
||||||
|
u32_t bitNumber = (base >> 12) & 0x07; //pageNumber % 8;
|
||||||
|
page_bitmap[byteNumber] = page_bitmap[byteNumber] | (0x01 << bitNumber);
|
||||||
|
mm_freepages--;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function allocates a single page, returning its physical address
|
||||||
|
u32_t mm_palloc()
|
||||||
|
{
|
||||||
|
u32_t bite;
|
||||||
|
for (bite = mm_first_free_byte; bite < MM_BITMAP_SIZE; bite++)
|
||||||
|
{
|
||||||
|
if (page_bitmap[bite] != 0xFF) //there is an available page within this 8-page region
|
||||||
|
{
|
||||||
|
int bit;
|
||||||
|
for (bit = 0; bit < 8; bit++)
|
||||||
|
{
|
||||||
|
if (!(page_bitmap[bite] & (1 << bit))) //this bite/bit combination is available
|
||||||
|
{
|
||||||
|
mm_first_free_byte = bite; //start searching from here next time
|
||||||
|
mm_freepages--;
|
||||||
|
page_bitmap[bite] = page_bitmap[bite] | (1 << bit); //set page as used
|
||||||
|
return ((bite << 15) | (bit << 12));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0; //no free page
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function reports the number of bytes of free physical memory
|
||||||
|
u32_t mm_getFreeMem()
|
||||||
|
{
|
||||||
|
return mm_freepages << 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
u32_t mm_getFreePages()
|
||||||
|
{
|
||||||
|
return mm_freepages;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
u32_t mm_getTotalMem()
|
||||||
|
{
|
||||||
|
return mm_totalmem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
u32_t mm_getTotalMegs()
|
||||||
|
{
|
||||||
|
return mm_megabytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
// mm.c
|
||||||
|
// Author: Josh Holtrop
|
||||||
|
// Created: 09/01/03
|
||||||
|
// Modified: 03/08/04
|
||||||
|
|
||||||
|
#ifndef __HOS_MM__
|
||||||
|
#define __HOS_MM__ __HOS_MM__
|
||||||
|
|
||||||
|
#include "kernel.h"
|
||||||
|
|
||||||
|
//The total amount of physical memory available (bytes, 1 bit per page)
|
||||||
|
#define MM_BITMAP_SIZE 0x20000
|
||||||
|
|
||||||
|
void mm_init();
|
||||||
|
void mm_pfreen(u32_t base, u32_t pages);
|
||||||
|
void mm_pfree(u32_t base);
|
||||||
|
void mm_preserven(u32_t base, u32_t pages);
|
||||||
|
void mm_preserve(u32_t base);
|
||||||
|
u32_t mm_palloc();
|
||||||
|
u32_t mm_getFreeMem();
|
||||||
|
u32_t mm_getFreePages();
|
||||||
|
u32_t mm_getTotalMem();
|
||||||
|
u32_t mm_getTotalMegs();
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+528
@@ -0,0 +1,528 @@
|
|||||||
|
// vmm.c
|
||||||
|
// Author: Josh Holtrop
|
||||||
|
// Date: 09/30/03
|
||||||
|
// Rewritten from scratch: 12/23/03
|
||||||
|
// Modified: 09/12/05
|
||||||
|
|
||||||
|
#include "hos_defines.h"
|
||||||
|
#include "kernel.h"
|
||||||
|
#include "mm/vmm.h"
|
||||||
|
#include "lang/lang.h"
|
||||||
|
#include "mm/mm.h"
|
||||||
|
|
||||||
|
int vmm_map_range(void *virt_start, void *virt_end, u32_t phys_start);
|
||||||
|
void *vmm_getFreeChunk(u32_t size);
|
||||||
|
void vmm_removeHeapEntry(u32_t queue, HeapEntry_t *he);
|
||||||
|
int vmm_moreCore(u32_t size);
|
||||||
|
int vmm_coalesceEntry(u32_t queue, HeapEntry_t *newHE);
|
||||||
|
void vmm_heb_init(HeapEntryBlock_t *heb);
|
||||||
|
void vmm_addToQueue(u32_t queue, HeapEntry_t *preceeding, HeapEntry_t *he);
|
||||||
|
int vmm_countHeapEntries(HeapEntry_t *he);
|
||||||
|
HeapEntry_t *vmm_followChain(HeapEntry_t *he);
|
||||||
|
HeapEntry_t *vmm_getUnusedEntry();
|
||||||
|
HeapEntry_t *vmm_stripUnusedEntry();
|
||||||
|
|
||||||
|
extern mb_info_t mb_info_block;
|
||||||
|
extern mb_module_t mb_modules[MAX_MODULES];
|
||||||
|
extern u32_t mm_freepages;
|
||||||
|
|
||||||
|
HeapEntryQueue_t heapEntryQueues[VMM_HE_TYPES]; // linked queues of HeapEntry objects
|
||||||
|
HeapEntry_t heapEntryHeadNodes[VMM_HE_TYPES]; // head nodes for linked queues
|
||||||
|
HeapEntry_t heapEntryTailNodes[VMM_HE_TYPES]; // tail nodes for linked queues
|
||||||
|
HeapEntryBlock_t initialHEB; // block for initial 256 HeapEntry objects
|
||||||
|
|
||||||
|
|
||||||
|
// This is the initialization procedure for the Virtual Memory Manager
|
||||||
|
// It sets up the heap for dynamic memory allocation and virtual page allocation
|
||||||
|
void vmm_init()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < mb_info_block.mods_count; i++) //page in the kernel modules
|
||||||
|
vmm_map_range((void*)mb_modules[i].mod_start, (void*)mb_modules[i].mod_end - 1, mb_modules[i].mod_start - VIRT_OFFSET);
|
||||||
|
for (i = 0; i < VMM_HE_TYPES; i++)
|
||||||
|
{
|
||||||
|
heapEntryQueues[i].count = 0;
|
||||||
|
heapEntryQueues[i].head = &heapEntryHeadNodes[i];
|
||||||
|
heapEntryHeadNodes[i].next = &heapEntryTailNodes[i];
|
||||||
|
heapEntryTailNodes[i].prev = &heapEntryHeadNodes[i];
|
||||||
|
}
|
||||||
|
vmm_heb_init(&initialHEB);
|
||||||
|
vmm_addToQueue(VMM_HE_UNUSED, &heapEntryHeadNodes[VMM_HE_UNUSED], &initialHEB.entry[0]);
|
||||||
|
HeapEntry_t *wilderness = vmm_stripUnusedEntry();
|
||||||
|
wilderness->base = (void *) HEAP_START;
|
||||||
|
wilderness->length = HEAP_LENGTH;
|
||||||
|
vmm_addToQueue(VMM_HE_HOLE, &heapEntryHeadNodes[VMM_HE_HOLE], wilderness);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Allocate a physical page and map the virtual address to it, return physical address allocated or NULL */
|
||||||
|
int vmm_map(void *virt)
|
||||||
|
{
|
||||||
|
u32_t dum;
|
||||||
|
return vmm_map_addr(virt, &dum);
|
||||||
|
}
|
||||||
|
|
||||||
|
int vmm_map_addr(void *virt, u32_t *phys_addr)
|
||||||
|
{
|
||||||
|
if (mm_freepages < 10)
|
||||||
|
return -1;
|
||||||
|
return vmm_map1((u32_t)virt, *phys_addr = mm_palloc());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function maps a virtual address to a physical address using the page directory / page table
|
||||||
|
int vmm_map1(u32_t virt, u32_t physical)
|
||||||
|
{
|
||||||
|
virt &= 0xFFFFF000;
|
||||||
|
physical &= 0xFFFFF000;
|
||||||
|
u32_t pde = virt >> 22;
|
||||||
|
u32_t pte = (virt & 0x003FF000) >> 12;
|
||||||
|
u32_t *pageTables = (u32_t *)0xFFFFF000; //this is the location of the page directory
|
||||||
|
if (!(pageTables[pde] & 0x01)) //the page directory entry is not present, we must allocate a page table
|
||||||
|
{
|
||||||
|
u32_t newpagetable;
|
||||||
|
if (!(newpagetable = mm_palloc()))
|
||||||
|
return -1; //out of physical memory
|
||||||
|
pageTables[pde] = newpagetable | 0x03;
|
||||||
|
invlpg_(0xFFFFF000 + (pde << 2));
|
||||||
|
invlpg_(virt); //in case it was cached, so we can fill page table safely
|
||||||
|
memsetd((void*)(0xFFC00000 | (pde << 12)), 0, 1024); //zero out new page table
|
||||||
|
}
|
||||||
|
*(u32_t *)(0xFFC00000 | (pde << 12) | (pte << 2)) = physical | 0x03;
|
||||||
|
invlpg_((0xFFC00000 | (pde << 12) | (pte << 2)));
|
||||||
|
invlpg_(virt);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function maps a variable number of pages in a row
|
||||||
|
int vmm_mapn(u32_t virt, u32_t physical, u32_t n)
|
||||||
|
{
|
||||||
|
while (n > 0)
|
||||||
|
{
|
||||||
|
if (vmm_map1(virt, physical))
|
||||||
|
return 1; // error mapping page
|
||||||
|
virt += 4096;
|
||||||
|
physical += 4096;
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function removes the virtual address's entry in the
|
||||||
|
// page directory / page table
|
||||||
|
void vmm_unmap1(u32_t virt)
|
||||||
|
{
|
||||||
|
*(u32_t *)(0xFFC00000 |
|
||||||
|
((virt & 0xFFC00000) >> 10) |
|
||||||
|
((virt & 0x003FF000) >> 10)) = 0;
|
||||||
|
invlpg_(virt);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function removes multiple pages' entries
|
||||||
|
void vmm_unmapn(u32_t virt, u32_t n)
|
||||||
|
{
|
||||||
|
while (n > 0)
|
||||||
|
{
|
||||||
|
vmm_unmap1(virt);
|
||||||
|
virt += 4096;
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function maps an entire address range into memory
|
||||||
|
int vmm_map_range(void *virt_start, void *virt_end, u32_t phys_start)
|
||||||
|
{
|
||||||
|
if (virt_end < virt_start)
|
||||||
|
return -1; // invalid region
|
||||||
|
while (virt_start < virt_end)
|
||||||
|
{
|
||||||
|
if (vmm_map1((u32_t)virt_start, phys_start))
|
||||||
|
return -2; // out of memory
|
||||||
|
virt_start += 4096;
|
||||||
|
phys_start += 4096;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// kernel virtual memory allocator
|
||||||
|
void *kmalloc(u32_t size)
|
||||||
|
{
|
||||||
|
k_enter_critical();
|
||||||
|
if (size % VMM_MALLOC_GRANULARITY)
|
||||||
|
size = size + VMM_MALLOC_GRANULARITY -
|
||||||
|
(size % VMM_MALLOC_GRANULARITY);
|
||||||
|
/* added 09/12/05 by josh - fixed bug returning size 0 segments
|
||||||
|
multiple times */
|
||||||
|
if (size < VMM_MALLOC_GRANULARITY)
|
||||||
|
size = VMM_MALLOC_GRANULARITY;
|
||||||
|
void *attempt = vmm_getFreeChunk(size);
|
||||||
|
if (attempt)
|
||||||
|
{
|
||||||
|
k_leave_critical();
|
||||||
|
return attempt;
|
||||||
|
}
|
||||||
|
if (vmm_moreCore(size))
|
||||||
|
{
|
||||||
|
k_leave_critical();
|
||||||
|
return NULL; //we could not get any more heap memory
|
||||||
|
}
|
||||||
|
attempt = vmm_getFreeChunk(size);
|
||||||
|
k_leave_critical();
|
||||||
|
return attempt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// kernel virtual memory de-allocator
|
||||||
|
int kfree(void *addr)
|
||||||
|
{
|
||||||
|
k_enter_critical();
|
||||||
|
HeapEntry_t *he = heapEntryQueues[VMM_HE_USED].head->next;
|
||||||
|
while (he->next)
|
||||||
|
{
|
||||||
|
if (he->base == addr)
|
||||||
|
{
|
||||||
|
vmm_removeHeapEntry(VMM_HE_USED, he);
|
||||||
|
if (vmm_coalesceEntry(VMM_HE_FREE, he))
|
||||||
|
vmm_addToQueue(VMM_HE_FREE, heapEntryQueues[VMM_HE_FREE].head, he);
|
||||||
|
else
|
||||||
|
vmm_addToQueue(VMM_HE_UNUSED, heapEntryQueues[VMM_HE_UNUSED].head, he);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
he = (HeapEntry_t *)he->next;
|
||||||
|
}
|
||||||
|
k_leave_critical();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function allocates a virtual page and maps it to a physical page
|
||||||
|
void *vmm_palloc()
|
||||||
|
{
|
||||||
|
u32_t dum;
|
||||||
|
return vmm_palloc_addr(&dum);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *vmm_palloc_addr(u32_t *phys_addr)
|
||||||
|
{
|
||||||
|
k_enter_critical();
|
||||||
|
HeapEntry_t *he = heapEntryQueues[VMM_HE_HOLE].head->next;
|
||||||
|
HeapEntry_t *wilderness = he;
|
||||||
|
while (he->next)
|
||||||
|
{
|
||||||
|
if (he->length == 4096)
|
||||||
|
{
|
||||||
|
vmm_removeHeapEntry(VMM_HE_HOLE, he);
|
||||||
|
vmm_addToQueue(VMM_HE_USED, &heapEntryHeadNodes[VMM_HE_USED], he);
|
||||||
|
if (vmm_map_addr(he->base, phys_addr))
|
||||||
|
he->base = NULL;
|
||||||
|
k_leave_critical();
|
||||||
|
return he->base;
|
||||||
|
}
|
||||||
|
if (he->length > wilderness->length)
|
||||||
|
wilderness = he;
|
||||||
|
he = (HeapEntry_t *)he->next;
|
||||||
|
}
|
||||||
|
if (wilderness->length < 0x00010000) //leave 16 pages free
|
||||||
|
{
|
||||||
|
k_leave_critical();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
wilderness->length -= 4096; //strip 4k from the top
|
||||||
|
he = vmm_getUnusedEntry();
|
||||||
|
he->base = wilderness->base + wilderness->length;
|
||||||
|
he->length = 4096;
|
||||||
|
vmm_addToQueue(VMM_HE_USED, &heapEntryHeadNodes[VMM_HE_USED], he);
|
||||||
|
if (vmm_map_addr(he->base, phys_addr))
|
||||||
|
he->base = NULL;
|
||||||
|
k_leave_critical();
|
||||||
|
return he->base;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function frees a previously-allocated virtual page
|
||||||
|
int vmm_pfree(void *addr)
|
||||||
|
{
|
||||||
|
u32_t pbase = *(u32_t *)(0xFFC00000 |
|
||||||
|
(((u32_t)addr & 0xFFC00000) >> 10) |
|
||||||
|
(((u32_t)addr & 0x003FF000) >> 10));
|
||||||
|
if (vmm_unmapp(addr))
|
||||||
|
return -1;
|
||||||
|
mm_pfree(pbase);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vmm_unmapp(void *addr)
|
||||||
|
{
|
||||||
|
if (!addr)
|
||||||
|
return -2;
|
||||||
|
k_enter_critical();
|
||||||
|
HeapEntry_t *he = heapEntryQueues[VMM_HE_USED].head->next;
|
||||||
|
while (he->next)
|
||||||
|
{
|
||||||
|
if (he->base == addr) //found the page to free
|
||||||
|
{
|
||||||
|
vmm_removeHeapEntry(VMM_HE_USED, he);
|
||||||
|
vmm_unmap1((u32_t)he->base);
|
||||||
|
vmm_addToQueue(VMM_HE_HOLE, &heapEntryHeadNodes[VMM_HE_HOLE], he);
|
||||||
|
k_leave_critical();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
he = he->next;
|
||||||
|
}
|
||||||
|
k_leave_critical();
|
||||||
|
return -1; // page not found
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function allocates and zeros memory for the given number of objects,
|
||||||
|
// given the size of each object
|
||||||
|
void *kcalloc(u32_t number, u32_t size)
|
||||||
|
{
|
||||||
|
void *mem = kmalloc(number * size);
|
||||||
|
if (!mem)
|
||||||
|
return NULL; //could not get memory
|
||||||
|
memset(mem, 0, number * size);
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function re-allocates memory already allocated, preserving the old contents
|
||||||
|
// (as long as newSize is greater than oldSize)
|
||||||
|
void *krealloc(void *orig, unsigned int newSize)
|
||||||
|
{
|
||||||
|
void *newMem;
|
||||||
|
if ((newMem = kmalloc(newSize)))
|
||||||
|
{
|
||||||
|
HeapEntry_t *he = heapEntryQueues[VMM_HE_USED].head->next;
|
||||||
|
while (he->next)
|
||||||
|
{
|
||||||
|
if (he->base == orig)
|
||||||
|
{
|
||||||
|
memcpy(newMem, orig, (he->length < newSize ? he->length : newSize));
|
||||||
|
kfree(orig);
|
||||||
|
return newMem;
|
||||||
|
}
|
||||||
|
he = (HeapEntry_t *)he->next;
|
||||||
|
}
|
||||||
|
kfree(newMem);
|
||||||
|
return NULL; // base address not found
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return NULL; // could not get mem for new chunk
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function returns the base address of a free chunk of virtual memory - called from kmalloc()
|
||||||
|
void *vmm_getFreeChunk(u32_t size)
|
||||||
|
{
|
||||||
|
HeapEntry_t *he = heapEntryQueues[VMM_HE_FREE].head->next;
|
||||||
|
HeapEntry_t *good = NULL;
|
||||||
|
while (he->next) // he is not the tail node
|
||||||
|
{
|
||||||
|
if (he->length == size)
|
||||||
|
{
|
||||||
|
vmm_removeHeapEntry(VMM_HE_FREE, he);
|
||||||
|
vmm_addToQueue(VMM_HE_USED, heapEntryQueues[VMM_HE_USED].head, he);
|
||||||
|
return he->base;
|
||||||
|
}
|
||||||
|
if (good)
|
||||||
|
{
|
||||||
|
if ((he->length > size) && (he->length < good->length))
|
||||||
|
good = he;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (he->length > size)
|
||||||
|
good = he;
|
||||||
|
}
|
||||||
|
he = (HeapEntry_t *)he->next;
|
||||||
|
}
|
||||||
|
if (!good)
|
||||||
|
return NULL;
|
||||||
|
HeapEntry_t *newHE = vmm_getUnusedEntry();
|
||||||
|
newHE->base = good->base;
|
||||||
|
newHE->length = size;
|
||||||
|
newHE->next = NULL;
|
||||||
|
newHE->prev = NULL;
|
||||||
|
good->base += size;
|
||||||
|
good->length -= size;
|
||||||
|
vmm_addToQueue(VMM_HE_USED, heapEntryQueues[VMM_HE_USED].head, newHE);
|
||||||
|
return newHE->base;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function retrieves more core memory for the virtual memory allocator to allocate
|
||||||
|
int vmm_moreCore(u32_t size)
|
||||||
|
{
|
||||||
|
int pages = (size >> 12) + 2;
|
||||||
|
size = pages << 12;
|
||||||
|
if ((mm_freepages - 5) < pages)
|
||||||
|
return -1; // out of physical memory
|
||||||
|
HeapEntry_t *he = heapEntryQueues[VMM_HE_HOLE].head->next;
|
||||||
|
HeapEntry_t *wilderness = he;
|
||||||
|
while (he->next)
|
||||||
|
{
|
||||||
|
if (he->length > wilderness->length)
|
||||||
|
wilderness = he;
|
||||||
|
he = (HeapEntry_t *)he->next;
|
||||||
|
}
|
||||||
|
if (wilderness->length <= size)
|
||||||
|
return -2; // out of virtual memory
|
||||||
|
int i;
|
||||||
|
void *virt = wilderness->base;
|
||||||
|
for (i = 0; i < pages; i++)
|
||||||
|
{
|
||||||
|
vmm_map(virt);
|
||||||
|
virt += 4096;
|
||||||
|
}
|
||||||
|
HeapEntry_t *newHE = vmm_getUnusedEntry();
|
||||||
|
newHE->base = wilderness->base;
|
||||||
|
newHE->length = size;
|
||||||
|
newHE->next = 0;
|
||||||
|
newHE->prev = 0;
|
||||||
|
wilderness->base += size;
|
||||||
|
wilderness->length -= size;
|
||||||
|
if (vmm_coalesceEntry(VMM_HE_FREE, newHE)) // returns 0 on success (coalesced into previous entry)
|
||||||
|
vmm_addToQueue(VMM_HE_FREE, heapEntryQueues[VMM_HE_FREE].head, newHE);
|
||||||
|
else
|
||||||
|
vmm_addToQueue(VMM_HE_UNUSED, heapEntryQueues[VMM_HE_UNUSED].head, newHE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function coalesces to heap entries into one
|
||||||
|
int vmm_coalesceEntry(u32_t queue, HeapEntry_t *newHE)
|
||||||
|
{
|
||||||
|
HeapEntry_t *existing = heapEntryQueues[queue].head->next;
|
||||||
|
while (existing->next)
|
||||||
|
{
|
||||||
|
if ((existing->base + existing->length) == newHE->base)
|
||||||
|
{
|
||||||
|
existing->length += newHE->length;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if ((newHE->base + newHE->length) == existing->base)
|
||||||
|
{
|
||||||
|
existing->base = newHE->base;
|
||||||
|
existing->length += newHE->length;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
existing = (HeapEntry_t *)existing->next;
|
||||||
|
}
|
||||||
|
return -1; // an entry to coalesce with was not found
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function removes a heap entry from a queue
|
||||||
|
void vmm_removeHeapEntry(u32_t queue, HeapEntry_t *he)
|
||||||
|
{
|
||||||
|
((HeapEntry_t *)he->prev)->next = he->next;
|
||||||
|
((HeapEntry_t *)he->next)->prev = he->prev;
|
||||||
|
heapEntryQueues[queue].count--;
|
||||||
|
he->next = NULL;
|
||||||
|
he->prev = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function initialzes a Heap Entry Block to entries linked together
|
||||||
|
void vmm_heb_init(HeapEntryBlock_t *heb)
|
||||||
|
{
|
||||||
|
int a;
|
||||||
|
for (a = 0; a < 255; a++)
|
||||||
|
{
|
||||||
|
heb->entry[a].next = &heb->entry[a+1];
|
||||||
|
heb->entry[a+1].prev = &heb->entry[a];
|
||||||
|
}
|
||||||
|
heb->entry[0].prev = NULL;
|
||||||
|
heb->entry[255].next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function adds a HeapEntry structure to the queue following 'preceeding' the queue
|
||||||
|
// fails if add to tail (add one element before tail node)
|
||||||
|
void vmm_addToQueue(u32_t queue, HeapEntry_t *preceeding, HeapEntry_t *he)
|
||||||
|
{
|
||||||
|
heapEntryQueues[queue].count += vmm_countHeapEntries(he);
|
||||||
|
HeapEntry_t *last = vmm_followChain(he);
|
||||||
|
last->next = preceeding->next;
|
||||||
|
he->prev = preceeding;
|
||||||
|
((HeapEntry_t *)last->next)->prev = last;
|
||||||
|
preceeding->next = he;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function returns how many HeapEntry objects are in a queue starting/including from the object given
|
||||||
|
int vmm_countHeapEntries(HeapEntry_t *he)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
while (he)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
he = (HeapEntry_t *)he->next;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function follows a chain of HeapEntry objects and returns a pointer to the last one
|
||||||
|
HeapEntry_t *vmm_followChain(HeapEntry_t *he)
|
||||||
|
{
|
||||||
|
while (he->next)
|
||||||
|
he = (HeapEntry_t *)he->next;
|
||||||
|
return he;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function breaks an unused chunk from its queue and returns a pointer to it
|
||||||
|
// 09/10/05 nasty bug fixed by josh, wasn't adding unused entries when we ran out of them
|
||||||
|
HeapEntry_t *vmm_getUnusedEntry()
|
||||||
|
{
|
||||||
|
if (heapEntryQueues[VMM_HE_UNUSED].count < 5)
|
||||||
|
{
|
||||||
|
HeapEntry_t *he = heapEntryQueues[VMM_HE_HOLE].head->next;
|
||||||
|
HeapEntry_t *wilderness = he;
|
||||||
|
while (he)
|
||||||
|
{
|
||||||
|
if ((he->length) > (wilderness->length))
|
||||||
|
wilderness = he;
|
||||||
|
he = (HeapEntry_t *)he->next;
|
||||||
|
}
|
||||||
|
if (wilderness->length < 10000)
|
||||||
|
{
|
||||||
|
k_check(-1, "Kernel panic: out of virtual memory\n");
|
||||||
|
}
|
||||||
|
wilderness->length -= 4096; //strip 4k from the top
|
||||||
|
HeapEntryBlock_t *newHEB = wilderness->base + wilderness->length;
|
||||||
|
vmm_map(newHEB);
|
||||||
|
vmm_heb_init(newHEB);
|
||||||
|
vmm_addToQueue(VMM_HE_UNUSED, heapEntryTailNodes[VMM_HE_UNUSED].prev, &newHEB->entry[0]);
|
||||||
|
}
|
||||||
|
return vmm_stripUnusedEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Return pointer to an unused HeapEntry object, ASSUMES THERE IS ONE PRESENT IN QUEUE
|
||||||
|
HeapEntry_t *vmm_stripUnusedEntry()
|
||||||
|
{
|
||||||
|
HeapEntry_t *he = heapEntryQueues[VMM_HE_UNUSED].head->next;
|
||||||
|
heapEntryQueues[VMM_HE_UNUSED].head->next = he->next;
|
||||||
|
if (! he->next)
|
||||||
|
k_check(1, "kernel panic: he->next is NULL\n");
|
||||||
|
((HeapEntry_t *)he->next)->prev = he->prev;
|
||||||
|
heapEntryQueues[VMM_HE_UNUSED].count--;
|
||||||
|
he->next = 0;
|
||||||
|
he->prev = 0;
|
||||||
|
return he;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
// vmm.h
|
||||||
|
// Author: Josh Holtrop
|
||||||
|
// Date: 09/30/03
|
||||||
|
// Rewritten from scratch: 12/23/03, 07/13/04
|
||||||
|
// Modified: 08/28/04
|
||||||
|
|
||||||
|
#ifndef __HOS_VMM__
|
||||||
|
#define __HOS_VMM__ __HOS_VMM__
|
||||||
|
|
||||||
|
#include "hos_defines.h"
|
||||||
|
#include "multiboot.h"
|
||||||
|
|
||||||
|
#define VMM_HE_TYPES 4 //4 types of heap entries
|
||||||
|
#define VMM_HE_UNUSED 0 //available entry
|
||||||
|
#define VMM_HE_FREE 1 //free section of memory
|
||||||
|
#define VMM_HE_USED 2 //used section of memory
|
||||||
|
#define VMM_HE_HOLE 3 //a "hole" (unmapped/wilderness) section of virtual memory
|
||||||
|
|
||||||
|
#define VMM_MALLOC_GRANULARITY 4 //a power of 2, granularity for all memory requests
|
||||||
|
#define VMM_MALLOC_GRAN_MASK VMM_MALLOC_GRANULARITY-1 //mask for determining how much of a request is past granularity
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void *base; //virtual base address
|
||||||
|
u32_t length; //size in bytes
|
||||||
|
void *next; //link to next HeapEntry
|
||||||
|
void *prev; //link to previous HeapEntry
|
||||||
|
} __attribute__((packed)) HeapEntry_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
HeapEntry_t entry[256]; //256 HeapEntry objects = 4kb (1 page)
|
||||||
|
} __attribute__((packed)) HeapEntryBlock_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int count;
|
||||||
|
HeapEntry_t *head;
|
||||||
|
} HeapEntryQueue_t;
|
||||||
|
|
||||||
|
|
||||||
|
void vmm_init();
|
||||||
|
void *kmalloc(u32_t size);
|
||||||
|
int kfree(void *addr);
|
||||||
|
int vmm_unmapp(void *addr);
|
||||||
|
void *vmm_palloc();
|
||||||
|
void *vmm_palloc_addr(u32_t *phys_addr);
|
||||||
|
int vmm_pfree(void *addr);
|
||||||
|
void *kcalloc(unsigned int number, unsigned int size);
|
||||||
|
|
||||||
|
int vmm_map(void *virt);
|
||||||
|
int vmm_map_addr(void *virt, u32_t *phys_addr);
|
||||||
|
int vmm_map1(unsigned int virt, unsigned int physical);
|
||||||
|
int vmm_mapn(unsigned int virt, unsigned int physical, unsigned int n);
|
||||||
|
void vmm_unmap1(unsigned int virt);
|
||||||
|
void vmm_unmapn(unsigned int virt, unsigned int n);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
#ifndef __HOS_MODULE_H__
|
||||||
|
#define __HOS_MODULE_H__ __HOS_MODULE_H__
|
||||||
|
|
||||||
|
#define MOD_INITRD 0
|
||||||
|
#define MOD_REAL_MODE 1
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned int mod_magic; // "HOSM" = dword value 0x4D534F48
|
||||||
|
unsigned int mod_type; // module type
|
||||||
|
void (*init) (); // address of void initialization function
|
||||||
|
unsigned int reserved;
|
||||||
|
} hos_module_header_t;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
|
||||||
|
#ifndef __HOS_MULTIBOOT_H__
|
||||||
|
#define __HOS_MULTIBOOT_H__ __HOS_MULTIBOOT_H__
|
||||||
|
|
||||||
|
#include "hos_defines.h"
|
||||||
|
|
||||||
|
/* The magic number for the Multiboot header. */
|
||||||
|
#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
|
||||||
|
|
||||||
|
#define MB_HEADER_ALIGN_MODULES 0x01
|
||||||
|
#define MB_HEADER_MEM_INFO 0x02
|
||||||
|
#define MB_HEADER_VIDEO_INFO 0x04
|
||||||
|
#define MB_HEADER_KLUDGE_OFFSETS 0x10000
|
||||||
|
|
||||||
|
/* The magic number passed by a Multiboot-compliant boot loader. */
|
||||||
|
#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
|
||||||
|
|
||||||
|
#define MB_BOOTLOADER_MEM_INFO 0x01
|
||||||
|
#define MB_BOOTLOADER_BOOT_DEVICE 0x02
|
||||||
|
#define MB_BOOTLOADER_COMMAND_LINE 0x04
|
||||||
|
#define MB_BOOTLOADER_MODS 0x08
|
||||||
|
#define MB_BOOTLOADER_AOUT 0x10
|
||||||
|
#define MB_BOOTLOADER_ELF 0x20
|
||||||
|
#define MB_BOOTLOADER_MMAP 0x40
|
||||||
|
#define MB_BOOTLOADER_DRIVES 0x80
|
||||||
|
#define MB_BOOTLOADER_CONFIG 0x0100
|
||||||
|
#define MB_BOOTLOADER_APM 0x0200
|
||||||
|
#define MB_BOOTLOADER_GRAPHICS 0x0400
|
||||||
|
|
||||||
|
#define MB_DRIVE_MODE_CHS 0
|
||||||
|
#define MB_DRIVE_MODE_LBA 1
|
||||||
|
|
||||||
|
/* The Multiboot header. */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned int magic;
|
||||||
|
unsigned int flags;
|
||||||
|
unsigned int checksum;
|
||||||
|
unsigned int header_addr;
|
||||||
|
unsigned int load_addr;
|
||||||
|
unsigned int load_end_addr;
|
||||||
|
unsigned int bss_end_addr;
|
||||||
|
unsigned int entry_addr;
|
||||||
|
} mb_header_t;
|
||||||
|
|
||||||
|
/* The symbol table for a.out. */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned int tabsize;
|
||||||
|
unsigned int strsize;
|
||||||
|
unsigned int addr;
|
||||||
|
unsigned int reserved;
|
||||||
|
} mb_aout_symbol_table_t;
|
||||||
|
|
||||||
|
/* The section header table for ELF. */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned int num;
|
||||||
|
unsigned int size;
|
||||||
|
unsigned int addr;
|
||||||
|
unsigned int shndx;
|
||||||
|
} mb_elf_section_header_table_t;
|
||||||
|
|
||||||
|
/* The Multiboot information. */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned int flags;
|
||||||
|
unsigned int mem_lower; // present if flags[0] is set
|
||||||
|
unsigned int mem_upper;
|
||||||
|
unsigned int boot_device; // 1
|
||||||
|
unsigned int cmdline; // 2
|
||||||
|
unsigned int mods_count; // 3
|
||||||
|
unsigned int mods_addr;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
mb_aout_symbol_table_t aout_sym; // 4
|
||||||
|
mb_elf_section_header_table_t elf_sec; // 5
|
||||||
|
};
|
||||||
|
unsigned int mmap_length; // 6
|
||||||
|
unsigned int mmap_addr;
|
||||||
|
unsigned int drives_length; // 7
|
||||||
|
unsigned int drives_addr;
|
||||||
|
unsigned int config_table; // 8
|
||||||
|
unsigned int bootloader_name; // 9
|
||||||
|
unsigned int apm_table; // 10
|
||||||
|
|
||||||
|
unsigned int vbe_control_info; // 11
|
||||||
|
unsigned int vbe_mode_info;
|
||||||
|
unsigned short vbe_mode;
|
||||||
|
unsigned short vbe_interface_seg;
|
||||||
|
unsigned short vbe_interface_off;
|
||||||
|
unsigned short vbe_interface_len;
|
||||||
|
} mb_info_t;
|
||||||
|
|
||||||
|
/* The module structure. */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned int mod_start;
|
||||||
|
unsigned int mod_end;
|
||||||
|
unsigned int string;
|
||||||
|
unsigned int reserved;
|
||||||
|
} mb_module_t;
|
||||||
|
|
||||||
|
/* The memory map. Be careful that the offset 0 is base_addr_low, not size. */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned int size; //offset -4
|
||||||
|
// unsigned int base_addr_low; //offset 0
|
||||||
|
// unsigned int base_addr_high;
|
||||||
|
// unsigned int length_low;
|
||||||
|
// unsigned int length_high;
|
||||||
|
u64_t base;
|
||||||
|
u64_t length;
|
||||||
|
unsigned int type;
|
||||||
|
} mb_mmap_t;
|
||||||
|
|
||||||
|
/* The drive structure */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned int size;
|
||||||
|
unsigned char drive_number;
|
||||||
|
unsigned char drive_mode;
|
||||||
|
unsigned char drive_cylinders;
|
||||||
|
unsigned char drive_heads;
|
||||||
|
unsigned char drive_sectors;
|
||||||
|
unsigned short drive_ports[1];
|
||||||
|
} mb_drive_t;
|
||||||
|
|
||||||
|
/* APM table structure */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned short version;
|
||||||
|
unsigned short cseg;
|
||||||
|
unsigned int offset;
|
||||||
|
unsigned short cseg_16;
|
||||||
|
unsigned short dseg;
|
||||||
|
unsigned short flags;
|
||||||
|
unsigned short cseg_len;
|
||||||
|
unsigned short cseg_16_len;
|
||||||
|
unsigned short dseg_len;
|
||||||
|
} mb_apm_t;
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
// hash.cpp
|
||||||
|
// Author: Josh Holtrop
|
||||||
|
// Date: 08/28/05
|
||||||
|
// Modified: 08/28/05
|
||||||
|
// Implements a basic hash table (u32_t -> void*)
|
||||||
|
|
||||||
|
#include "hos_defines.h"
|
||||||
|
#include "hash.h"
|
||||||
|
#include "lang/vector.h"
|
||||||
|
|
||||||
|
extern "C"{
|
||||||
|
#include "display/kout.h"
|
||||||
|
#include "mm/vmm.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hash Primes come from
|
||||||
|
* http://planetmath.org/encyclopedia/GoodHashTablePrimes.html
|
||||||
|
*/
|
||||||
|
const u32_t hash_primes[] =
|
||||||
|
{53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317,
|
||||||
|
196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843,
|
||||||
|
50331653, 100663319, 201326611, 402653189, 805306457, 1610612741};
|
||||||
|
|
||||||
|
hash::hash()
|
||||||
|
{
|
||||||
|
mySizeIndex = 0;
|
||||||
|
mySize = 0;
|
||||||
|
for (u32_t i = 0; i < hash_primes[mySizeIndex]; i++)
|
||||||
|
myTable.add(vector<hash_entry_t>());
|
||||||
|
}
|
||||||
|
|
||||||
|
int hash::add(u32_t key, void *val)
|
||||||
|
{
|
||||||
|
u32_t hashed = hash_key(key);
|
||||||
|
for (u32_t i = 0; i < myTable[hashed].size(); i++)
|
||||||
|
if ( myTable[hashed][i].key == key )
|
||||||
|
return -1; // key exists already
|
||||||
|
hash_entry_t he = {key, val};
|
||||||
|
myTable[hashed].add(he);
|
||||||
|
mySize++;
|
||||||
|
if ( mySize > (hash_primes[mySizeIndex] << 1) ) // re-hash
|
||||||
|
{
|
||||||
|
vector< vector<hash_entry_t> > oldTable = myTable;
|
||||||
|
mySizeIndex++;
|
||||||
|
myTable = vector< vector<hash_entry_t> >();
|
||||||
|
for (u32_t i = 0; i < hash_primes[mySizeIndex]; i++)
|
||||||
|
myTable.add(vector<hash_entry_t>());
|
||||||
|
mySize = 0;
|
||||||
|
for (u32_t i = 0; i < hash_primes[mySizeIndex - 1]; i++)
|
||||||
|
{
|
||||||
|
for (u32_t j = 0; j < oldTable[i].size(); j++)
|
||||||
|
{
|
||||||
|
add( oldTable[i][j].key,
|
||||||
|
oldTable[i][j].data );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *hash::get(u32_t key)
|
||||||
|
{
|
||||||
|
u32_t hashed = hash_key(key);
|
||||||
|
for (u32_t i = 0; i < myTable[hashed].size(); i++)
|
||||||
|
if ( myTable[hashed][i].key == key )
|
||||||
|
return myTable[hashed][i].data;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hash::remove(u32_t key)
|
||||||
|
{
|
||||||
|
u32_t hashed = hash_key(key);
|
||||||
|
for (u32_t i = 0; i < myTable[hashed].size(); i++)
|
||||||
|
if ( myTable[hashed][i].key == key )
|
||||||
|
{
|
||||||
|
myTable[hashed].remove(i); // remove key
|
||||||
|
mySize--;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hash::exists(u32_t key)
|
||||||
|
{
|
||||||
|
u32_t hashed = hash_key(key);
|
||||||
|
for (u32_t i = 0; i < myTable[hashed].size(); i++)
|
||||||
|
if ( myTable[hashed][i].key == key )
|
||||||
|
return 1; // key exists
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32_t hash::hash_key(u32_t key)
|
||||||
|
{
|
||||||
|
return ((key * 11) + mySizeIndex) % hash_primes[mySizeIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
u32_t hash::size()
|
||||||
|
{
|
||||||
|
return mySize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hash::dump()
|
||||||
|
{
|
||||||
|
kprintf("hash table @ 0x%x : {\n", &myTable);
|
||||||
|
for (u32_t i = 0; i < hash_primes[mySizeIndex]; i++)
|
||||||
|
{
|
||||||
|
kprintf("\t%d @ 0x%x (", i, &myTable[i]);
|
||||||
|
for (u32_t j = 0; j < myTable[i].size(); j++)
|
||||||
|
kprintf("%s%d -> %d @ 0x%x", (j ? ", " : ""),
|
||||||
|
myTable[i][j].key,
|
||||||
|
myTable[i][j].data,
|
||||||
|
&myTable[i][j]);
|
||||||
|
kprintf(")\n");
|
||||||
|
}
|
||||||
|
kprintf("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
Loaded 100 of 142 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user