Compare commits
No commits in common. "master" and "v0.16" have entirely different histories.
43
.bochsrc
Normal file
43
.bochsrc
Normal file
@ -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
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
.rscons*
|
||||
/i686-elf-gcc/
|
||||
/build/
|
88
Makefile
Normal file
88
Makefile
Normal file
@ -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
|
||||
|
166
Rsconscript
166
Rsconscript
@ -1,166 +0,0 @@
|
||||
path_prepend "i686-elf-gcc/bin"
|
||||
|
||||
configure do
|
||||
rscons "i686-elf-gcc.rb", "-b", "#{build_dir}/i686-elf-gcc"
|
||||
check_c_compiler "i686-elf-gcc"
|
||||
check_program "genext2fs"
|
||||
check_program "grub-mkstandalone"
|
||||
check_program "mformat", on_fail: "Install the mtools package"
|
||||
check_program "xorriso"
|
||||
check_cfg package: "freetype2", on_fail: "Install libfreetype-dev", use: "freetype"
|
||||
end
|
||||
|
||||
require "tmpdir"
|
||||
|
||||
# EFI (w/ GRUB) partition size (MiB)
|
||||
EFI_PART_SIZE = 8
|
||||
# HOS partition size (MiB)
|
||||
HOS_PART_SIZE = 4
|
||||
# Kernel default font size
|
||||
KFONT_SIZE = 15
|
||||
|
||||
class BiosImage < Builder
|
||||
def run(options)
|
||||
unless @cache.up_to_date?(@target, nil, @sources, @env)
|
||||
print_run_message("Generating BIOS boot image #{@target}", nil)
|
||||
Dir.mktmpdir do |tmpdir|
|
||||
# Create iso directory.
|
||||
FileUtils.mkdir_p("#{tmpdir}/iso/boot/grub")
|
||||
File.open("#{tmpdir}/iso/boot/grub/grub.cfg", "wb") do |fh|
|
||||
fh.write(<<EOF)
|
||||
set default="0"
|
||||
set timeout=1
|
||||
menuentry "HOS" {
|
||||
insmod multiboot2
|
||||
multiboot2 /hos.elf
|
||||
}
|
||||
EOF
|
||||
end
|
||||
@sources.each do |source|
|
||||
FileUtils.cp(source, "#{tmpdir}/iso")
|
||||
end
|
||||
# Build bootable GRUB image.
|
||||
system(*%W[grub-mkrescue -o #{@target} #{tmpdir}/iso], err: "#{@env.build_root}/grub-mkrescue.log")
|
||||
end
|
||||
@cache.register_build(@target, nil, @sources, @env)
|
||||
end
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
class EfiImage < Builder
|
||||
def run(options)
|
||||
unless @cache.up_to_date?(@target, nil, @sources, @env)
|
||||
print_run_message("Generating EFI boot image #{@target}", nil)
|
||||
Dir.mktmpdir do |tmpdir|
|
||||
# Build a standalone GRUB.
|
||||
File.open("#{tmpdir}/grub.cfg", "wb") do |fh|
|
||||
fh.write(<<EOF)
|
||||
insmod part_gpt
|
||||
configfile (hd0,gpt2)/grub.cfg
|
||||
EOF
|
||||
end
|
||||
system(*%W[grub-mkstandalone -O x86_64-efi -o #{tmpdir}/BOOTX64.EFI boot/grub/grub.cfg=#{tmpdir}/grub.cfg])
|
||||
# Create EFI partition.
|
||||
system(*%W[dd if=/dev/zero of=#{tmpdir}/efi.part bs=1M count=#{EFI_PART_SIZE}], err: "/dev/null")
|
||||
system(*%W[mformat -i #{tmpdir}/efi.part ::])
|
||||
system(*%W[mmd -i #{tmpdir}/efi.part ::/EFI])
|
||||
system(*%W[mmd -i #{tmpdir}/efi.part ::/EFI/BOOT])
|
||||
system(*%W[mcopy -i #{tmpdir}/efi.part #{tmpdir}/BOOTX64.EFI ::/EFI/BOOT])
|
||||
# Create ext2 HOS partition.
|
||||
FileUtils.mkdir_p("#{tmpdir}/ext2")
|
||||
@sources.each do |source|
|
||||
FileUtils.cp(source, "#{tmpdir}/ext2")
|
||||
end
|
||||
File.open("#{tmpdir}/ext2/grub.cfg", "wb") do |fh|
|
||||
fh.write(<<EOF)
|
||||
set default="0"
|
||||
set timeout=1
|
||||
menuentry "HOS" {
|
||||
insmod part_gpt
|
||||
insmod multiboot2
|
||||
set root=(hd0,gpt2)
|
||||
multiboot2 /hos.elf
|
||||
}
|
||||
EOF
|
||||
end
|
||||
system(*%W[genext2fs -b #{HOS_PART_SIZE * 1024} -d #{tmpdir}/ext2 #{tmpdir}/ext2.part])
|
||||
# Create full disk image.
|
||||
system(*%W[dd if=/dev/zero of=#{@target} bs=1M count=#{EFI_PART_SIZE + HOS_PART_SIZE + 2}], err: "/dev/null")
|
||||
system(*%W[parted -s #{@target} mklabel gpt])
|
||||
system(*%W[parted -s #{@target} mkpart efi 1MiB #{EFI_PART_SIZE + 1}MiB])
|
||||
system(*%W[parted -s #{@target} mkpart hos #{EFI_PART_SIZE + 1}MiB #{EFI_PART_SIZE + HOS_PART_SIZE + 1}MiB])
|
||||
system(*%W[dd if=#{tmpdir}/efi.part of=#{@target} bs=1M seek=1 conv=notrunc], err: "/dev/null")
|
||||
system(*%W[dd if=#{tmpdir}/ext2.part of=#{@target} bs=1M seek=#{1 + EFI_PART_SIZE} conv=notrunc], err: "/dev/null")
|
||||
end
|
||||
@cache.register_build(@target, nil, @sources, @env)
|
||||
end
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
class FontGen < Builder
|
||||
def run(options)
|
||||
if @command
|
||||
finalize_command
|
||||
else
|
||||
fontgen = @vars["fontgen"]
|
||||
@sources += [fontgen]
|
||||
command = %W[#{fontgen} #{@sources.first} #{KFONT_SIZE} #{@target}]
|
||||
standard_command("FontGen <target>#{@target}<reset>", command, {})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Size < Builder
|
||||
def run(options)
|
||||
if @command
|
||||
finalize_command
|
||||
else
|
||||
@vars["_SOURCES"] = @sources
|
||||
@vars["_TARGET"] = @target
|
||||
command = @env.build_command(%w[${SIZE} ${_SOURCES}], @vars)
|
||||
standard_command("Size <target>#{@target}<reset>", command, stdout: @target)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# FontGen Environment
|
||||
fontgen_env = env "fontgen", use: "freetype" do |env|
|
||||
env["CC"] = "gcc"
|
||||
env.Program("^/fontgen.bin", glob("fontgen/**/*.c"))
|
||||
end
|
||||
|
||||
# Kernel Environment
|
||||
kernel_env = env "kernel" do |env|
|
||||
env.add_builder(EfiImage)
|
||||
env.add_builder(BiosImage)
|
||||
env.add_builder(FontGen)
|
||||
env.add_builder(Size)
|
||||
env["OBJDUMP"] = "i686-elf-objdump"
|
||||
env["SIZE"] = "i686-elf-size"
|
||||
env["CCFLAGS"] += %w[-ffreestanding -Wall -O2]
|
||||
env["LDFLAGS"] += %w[-ffreestanding -nostdlib -T src/link.ld]
|
||||
env["LDFLAGS"] += %W[-Wl,-Map,${_TARGET}.map]
|
||||
env["LIBS"] += %w[gcc]
|
||||
env.FontGen("^/kfont/kfont.c", "font/Hack-Regular.ttf",
|
||||
"fontgen" => fontgen_env.expand("^/fontgen.bin"))
|
||||
env.barrier
|
||||
env["CPPPATH"] += ["#{env.build_root}/kfont"]
|
||||
env.Program("^/hos.elf", glob("src/**/*.{S,c}") + ["^/kfont/kfont.c"])
|
||||
env.depends("#{env.build_root}/hos.elf", "src/link.ld")
|
||||
env.Disassemble("^/hos.elf.txt", "^/hos.elf")
|
||||
env.Size("^/hos.elf.size", "^/hos.elf")
|
||||
env.EfiImage("^/hos-efi.img", %w[^/hos.elf])
|
||||
env.BiosImage("^/hos.img", %w[^/hos.elf])
|
||||
end
|
||||
|
||||
task "run", desc: "Run HOS in QEMU" do
|
||||
img = kernel_env.expand("^/hos.img")
|
||||
sh %W[qemu-system-x86_64 -hda #{img}]
|
||||
end
|
||||
|
||||
task "run-efi", desc: "Run HOS EFI in QEMU" do
|
||||
img = kernel_env.expand("^/hos-efi.img")
|
||||
sh %W[qemu-system-x86_64 -bios OVMF.fd -hda #{img}]
|
||||
end
|
5
apps/Makefile
Normal file
5
apps/Makefile
Normal file
@ -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
|
||||
|
3
apps/hash/Makefile
Normal file
3
apps/hash/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
all:
|
||||
nasm -f bin hash.asm -o hash
|
||||
|
1
apps/hash/hash
Normal file
1
apps/hash/hash
Normal file
@ -0,0 +1 @@
|
||||
<EFBFBD>0<EFBFBD>
|
6
apps/hash/hash.asm
Normal file
6
apps/hash/hash.asm
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
[bits 32]
|
||||
|
||||
begin:
|
||||
int 0x30
|
||||
ret
|
BIN
apps/test1.app
Normal file
BIN
apps/test1.app
Normal file
Binary file not shown.
20
apps/test1.asm
Normal file
20
apps/test1.asm
Normal file
@ -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
|
22
apps/test1.lst
Normal file
22
apps/test1.lst
Normal file
@ -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
|
BIN
apps/test2.app
Normal file
BIN
apps/test2.app
Normal file
Binary file not shown.
17
apps/test2.asm
Normal file
17
apps/test2.asm
Normal file
@ -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
|
2
build.txt
Normal file
2
build.txt
Normal file
@ -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)
|
Binary file not shown.
@ -1,224 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <ft2build.h>
|
||||
#include <stdio.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define N_CHARS 128
|
||||
|
||||
#define round_up_26_6(val) (((val) + 63) >> 6u)
|
||||
|
||||
int max_advance;
|
||||
int max_top = -9999;
|
||||
int min_bottom = 9999;
|
||||
int line_height;
|
||||
int baseline_offset;
|
||||
|
||||
typedef struct {
|
||||
int width;
|
||||
int height;
|
||||
int top;
|
||||
int left;
|
||||
uint8_t * bitmap;
|
||||
} char_info_t;
|
||||
|
||||
static char_info_t char_infos[N_CHARS];
|
||||
|
||||
static void load_char(FT_Face face, int char_code)
|
||||
{
|
||||
if (FT_Load_Char(face, char_code, FT_LOAD_RENDER) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int advance = round_up_26_6(face->glyph->advance.x);
|
||||
if (advance > max_advance)
|
||||
{
|
||||
max_advance = advance;
|
||||
}
|
||||
if ((face->glyph->bitmap.width == 0) ||
|
||||
(face->glyph->bitmap.rows == 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
char_infos[char_code].width = face->glyph->bitmap.width;
|
||||
char_infos[char_code].height = face->glyph->bitmap.rows;
|
||||
char_infos[char_code].top = face->glyph->bitmap_top;
|
||||
if (char_infos[char_code].top > max_top)
|
||||
{
|
||||
max_top = char_infos[char_code].top;
|
||||
}
|
||||
int bottom = char_infos[char_code].top - char_infos[char_code].height;
|
||||
if (bottom < min_bottom)
|
||||
{
|
||||
min_bottom = bottom;
|
||||
}
|
||||
char_infos[char_code].left = face->glyph->bitmap_left;
|
||||
char_infos[char_code].bitmap = malloc(char_infos[char_code].width * char_infos[char_code].height);
|
||||
memcpy(char_infos[char_code].bitmap,
|
||||
face->glyph->bitmap.buffer,
|
||||
char_infos[char_code].width * char_infos[char_code].height);
|
||||
}
|
||||
|
||||
static const char * bare_header_name(const char * h_file_name)
|
||||
{
|
||||
const char * p = rindex(h_file_name, '/');
|
||||
if (p == NULL)
|
||||
{
|
||||
p = h_file_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
p++;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static char * include_guard_name(const char * h_file_name)
|
||||
{
|
||||
const char * p = bare_header_name(h_file_name);
|
||||
char * guard_name = malloc(strlen(p) + 1);
|
||||
strcpy(guard_name, p);
|
||||
char * m = guard_name;
|
||||
while (*m != '\0')
|
||||
{
|
||||
if ('a' <= *m && *m <= 'z')
|
||||
{
|
||||
*m = toupper(*m);
|
||||
}
|
||||
else if (('0' <= *m && *m <= '9') || ('A' <= *m && *m <= 'Z'))
|
||||
{
|
||||
/* no change */
|
||||
}
|
||||
else
|
||||
{
|
||||
*m = '_';
|
||||
}
|
||||
m++;
|
||||
}
|
||||
return guard_name;
|
||||
}
|
||||
|
||||
static void generate_bytes(FILE * file, const uint8_t * bytes, int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (i % 8 == 0)
|
||||
{
|
||||
fprintf(file, " ");
|
||||
}
|
||||
fprintf(file, "0x%02xu,", bytes[i]);
|
||||
if ((i + 1) % 8 == 0)
|
||||
{
|
||||
fprintf(file, "\n");
|
||||
}
|
||||
else if (i < (count - 1))
|
||||
{
|
||||
fprintf(file, " ");
|
||||
}
|
||||
}
|
||||
if (count % 8 != 0)
|
||||
{
|
||||
fprintf(file, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void generate(const char * c_file_name)
|
||||
{
|
||||
char * h_file_name = malloc(strlen(c_file_name) + 1);
|
||||
strcpy(h_file_name, c_file_name);
|
||||
h_file_name[strlen(h_file_name) - 1] = 'h';
|
||||
char * guard = include_guard_name(h_file_name);
|
||||
|
||||
FILE * h_file = fopen(h_file_name, "wb");
|
||||
fprintf(h_file, "#ifndef %s\n", guard);
|
||||
fprintf(h_file, "#define %s\n\n", guard);
|
||||
fprintf(h_file, "#include <stdint.h>\n");
|
||||
fprintf(h_file, "typedef struct {\n int width;\n int height;\n int top;\n int left;\n const uint8_t * bitmap;\n} fontgen_char_info_t;\n");
|
||||
fprintf(h_file, "typedef struct {\n int line_height;\n int advance;\n int baseline_offset;\n const fontgen_char_info_t ** char_infos;\n} fontgen_font_t;\n");
|
||||
fprintf(h_file, "extern const fontgen_font_t kfont;\n");
|
||||
fprintf(h_file, "#endif\n");
|
||||
fclose(h_file);
|
||||
|
||||
FILE * c_file = fopen(c_file_name, "wb");
|
||||
fprintf(c_file, "#include \"%s\"\n", bare_header_name(h_file_name));
|
||||
fprintf(c_file, "#include <stddef.h>\n");
|
||||
for (int i = 0; i < N_CHARS; i++)
|
||||
{
|
||||
if (char_infos[i].width > 0)
|
||||
{
|
||||
fprintf(c_file, "static const uint8_t char_bitmap_%d[] = {\n", i);
|
||||
generate_bytes(c_file, char_infos[i].bitmap, char_infos[i].width * char_infos[i].height);
|
||||
fprintf(c_file, "};\n");
|
||||
}
|
||||
fprintf(c_file, "static const fontgen_char_info_t char_%d = {\n", i);
|
||||
fprintf(c_file, " %d,\n", char_infos[i].width);
|
||||
fprintf(c_file, " %d,\n", char_infos[i].height);
|
||||
fprintf(c_file, " %d,\n", char_infos[i].top);
|
||||
fprintf(c_file, " %d,\n", char_infos[i].left);
|
||||
if (char_infos[i].width > 0)
|
||||
{
|
||||
fprintf(c_file, " char_bitmap_%d,\n", i);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(c_file, " NULL,\n");
|
||||
}
|
||||
fprintf(c_file, "};\n\n");
|
||||
}
|
||||
fprintf(c_file, "const fontgen_char_info_t * char_infos[] = {\n");
|
||||
for (int i = 0; i < N_CHARS; i++)
|
||||
{
|
||||
fprintf(c_file, " &char_%d,\n", i);
|
||||
}
|
||||
fprintf(c_file, "};\n");
|
||||
fprintf(c_file, "const fontgen_font_t kfont = {\n");
|
||||
fprintf(c_file, " %d,\n", line_height);
|
||||
fprintf(c_file, " %d,\n", max_advance);
|
||||
fprintf(c_file, " %d,\n", baseline_offset);
|
||||
fprintf(c_file, " char_infos,\n");
|
||||
fprintf(c_file, "};\n");
|
||||
fclose(c_file);
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
/* Expect: font file, size, out file */
|
||||
if (argc != 4)
|
||||
{
|
||||
fprintf(stderr, "Incorrect arguments\n");
|
||||
return 1;
|
||||
}
|
||||
const char * font_file = argv[1];
|
||||
int size = atoi(argv[2]);
|
||||
const char * out_file = argv[3];
|
||||
|
||||
FT_Library ft_library;
|
||||
if (FT_Init_FreeType(&ft_library) != 0)
|
||||
{
|
||||
fprintf(stderr, "Could not initialize freetype\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
FT_Face face;
|
||||
if (FT_New_Face(ft_library, font_file, 0, &face) != 0)
|
||||
{
|
||||
fprintf(stderr, "Could not open %s\n", font_file);
|
||||
return 3;
|
||||
}
|
||||
|
||||
FT_Set_Pixel_Sizes(face, 0, size);
|
||||
|
||||
for (int i = 0; i < N_CHARS; i++)
|
||||
{
|
||||
load_char(face, i);
|
||||
}
|
||||
line_height = round_up_26_6(face->size->metrics.height);
|
||||
baseline_offset = (line_height - (max_top - min_bottom)) / 2 - min_bottom;
|
||||
|
||||
generate(out_file);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
binutils_version = "2.35"
|
||||
binutils_checksum = "1b11659fb49e20e18db460d44485f09442c8c56d5df165de9461eb09c8302f85"
|
||||
gcc_version = "10.2.0"
|
||||
gcc_checksum = "b8dd4368bb9c7f0b98188317ee0254dd8cc99d1e3a18d0ff146c855fe16c1d8c"
|
||||
install_path = File.expand_path("i686-elf-gcc")
|
||||
target = "i686-elf"
|
||||
path_prepend "#{install_path}/bin"
|
||||
|
||||
configure do
|
||||
check_c_compiler "gcc"
|
||||
check_program "make"
|
||||
check_program "bison"
|
||||
check_program "flex"
|
||||
check_program "texi2any", on_fail: "Install the texinfo package"
|
||||
check_program "wget"
|
||||
check_lib "gmp", on_fail: "Install the libgmp-dev package"
|
||||
check_lib "mpc", on_fail: "Install the libmpc-dev package"
|
||||
check_lib "mpfr", on_fail: "Install the libmpfr-dev package"
|
||||
end
|
||||
|
||||
default do
|
||||
unless Dir.exist?(install_path)
|
||||
# Download archives.
|
||||
download "https://ftp.gnu.org/gnu/binutils/binutils-#{binutils_version}.tar.xz",
|
||||
"#{build_dir}/binutils-#{binutils_version}.tar.xz",
|
||||
sha256sum: binutils_checksum
|
||||
|
||||
download "https://ftp.gnu.org/gnu/gcc/gcc-#{gcc_version}/gcc-#{gcc_version}.tar.xz",
|
||||
"#{build_dir}/gcc-#{gcc_version}.tar.xz",
|
||||
sha256sum: gcc_checksum
|
||||
|
||||
# Extract archives.
|
||||
sh "tar", "xJf", "binutils-#{binutils_version}.tar.xz",
|
||||
chdir: build_dir
|
||||
|
||||
sh "tar", "xJf", "gcc-#{gcc_version}.tar.xz",
|
||||
chdir: build_dir
|
||||
|
||||
# Build binutils.
|
||||
rm_rf "#{build_dir}/build-binutils"
|
||||
mkdir_p "#{build_dir}/build-binutils"
|
||||
cd "#{build_dir}/build-binutils" do
|
||||
sh %W[../binutils-#{binutils_version}/configure
|
||||
--target=#{target} --prefix=#{install_path} --with-sysroot --disable-nls
|
||||
--disable-werror]
|
||||
sh "make"
|
||||
sh "make install"
|
||||
end
|
||||
|
||||
# Build gcc.
|
||||
rm_rf "#{build_dir}/build-gcc"
|
||||
mkdir_p "#{build_dir}/build-gcc"
|
||||
cd "#{build_dir}/build-gcc" do
|
||||
sh %W[../gcc-#{gcc_version}/configure
|
||||
--target=#{target} --prefix=#{install_path} --disable-nls
|
||||
--enable-languages=c,c++ --without-headers]
|
||||
sh "make all-gcc"
|
||||
sh "make all-target-libgcc"
|
||||
sh "make install-gcc"
|
||||
sh "make install-target-libgcc"
|
||||
end
|
||||
|
||||
# Remove archives and build directories if everything succeeded.
|
||||
rm_f "#{build_dir}/binutils-#{binutils_version}.tar.xz"
|
||||
rm_rf "#{build_dir}/binutils-#{binutils_version}"
|
||||
rm_rf "#{build_dir}/build-binutils"
|
||||
rm_f "#{build_dir}/gcc-#{gcc_version}.tar.xz"
|
||||
rm_rf "#{build_dir}/gcc-#{gcc_version}"
|
||||
rm_rf "#{build_dir}/build-gcc"
|
||||
end
|
||||
end
|
||||
|
||||
distclean do
|
||||
rm_rf install_path
|
||||
end
|
BIN
initrd/bin/init
Normal file
BIN
initrd/bin/init
Normal file
Binary file not shown.
1
initrd/link
Symbolic link
1
initrd/link
Symbolic link
@ -0,0 +1 @@
|
||||
test_file
|
46
initrd/ulab
Normal file
46
initrd/ulab
Normal file
@ -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
|
||||
|
128
kernel/Makefile
Normal file
128
kernel/Makefile
Normal file
@ -0,0 +1,128 @@
|
||||
# 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 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
|
123
kernel/Makefile.bak
Normal file
123
kernel/Makefile.bak
Normal file
@ -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
|
91
kernel/block/ramdisk.cpp
Normal file
91
kernel/block/ramdisk.cpp
Normal file
@ -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;
|
||||
}
|
||||
|
38
kernel/block/ramdisk.h
Normal file
38
kernel/block/ramdisk.h
Normal file
@ -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
|
||||
|
100
kernel/block/ramdisk_old.c
Normal file
100
kernel/block/ramdisk_old.c
Normal file
@ -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;
|
||||
}
|
||||
|
||||
|
25
kernel/block/ramdisk_old.h
Normal file
25
kernel/block/ramdisk_old.h
Normal file
@ -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
kernel/boot.asm
Normal file
236
kernel/boot.asm
Normal file
@ -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 multiboot_header-VIRT_OFFSET ;header_addr
|
||||
dd _start-VIRT_OFFSET ;load_addr
|
||||
dd 0 ;load_end_addr
|
||||
dd _end-VIRT_OFFSET ;bss_end_addr
|
||||
dd multiboot_entry-VIRT_OFFSET ;entry_addr
|
||||
|
||||
; dd 1 ;mode_type
|
||||
; dd 80 ;width
|
||||
; dd 25 ;height
|
||||
; dd 0 ;depth
|
||||
|
||||
[global multiboot_entry]
|
||||
multiboot_entry:
|
||||
;This is where the kernel begins execution from the bootloader.
|
||||
;At this point, a temporary gdt is set up to "map" 0xC000_0000 to 0x0.
|
||||
cli ;should already be off...
|
||||
lgdt [gdtrbs32-VIRT_OFFSET]
|
||||
jmp KERNEL_CODE_BS32:segmented_start
|
||||
segmented_start:
|
||||
mov cx, KERNEL_DATA_BS32
|
||||
mov ss, cx
|
||||
mov ds, cx
|
||||
mov es, cx
|
||||
mov gs, cx
|
||||
mov fs, cx
|
||||
mov esp, STACK_V+0x1000 ;ok, now we can access our data
|
||||
|
||||
;Then the multiboot info structures are saved to local data variables.
|
||||
add ebx, VIRT_OFFSET
|
||||
push eax
|
||||
push ebx ;pointer to multiboot info structure
|
||||
call _k_mbsave ;save multiboot info structures
|
||||
add esp, 8
|
||||
|
||||
cmp eax, 0 ; eax = pointer to mb_module_t struct for rmmod
|
||||
jz pm_return
|
||||
|
||||
;go back to real mode to initialize video mode
|
||||
mov ebx, eax ; pointer to mb_module_t
|
||||
mov ecx, [ebx+4] ; end of module
|
||||
mov eax, [ebx] ; start of module
|
||||
mov esi, eax ; start of module
|
||||
sub ecx, eax ; ecx = length of rmmod
|
||||
shr ecx, 2 ; ecx = length of rmmod in dwords
|
||||
mov edi, 0xC0005000 ; where to copy rmmod to (0x5000 physical)
|
||||
|
||||
rep movsd ; copy rmmod to first 1mb
|
||||
|
||||
mov ebx, pm_return ; return address
|
||||
mov ecx, _rm_params ; put real mode params here (video mode etc...)
|
||||
sub ecx, VIRT_OFFSET
|
||||
|
||||
jmp 0xC0005010 ; jump to rmmod
|
||||
|
||||
;Next we enable paging with the first 4mb mapped 1:1 virtual:physical
|
||||
; and with the 4mb starting at 0xC000_0000 mapped to the first 4mb physical.
|
||||
pm_return:
|
||||
mov esp, STACK_V+0x1000 ;ok, now we can access our data again
|
||||
xor eax, eax
|
||||
mov edi, PDBR_V
|
||||
mov ecx, 1024 ;clear the PDBR
|
||||
rep stosd
|
||||
mov edi, PT_STACK_V
|
||||
mov ecx, 1024 ;clear the PT_STACK
|
||||
rep stosd
|
||||
mov [PDBR_V], dword LOPT_P|0x03 ;store the physical address of the LOw Page Table | (read/write, present)
|
||||
mov [PDBR_V+0xC00], dword LOPT_P|0x03 ;store the physical address of the LOw Page Table | (read/write, present)
|
||||
mov [PDBR_V+0xCFC], dword PT_STACK_P|0x03 ;store the physical address of the initial stack page page table | (read/write, present)
|
||||
mov [PDBR_V+0xFFC], dword PDBR_P|0x03 ;store the physical address of the page directory (identity map) | (read/write, present)
|
||||
mov [PT_STACK_V+0xFFC], dword STACK_P|0x03 ;store the physical address of the initial stack page | (read/write, present)
|
||||
|
||||
mov edi, LOPT_V
|
||||
mov ecx, 1024
|
||||
mov eax, 0x03 ;starting physical address = 0x0 | (read/write, present flags)
|
||||
fill_lopt_loop: ;fill the page table
|
||||
stosd
|
||||
add eax, 4096 ;increment next phsyical address by 4kb
|
||||
loop fill_lopt_loop
|
||||
|
||||
mov eax, PDBR_P
|
||||
mov cr3, eax ;store the Page Directory Base Address
|
||||
mov eax, cr0
|
||||
or eax, 0x80000000 ;set Page Enable bit
|
||||
mov cr0, eax ;now paging is active!
|
||||
|
||||
mov edi, GDT_V
|
||||
mov esi, gdt
|
||||
mov ecx, gdt_end-gdt
|
||||
rep movsb
|
||||
|
||||
mov edi, IDT_V ;destination
|
||||
mov esi, isr_0 ;address of isr0
|
||||
mov edx, isr_1-isr_0 ;distance between isr labels
|
||||
mov ecx, 50 ;number of isrlabels
|
||||
fill_idt:
|
||||
mov ebx, esi
|
||||
mov ax, si
|
||||
stosw ;0 offset 15:0
|
||||
mov ax, KERNEL_CODE
|
||||
stosw ;2 selector 15:0
|
||||
mov ax, 0x8E00
|
||||
stosw ;4 [P][DPL][0][TYPE][0][0][0][0][0][0][0][0]
|
||||
shr esi, 16
|
||||
mov ax, si
|
||||
stosw ;6 offset 31:16
|
||||
mov esi, ebx
|
||||
add esi, edx
|
||||
loop fill_idt
|
||||
mov word [IDT_V+0x30*8+4], 0xEE00 ;interrupt 0x30 has user priviledges
|
||||
|
||||
;Then we can start using our "real" gdt, then unmap the lower 4mb.
|
||||
lgdt [gdtr] ;load gdt
|
||||
jmp KERNEL_CODE:newgdtcontinue
|
||||
newgdtcontinue:
|
||||
mov ax, KERNEL_DATA
|
||||
mov es, ax
|
||||
mov ds, ax
|
||||
mov gs, ax
|
||||
mov fs, ax
|
||||
mov ss, ax
|
||||
mov esp, VIRT_STACK_TOP ;stack just under 3gb+256mb, moves downward
|
||||
lidt [idtr] ;load idt
|
||||
mov [PDBR_V], dword 0 ;unmap 0x0, we are running completely paged at 0xC000_0000
|
||||
|
||||
mov edi, GDT_V + TSS0_SEG + 2 ; copy _tss0 base address
|
||||
mov eax, _tss0 ; into the GDT descrtiptor
|
||||
stosw ; for TSS0
|
||||
shr eax, 16
|
||||
stosb
|
||||
add edi, 2
|
||||
shr eax, 8
|
||||
stosb
|
||||
|
||||
call _k_init ;C kernel initialization
|
||||
|
||||
mov ax, TSS0_SEG
|
||||
ltr ax
|
||||
|
||||
mov eax, esp
|
||||
push KERNEL_DATA
|
||||
push eax
|
||||
|
||||
idle_loop: ; system idle loop
|
||||
sti
|
||||
hlt
|
||||
jmp idle_loop
|
||||
|
||||
;-------------------------------------------------------
|
||||
gdtrbs32:
|
||||
dw gdt_endbs32-gdtbs32-1
|
||||
dd gdtbs32-VIRT_OFFSET
|
||||
gdtbs32: ; 0 = null descriptor
|
||||
dd 0
|
||||
dd 0
|
||||
|
||||
;a base of 0x4000_0000, when added to 0xC000_0000 will produce 0x0000_0000 physical before paging in effect
|
||||
KERNEL_CODE_BS32 equ $-gdtbs32 ; 8
|
||||
db 0xff ;limit 7:0
|
||||
db 0xff ;limit 15:8
|
||||
db 0x00 ;base 7:0
|
||||
db 0x00 ;base 15:8
|
||||
db 0x00 ;base 23:16
|
||||
db 0x9a ;access
|
||||
db 0xcf ;flags / limit 19:16
|
||||
db 0x40 ;base 31:24
|
||||
|
||||
KERNEL_DATA_BS32 equ $-gdtbs32 ; 16
|
||||
db 0xff ;limit 7:0
|
||||
db 0xff ;limit 15:8
|
||||
db 0x00 ;base 7:0
|
||||
db 0x00 ;base 15:8
|
||||
db 0x00 ;base 23:16
|
||||
db 0x92 ;access
|
||||
db 0xcf ;flags / limit 19:16
|
||||
db 0x40 ;base 31:24
|
||||
|
||||
KERNEL_CODE_BS6_ equ $-gdtbs32 ; 24
|
||||
dw 0xffff ;limit 15:0
|
||||
dw 0x0000 ;base 15:0
|
||||
db 0x00 ;base 23:16
|
||||
db 0x9A ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A])
|
||||
db 0x00 ;flags ([G][D/B][0][0]) / limit 19:16
|
||||
db 0x00 ;base 31:24
|
||||
|
||||
KERNEL_DATA_BS16 equ $-gdtbs32 ; 32
|
||||
dw 0xffff ;limit 15:0
|
||||
dw 0x0000 ;base 15:0
|
||||
db 0x00 ;base 23:16
|
||||
db 0x92 ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A])
|
||||
db 0x00 ;flags ([G][D/B][0][0]) / limit 19:16
|
||||
db 0x00 ;base 31:24
|
||||
|
||||
gdt_endbs32:
|
||||
|
||||
%include "gdt.inc"
|
||||
%include "idt.inc"
|
||||
|
151
kernel/char/keyboard.c
Normal file
151
kernel/char/keyboard.c
Normal file
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
36
kernel/char/keyboard.h
Normal file
36
kernel/char/keyboard.h
Normal file
@ -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
|
||||
|
44
kernel/char/misc_char.cpp
Normal file
44
kernel/char/misc_char.cpp
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
|
31
kernel/char/misc_char.h
Normal file
31
kernel/char/misc_char.h
Normal file
@ -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
|
||||
|
52
kernel/char/mouse.c
Normal file
52
kernel/char/mouse.c
Normal file
@ -0,0 +1,52 @@
|
||||
// mouse.c
|
||||
// Author: Josh Holtrop
|
||||
// Date: 10/03/03
|
||||
// Modified: 08/02/04
|
||||
|
||||
#include "hos_defines.h"
|
||||
#include "char/mouse.h"
|
||||
#include "video/video.h"
|
||||
#include "sys/io.h"
|
||||
|
||||
int mouse_bytesRead;
|
||||
byte mouse_inbuffer[MOUSE_BUFFER_LENGTH];
|
||||
|
||||
//This method initializes the ps/2 mouse
|
||||
void mouse_init()
|
||||
{
|
||||
outportb(0x64, 0x20); //tell keyboard controller we are going to read keyboard controller command byte
|
||||
byte temp = inportb(0x60); //read keyboard controller command byte
|
||||
outportb(0x64, 0x60); //tell keyboard controller we are going to write keyboard controller command byte
|
||||
outportb(0x60, 0x03 | (temp & 0x40)); //write keyboard controller command byte: enable mouse/keyboard ints, include original XLATE bit from temp (bit6)
|
||||
|
||||
outportb(0x64, 0xA8); //enable mouse port
|
||||
|
||||
outportb(0x64, 0xD4); //send command to mouse, not kbd
|
||||
outportb(0x60, 0xF4); //enable data reporting
|
||||
|
||||
mouse_bytesRead = 0;
|
||||
|
||||
//outportb(0x64, 0xD4);
|
||||
//outportb(0x60, 0xE7); //scaling 2:1
|
||||
}
|
||||
|
||||
|
||||
//This method is called when a mouse interrupt occurs
|
||||
void isr_mouse()
|
||||
{
|
||||
byte inb = inportb(0x60); //read mouse byte
|
||||
if ((inb == 0xFA) && (mouse_bytesRead < 1)) //ACK
|
||||
return;
|
||||
mouse_inbuffer[mouse_bytesRead] = inb;
|
||||
mouse_bytesRead++;
|
||||
if (mouse_bytesRead == 3) //complete packet received
|
||||
{
|
||||
mouse_bytesRead = 0;
|
||||
int adjx = (char) mouse_inbuffer[1];
|
||||
int adjy = (char) mouse_inbuffer[2];
|
||||
// TODO: do something with adjx, adjy...
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
15
kernel/char/mouse.h
Normal file
15
kernel/char/mouse.h
Normal file
@ -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
|
||||
|
274
kernel/char/vconsole.cpp
Normal file
274
kernel/char/vconsole.cpp
Normal file
@ -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;
|
||||
}
|
||||
|
||||
|
76
kernel/char/vconsole.h
Normal file
76
kernel/char/vconsole.h
Normal file
@ -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
|
||||
|
65
kernel/devices.cpp
Normal file
65
kernel/devices.cpp
Normal file
@ -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; }
|
||||
|
58
kernel/devices.h
Normal file
58
kernel/devices.h
Normal file
@ -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
|
||||
|
75
kernel/display/display.c
Normal file
75
kernel/display/display.c
Normal file
@ -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 */
|
||||
}
|
||||
|
28
kernel/display/display.h
Normal file
28
kernel/display/display.h
Normal file
@ -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
|
||||
|
||||
|
141
kernel/display/kout.c
Normal file
141
kernel/display/kout.c
Normal file
@ -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);
|
||||
|
||||
}
|
||||
|
20
kernel/display/kout.h
Normal file
20
kernel/display/kout.h
Normal file
@ -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
|
||||
|
111
kernel/display/vesafb.c
Normal file
111
kernel/display/vesafb.c
Normal file
@ -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;
|
||||
}
|
||||
|
25
kernel/display/vesafb.h
Normal file
25
kernel/display/vesafb.h
Normal file
@ -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
|
||||
|
||||
|
21
kernel/fs/FileSystem.cpp
Normal file
21
kernel/fs/FileSystem.cpp
Normal file
@ -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;}
|
35
kernel/fs/FileSystem.h
Normal file
35
kernel/fs/FileSystem.h
Normal file
@ -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
|
15
kernel/fs/OpenDirectory.cpp
Normal file
15
kernel/fs/OpenDirectory.cpp
Normal file
@ -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; }
|
23
kernel/fs/OpenDirectory.h
Normal file
23
kernel/fs/OpenDirectory.h
Normal file
@ -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
|
||||
|
13
kernel/fs/OpenFile.cpp
Normal file
13
kernel/fs/OpenFile.cpp
Normal file
@ -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; }
|
23
kernel/fs/OpenFile.h
Normal file
23
kernel/fs/OpenFile.h
Normal file
@ -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
|
||||
|
39
kernel/fs/VFSMount.cpp
Normal file
39
kernel/fs/VFSMount.cpp
Normal file
@ -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;
|
||||
}
|
31
kernel/fs/VFSMount.h
Normal file
31
kernel/fs/VFSMount.h
Normal file
@ -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
|
143
kernel/fs/ext2/Ext2BlockCache.cpp
Normal file
143
kernel/fs/ext2/Ext2BlockCache.cpp
Normal file
@ -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];
|
||||
}
|
34
kernel/fs/ext2/Ext2BlockCache.h
Normal file
34
kernel/fs/ext2/Ext2BlockCache.h
Normal file
@ -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
|
238
kernel/fs/ext2/Ext2OpenDirectory.cpp
Normal file
238
kernel/fs/ext2/Ext2OpenDirectory.cpp
Normal file
@ -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 */
|
||||
}
|
||||
|
37
kernel/fs/ext2/Ext2OpenDirectory.h
Normal file
37
kernel/fs/ext2/Ext2OpenDirectory.h
Normal file
@ -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
|
228
kernel/fs/ext2/Ext2OpenFile.cpp
Normal file
228
kernel/fs/ext2/Ext2OpenFile.cpp
Normal file
@ -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);
|
||||
lock(&Ext2OpenFileListLock);
|
||||
if ((mode & VFS_MODE_RW_MASK) == VFS_MODE_WRITE)
|
||||
{
|
||||
if ((mode & VFS_MODE_WRITE_MASK) == VFS_MODE_TRUNCATE)
|
||||
{
|
||||
/* file opened for write/truncate
|
||||
* tell any open files that it's been truncated, then
|
||||
* tell ext2 filesystem to free its blocks
|
||||
*/
|
||||
u32_t size = Ext2OpenFileList->size();
|
||||
for (u32_t i = 0; i < size; i++)
|
||||
{
|
||||
if ((*Ext2OpenFileList)[i].inode == inum)
|
||||
(*Ext2OpenFileList)[i].ofile->notifyTruncated();
|
||||
}
|
||||
fs->truncateInode(inum);
|
||||
fs->readInode(inum, &myInode); /* re-read inode */
|
||||
}
|
||||
else
|
||||
myPosition = myInode.i_size;
|
||||
}
|
||||
if (Ext2OpenFileList == NULL)
|
||||
Ext2OpenFileList = new vector<Ext2OpenFileHandle>();
|
||||
/* add ourselves to the list */
|
||||
Ext2OpenFileHandle thisHandle = {inum, this};
|
||||
Ext2OpenFileList->add(thisHandle);
|
||||
unlock(&Ext2OpenFileListLock);
|
||||
}
|
||||
|
||||
/* destroy an Ext2OpenFile object */
|
||||
Ext2OpenFile::~Ext2OpenFile()
|
||||
{
|
||||
/* remove ourselves from the open file list */
|
||||
lock(&Ext2OpenFileListLock);
|
||||
u32_t size = Ext2OpenFileList->size();
|
||||
for (u32_t i = 0; i < size; i++)
|
||||
{
|
||||
if ((*Ext2OpenFileList)[i].ofile == this)
|
||||
{
|
||||
Ext2OpenFileList->remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
unlock(&Ext2OpenFileListLock);
|
||||
|
||||
/* write back any open caches if in write mode */
|
||||
if ( !myBeenTruncated && ((myMode & VFS_MODE_RW_MASK) == VFS_MODE_WRITE) )
|
||||
{
|
||||
if (myBlockCacheStatus == 2)
|
||||
myCache->writeBlock(myBlockCacheBlock, myBlockCache);
|
||||
myFS->writeInode(myInum, &myInode);
|
||||
}
|
||||
/* free the memory we used */
|
||||
delete myCache;
|
||||
delete[] myBlockCache;
|
||||
}
|
||||
|
||||
/* seek to a certain position in the file (only for reading) */
|
||||
int Ext2OpenFile::seek(int pos, int mode)
|
||||
{
|
||||
if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_READ)
|
||||
return -1;
|
||||
if (mode == SEEK_ABSOLUTE)
|
||||
{
|
||||
if (pos < 0)
|
||||
return -2;
|
||||
if ((u32_t)pos >= myInode.i_size)
|
||||
return -3;
|
||||
myPosition = pos;
|
||||
return 0;
|
||||
}
|
||||
else if (mode == SEEK_RELATIVE)
|
||||
{
|
||||
if (myPosition + pos < 0)
|
||||
return -2;
|
||||
if (myPosition + pos >= myInode.i_size)
|
||||
return -3;
|
||||
myPosition += pos;
|
||||
return 0;
|
||||
}
|
||||
else if (mode == SEEK_END)
|
||||
{
|
||||
if (myInode.i_size + pos < 0)
|
||||
return -2;
|
||||
if (myInode.i_size + pos >= myInode.i_size)
|
||||
return -3;
|
||||
myPosition = myInode.i_size + pos;
|
||||
return 0;
|
||||
}
|
||||
return -4;
|
||||
}
|
||||
|
||||
/* read a byte from the current file position, return error code/EOF */
|
||||
int Ext2OpenFile::read()
|
||||
{
|
||||
if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_READ)
|
||||
return -1;
|
||||
if (myBeenTruncated || myPosition >= myInode.i_size)
|
||||
return EOF;
|
||||
u32_t theBlock = myPosition / myBlockSize;
|
||||
updateCache(theBlock);
|
||||
return myBlockCache[myPosition++ % myBlockSize];
|
||||
}
|
||||
|
||||
/* read num bytes from the current file position, put in buf
|
||||
* return: number of bytes read (>=0) or error code (<0)
|
||||
*/
|
||||
int Ext2OpenFile::read(void *buf, u32_t num)
|
||||
{
|
||||
if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_READ)
|
||||
return -1;
|
||||
if (myBeenTruncated || myPosition >= myInode.i_size)
|
||||
return EOF;
|
||||
if (myPosition + num > myInode.i_size)
|
||||
num = myInode.i_size - myPosition;
|
||||
u32_t bytesRead = 0;
|
||||
u32_t bytesIntoFirstBlock = myPosition % myBlockSize;
|
||||
if (bytesIntoFirstBlock)
|
||||
{
|
||||
updateCache(myPosition / myBlockSize);
|
||||
bytesRead = min(myBlockSize - bytesIntoFirstBlock, num);
|
||||
memcpy(buf, myBlockCache + bytesIntoFirstBlock, bytesRead);
|
||||
myPosition += bytesRead;
|
||||
}
|
||||
while (bytesRead < num)
|
||||
{
|
||||
updateCache(myPosition / myBlockSize);
|
||||
u32_t bytesToRead = min(num - bytesRead, myBlockSize);
|
||||
memcpy((u8_t *)buf + bytesRead, myBlockCache, bytesToRead);
|
||||
bytesRead += bytesToRead;
|
||||
myPosition += bytesToRead;
|
||||
}
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
/* write a byte to the current file position */
|
||||
int Ext2OpenFile::write(int chr)
|
||||
{
|
||||
if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_WRITE)
|
||||
return -1;
|
||||
if (myBeenTruncated)
|
||||
return EOF;
|
||||
u32_t theBlock = myPosition / myBlockSize;
|
||||
updateCache(theBlock);
|
||||
myBlockCache[myPosition++ % myBlockSize] = chr;
|
||||
myBlockCacheStatus = 2;
|
||||
myInode.i_size++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* write num bytes from buf to the current file position
|
||||
* return: number of bytes written (>=0) or error code (<0)
|
||||
*/
|
||||
int Ext2OpenFile::write(void *buf, u32_t num)
|
||||
{
|
||||
if (myBeenTruncated)
|
||||
return -1;
|
||||
if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_WRITE)
|
||||
return -2;
|
||||
u32_t bytesIntoFirstBlock = myPosition % myBlockSize;
|
||||
u32_t bytesWritten = 0;
|
||||
if (bytesIntoFirstBlock)
|
||||
{
|
||||
updateCache(myPosition / myBlockSize);
|
||||
bytesWritten = min(myBlockSize - bytesIntoFirstBlock, num);
|
||||
memcpy(myBlockCache + bytesIntoFirstBlock, buf, bytesWritten);
|
||||
myBlockCacheStatus = 2;
|
||||
myPosition += bytesWritten;
|
||||
}
|
||||
while (bytesWritten < num)
|
||||
{
|
||||
updateCache(myPosition / myBlockSize);
|
||||
u32_t bytesToWrite = min(num - bytesWritten, myBlockSize);
|
||||
memcpy(myBlockCache, (u8_t *)buf + bytesWritten, bytesToWrite);
|
||||
myBlockCacheStatus = 2;
|
||||
bytesWritten += bytesToWrite;
|
||||
myPosition += bytesToWrite;
|
||||
}
|
||||
myInode.i_size += bytesWritten;
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
void Ext2OpenFile::updateCache(u32_t blockNum)
|
||||
{
|
||||
if (myBlockCacheStatus && myBlockCacheBlock == blockNum)
|
||||
return;
|
||||
if (myBlockCacheStatus == 2)
|
||||
myCache->writeBlock(myBlockCacheBlock, myBlockCache);
|
||||
myCache->readBlock(blockNum, myBlockCache);
|
||||
myBlockCacheStatus = 1;
|
||||
myBlockCacheBlock = blockNum;
|
||||
}
|
||||
|
||||
void Ext2OpenFile::notifyTruncated()
|
||||
{
|
||||
myBeenTruncated = 1;
|
||||
}
|
47
kernel/fs/ext2/Ext2OpenFile.h
Normal file
47
kernel/fs/ext2/Ext2OpenFile.h
Normal file
@ -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
|
599
kernel/fs/ext2/ext2.cpp
Normal file
599
kernel/fs/ext2/ext2.cpp
Normal file
@ -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;
|
||||
}
|
204
kernel/fs/ext2/ext2.h
Normal file
204
kernel/fs/ext2/ext2.h
Normal file
@ -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
|
||||
|
762
kernel/fs/ext2/ext2_old.c
Normal file
762
kernel/fs/ext2/ext2_old.c
Normal file
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
241
kernel/fs/ext2/ext2_old.h
Normal file
241
kernel/fs/ext2/ext2_old.h
Normal file
@ -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
|
||||
|
332
kernel/fs/ext2/ext2_working.c
Normal file
332
kernel/fs/ext2/ext2_working.c
Normal file
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
241
kernel/fs/ext2/ext2_working.h
Normal file
241
kernel/fs/ext2/ext2_working.h
Normal file
@ -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
|
||||
|
42
kernel/fs/sysfs/sysfs.cpp
Normal file
42
kernel/fs/sysfs/sysfs.cpp
Normal file
@ -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;
|
||||
}
|
37
kernel/fs/sysfs/sysfs.h
Normal file
37
kernel/fs/sysfs/sysfs.h
Normal file
@ -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
|
||||
|
20
kernel/fs/sysfs/sysfs_entry.cpp
Normal file
20
kernel/fs/sysfs/sysfs_entry.cpp
Normal file
@ -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()
|
||||
{
|
||||
}
|
||||
|
30
kernel/fs/sysfs/sysfs_entry.h
Normal file
30
kernel/fs/sysfs/sysfs_entry.h
Normal file
@ -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
|
||||
|
413
kernel/fs/vfs.cpp
Normal file
413
kernel/fs/vfs.cpp
Normal file
@ -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
kernel/fs/vfs.h
Normal file
129
kernel/fs/vfs.h
Normal file
@ -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
|
||||
|
432
kernel/fs/vfs_old.cpp
Normal file
432
kernel/fs/vfs_old.cpp
Normal file
@ -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;
|
||||
}
|
||||
|
165
kernel/fs/vfs_old.h
Normal file
165
kernel/fs/vfs_old.h
Normal file
@ -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
|
||||
|
105
kernel/functions.h
Normal file
105
kernel/functions.h
Normal file
@ -0,0 +1,105 @@
|
||||
//functions.h
|
||||
//05/07/03 Josh Holtrop
|
||||
//for HOS
|
||||
//Modified: 02/26/04
|
||||
|
||||
#ifndef __HOS_FUNCTIONS__
|
||||
#define __HOS_FUNCTIONS__ __HOS_FUNCTIONS__
|
||||
|
||||
#include "hos_defines.h"
|
||||
#include "sys/io.h"
|
||||
|
||||
extern u32_t _code;
|
||||
extern u32_t _bss;
|
||||
extern u32_t _end;
|
||||
|
||||
//Enables (SeTs) Interrupt Flag on the processor
|
||||
static inline void enable_ints()
|
||||
{
|
||||
asm("sti");
|
||||
}
|
||||
|
||||
//Disables (CLears) Interrupt Flag on the processor
|
||||
static inline void disable_ints()
|
||||
{
|
||||
asm("cli");
|
||||
}
|
||||
|
||||
//Restarts the computer
|
||||
static inline void restart()
|
||||
{
|
||||
enable_ints();
|
||||
byte temp;
|
||||
do
|
||||
{
|
||||
temp = inportb(0x64);
|
||||
if (temp & 1)
|
||||
inportb(0x60);
|
||||
} while(temp & 2);
|
||||
|
||||
|
||||
outportb (0x64, 0xfe);
|
||||
for (;;) {}
|
||||
}
|
||||
|
||||
//Halts (freezes) the computer
|
||||
static inline void halt()
|
||||
{
|
||||
asm("cli");
|
||||
asm("hlt");
|
||||
while (1) ;
|
||||
}
|
||||
|
||||
//Initializes 8253 Programmable Interrupt Timer
|
||||
static inline void timer_init(u32_t freq)
|
||||
{
|
||||
u32_t wait = 1193180 / freq; //how many ticks the PIT must wait before issuing an interrupt
|
||||
outportb(0x43, 0x34);
|
||||
outportb(0x40, wait); //lsb
|
||||
outportb(0x40, wait >> 8); //msb
|
||||
}
|
||||
|
||||
//Returns the size of the kernel (code & data & bss)
|
||||
// - this should be 4kb aligned per the linker script
|
||||
// - this is the amount of RAM the kernel code, data, & bss take
|
||||
static inline u32_t kernel_size_used()
|
||||
{
|
||||
return (u32_t)(&_end)-(u32_t)(&_code);
|
||||
}
|
||||
|
||||
//Returns the size of the kernel (code & data)
|
||||
// - this does not include the bss section
|
||||
// - this should be 4kb aligned per the linker script
|
||||
// - this should be the size of kernel.bin
|
||||
static inline u32_t kernel_size()
|
||||
{
|
||||
return (u32_t)(&_bss)-(u32_t)(&_code);
|
||||
}
|
||||
|
||||
//converts a binary-coded-decimal byte to its decimal equivalent
|
||||
static inline byte bcd2byte(byte bcd)
|
||||
{
|
||||
return (10 * ((bcd & 0xF0) >> 4)) + (bcd & 0x0F);
|
||||
}
|
||||
|
||||
//converts a binary-coded-decimal byte to its decimal equivalent
|
||||
static inline byte byte2bcd(byte bite)
|
||||
{
|
||||
return ((bite / 10) << 4) | (bite % 10);
|
||||
}
|
||||
|
||||
// get the maximum of two values
|
||||
static inline u32_t max(u32_t v1, u32_t v2)
|
||||
{
|
||||
return ( (v2 > v1) ? v2 : v1 );
|
||||
}
|
||||
|
||||
// get the minimum of two values
|
||||
static inline u32_t min(u32_t v1, u32_t v2)
|
||||
{
|
||||
return ( (v2 > v1) ? v1 : v2 );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
57
kernel/gdt.inc
Normal file
57
kernel/gdt.inc
Normal file
@ -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:
|
||||
|
||||
|
||||
|
52
kernel/hos_defines.h
Normal file
52
kernel/hos_defines.h
Normal file
@ -0,0 +1,52 @@
|
||||
// hos_defines.h
|
||||
// Author: Josh Holtrop
|
||||
// Date: 08/15/04
|
||||
// Modified: 08/16/04
|
||||
|
||||
#ifndef __HOS_DEFINES_H__
|
||||
#define __HOS_DEFINES_H__ __HOS_DEFINES_H__
|
||||
|
||||
#define PARALLEL_DEBUG
|
||||
|
||||
#define HOS_TIMER_FREQ 1000
|
||||
#define KERNEL_MSG_CONSOLE 11
|
||||
|
||||
#define VIRT_OFFSET 0xC0000000
|
||||
#define PHYS_LOAD 0x00108000
|
||||
#define PDBR 0x00104000
|
||||
#define VIRT_STACK_TOP 0xD0000000
|
||||
#define HEAP_START 0xD0000000
|
||||
#define HEAP_LENGTH 0x20000000
|
||||
|
||||
#define CONSOLE_MEMORY 0xC00B8000
|
||||
#define BIOS_CHAR_MAP 0xC00FFA6E
|
||||
#define LFB_MEMORY 0xF0000000
|
||||
|
||||
#define SEG_KERNEL_CODE 8
|
||||
#define SEG_KERNEL_DATA 16
|
||||
#define SEG_USER_CODE 24
|
||||
#define SEG_USER_DATA 32
|
||||
#define SEG_TSS0 40
|
||||
|
||||
#define MAX_MODULES 16
|
||||
#define MAX_MMAP 16
|
||||
|
||||
#define NULL 0
|
||||
|
||||
#define HOS_INIT_TASK "/bin/init"
|
||||
|
||||
#define New(x) kcalloc(1, sizeof(x))
|
||||
|
||||
typedef unsigned long long u64_t;
|
||||
typedef unsigned int u32_t;
|
||||
typedef unsigned short u16_t;
|
||||
typedef unsigned char u8_t;
|
||||
typedef unsigned char byte;
|
||||
typedef int lock_t;
|
||||
|
||||
extern u32_t _end;
|
||||
extern u32_t _bss;
|
||||
extern u32_t start;
|
||||
|
||||
#endif
|
||||
|
117
kernel/idt.inc
Normal file
117
kernel/idt.inc
Normal file
@ -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
kernel/kernel.c
Normal file
288
kernel/kernel.c
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
|
53
kernel/kernel.h
Normal file
53
kernel/kernel.h
Normal file
@ -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
|
||||
|
109
kernel/lang/conv.c
Normal file
109
kernel/lang/conv.c
Normal file
@ -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;
|
||||
}
|
||||
|
||||
|
20
kernel/lang/conv.h
Normal file
20
kernel/lang/conv.h
Normal file
@ -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
|
||||
|
362
kernel/lang/lang.asm
Normal file
362
kernel/lang/lang.asm
Normal file
@ -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 _lock]
|
||||
_lock:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push eax
|
||||
push ebx
|
||||
push esi
|
||||
|
||||
mov esi, [ebp + 8]
|
||||
_lock_loop0:
|
||||
xor eax, eax
|
||||
mov ebx, 1
|
||||
cmpxchg [esi], ebx
|
||||
jnz _lock_loop0 ; failed to acquire lock
|
||||
|
||||
pop esi
|
||||
pop ebx
|
||||
pop eax
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
;releases a lock
|
||||
[global _unlock]
|
||||
_unlock:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push esi
|
||||
|
||||
mov esi, [ebp + 8]
|
||||
mov [esi], dword 0
|
||||
|
||||
pop esi
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
;returns the value in the CR0 register
|
||||
;extern dword read_cr0();
|
||||
[global _read_cr0]
|
||||
_read_cr0:
|
||||
mov eax, cr0;
|
||||
ret
|
||||
|
||||
;stores the parameter to the CR0 register
|
||||
;extern dword write_cr0(dword cr0);
|
||||
[global _write_cr0]
|
||||
_write_cr0:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
mov eax, [ebp+8]
|
||||
mov cr0, eax
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
;returns the value in the CR2 register
|
||||
;extern dword read_cr2();
|
||||
[global _read_cr2]
|
||||
_read_cr2:
|
||||
mov eax, cr2;
|
||||
ret
|
||||
|
||||
|
||||
|
||||
;returns the value in the CR3 register
|
||||
;extern dword read_cr3();
|
||||
[global _read_cr3]
|
||||
_read_cr3:
|
||||
mov eax, cr3;
|
||||
ret
|
||||
|
||||
|
||||
;stores the parameter to the CR3 register
|
||||
;extern dword write_cr3(dword cr3);
|
||||
[global _write_cr3]
|
||||
_write_cr3:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
mov eax, [ebp+8]
|
||||
mov cr3, eax
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
|
||||
; read ss register
|
||||
[global _read_ss]
|
||||
_read_ss:
|
||||
mov ax, ss
|
||||
ret
|
||||
|
||||
|
||||
;copies a string from the source to the destination parameter
|
||||
;extern void strcpy(char *dest, char *src);
|
||||
[global _strcpy]
|
||||
_strcpy:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push esi
|
||||
push edi
|
||||
mov edi, [ebp+8]
|
||||
mov esi, [ebp+12]
|
||||
strcpyloop:
|
||||
lodsb
|
||||
stosb
|
||||
or al, al
|
||||
jnz strcpyloop
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
;copies memory of n bytes from src to destination
|
||||
;void memcpy(void *dest, void *src, dword n);
|
||||
[global _memcpy]
|
||||
_memcpy:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push esi
|
||||
push edi
|
||||
push ecx
|
||||
mov edi, [ebp+8]
|
||||
mov esi, [ebp+12]
|
||||
mov ecx, [ebp+16]
|
||||
|
||||
cld
|
||||
rep movsb
|
||||
|
||||
pop ecx
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
|
||||
;copies memory of n words (n*2 bytes) from src to destination
|
||||
;void memcpyw(void *dest, void *src, dword n);
|
||||
[global _memcpyw]
|
||||
_memcpyw:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push esi
|
||||
push edi
|
||||
push ecx
|
||||
mov edi, [ebp+8]
|
||||
mov esi, [ebp+12]
|
||||
mov ecx, [ebp+16]
|
||||
|
||||
cld
|
||||
rep movsw
|
||||
|
||||
pop ecx
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
|
||||
;copies memory of n dwords (n*4 bytes) from src to destination
|
||||
;void memcpyd(void *dest, void *src, dword n);
|
||||
[global _memcpyd]
|
||||
_memcpyd:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push esi
|
||||
push edi
|
||||
push ecx
|
||||
mov edi, [ebp+8]
|
||||
mov esi, [ebp+12]
|
||||
mov ecx, [ebp+16]
|
||||
|
||||
cld
|
||||
rep movsd
|
||||
|
||||
pop ecx
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
|
||||
;sets num bytes at buffer to the value of c
|
||||
;void *memset(void *buffer, int c, int num);
|
||||
[global _memset]
|
||||
_memset:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push edi
|
||||
push ecx
|
||||
mov edi, [ebp+8]
|
||||
push edi ;save for return address
|
||||
mov eax, [ebp+12]
|
||||
mov ecx, [ebp+16]
|
||||
|
||||
rep stosb
|
||||
|
||||
pop eax
|
||||
pop ecx
|
||||
pop edi
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
|
||||
;sets num words at buffer to the value of c
|
||||
;void *memsetw(void *buffer, int c, int num);
|
||||
[global _memsetw]
|
||||
_memsetw:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push edi
|
||||
push ecx
|
||||
mov edi, [ebp+8]
|
||||
push edi ;save for return address
|
||||
mov eax, [ebp+12]
|
||||
mov ecx, [ebp+16]
|
||||
|
||||
rep stosw
|
||||
|
||||
pop eax
|
||||
pop ecx
|
||||
pop edi
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
|
||||
;sets num dwords at buffer to the value of c
|
||||
;void *memsetd(void *buffer, int c, int num);
|
||||
[global _memsetd]
|
||||
_memsetd:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push edi
|
||||
push ecx
|
||||
mov edi, [ebp+8]
|
||||
push edi ;save for return address
|
||||
mov eax, [ebp+12]
|
||||
mov ecx, [ebp+16]
|
||||
|
||||
rep stosd
|
||||
|
||||
pop eax
|
||||
pop ecx
|
||||
pop edi
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
|
||||
;returns the number of characters in a string
|
||||
;extern dword strlen(char *str);
|
||||
[global _strlen]
|
||||
_strlen:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push esi
|
||||
push ebx
|
||||
mov esi, [ebp+8]
|
||||
xor ebx, ebx
|
||||
strlenloop:
|
||||
lodsb
|
||||
or al, al
|
||||
jz strlendone
|
||||
inc ebx
|
||||
jmp strlenloop
|
||||
strlendone:
|
||||
mov eax, ebx
|
||||
pop ebx
|
||||
pop esi
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
|
||||
;this function invalidates the page directory/table entry that
|
||||
; would be used to access the memory address given in the parameter
|
||||
;extern void invlpg_(dword addr);
|
||||
[global _invlpg_]
|
||||
_invlpg_:
|
||||
mov eax, [esp+4]
|
||||
invlpg [eax]
|
||||
ret
|
||||
|
||||
|
||||
;
|
||||
;void writeCursorPosition(word pos)
|
||||
;
|
||||
[global _writeCursorPosition]
|
||||
_writeCursorPosition:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
|
||||
push eax
|
||||
push ebx
|
||||
push edx
|
||||
|
||||
mov eax, [ebp+8] ;cursor position in ax
|
||||
|
||||
mov bl, al
|
||||
mov dx, 0x03D4
|
||||
mov al, 0x0E
|
||||
out dx, al
|
||||
|
||||
inc dx
|
||||
mov al, ah
|
||||
out dx, al
|
||||
|
||||
dec dx
|
||||
mov al, 0x0F
|
||||
out dx, al
|
||||
|
||||
inc dx
|
||||
mov al, bl
|
||||
out dx, al
|
||||
|
||||
pop edx
|
||||
pop ebx
|
||||
pop eax
|
||||
pop ebp
|
||||
|
||||
ret
|
||||
|
||||
|
||||
;
|
||||
;word getCursorPosition()
|
||||
;
|
||||
[global _getCursorPosition]
|
||||
_getCursorPosition:
|
||||
push ebx
|
||||
push edx
|
||||
|
||||
xor eax, eax
|
||||
mov dx, 0x03D4
|
||||
mov al, 0x0E
|
||||
out dx, al
|
||||
|
||||
inc dx
|
||||
in al, dx
|
||||
mov bl, al
|
||||
|
||||
dec dx
|
||||
mov al, 0x0F
|
||||
out dx, al
|
||||
|
||||
inc dx
|
||||
in al, dx
|
||||
mov ah, bl
|
||||
|
||||
pop edx
|
||||
pop ebx
|
||||
|
||||
ret
|
||||
|
114
kernel/lang/lang.c
Normal file
114
kernel/lang/lang.c
Normal file
@ -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);
|
||||
}
|
||||
|
43
kernel/lang/lang.h
Normal file
43
kernel/lang/lang.h
Normal file
@ -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 lock(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
|
||||
|
||||
|
25
kernel/lang/new.cpp
Normal file
25
kernel/lang/new.cpp
Normal file
@ -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); }
|
258
kernel/lang/string.cpp
Normal file
258
kernel/lang/string.cpp
Normal file
@ -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); }
|
||||
|
||||
|
||||
|
110
kernel/lang/string.h
Normal file
110
kernel/lang/string.h
Normal file
@ -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
|
||||
|
181
kernel/lang/vector.h
Normal file
181
kernel/lang/vector.h
Normal file
@ -0,0 +1,181 @@
|
||||
|
||||
// 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:
|
||||
/* 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();
|
||||
|
||||
public:
|
||||
/* Constructors/Destructor */
|
||||
vector<type>();
|
||||
vector<type>(unsigned int size);
|
||||
vector<type>(const vector<type> & v1);
|
||||
~vector<type>();
|
||||
|
||||
/* Assignment operator */
|
||||
vector<type> & operator=(const vector<type> & v1);
|
||||
|
||||
/* Returns the size of the vector */
|
||||
unsigned int size() const;
|
||||
|
||||
/* Add an element to the end of the vector */
|
||||
vector<type> & add(type elem);
|
||||
|
||||
/* Remove an element from the vector */
|
||||
vector<type> & remove(unsigned int index);
|
||||
|
||||
/* Insert an element into a position in the vector */
|
||||
vector<type> & insert(type elem, unsigned int position);
|
||||
|
||||
/* Direct access operators */
|
||||
const type & operator[](unsigned int index) const;
|
||||
type & operator[](unsigned int index);
|
||||
|
||||
/* Returns pointer to data */
|
||||
type **data();
|
||||
};
|
||||
|
||||
template<typename type>
|
||||
vector<type>::vector<type>()
|
||||
{
|
||||
myData = NULL;
|
||||
mySize = 0;
|
||||
myAllocated = 0;
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
vector<type>::vector<type>(unsigned int size)
|
||||
{
|
||||
myData = new (type *)[size];
|
||||
mySize = 0;
|
||||
myAllocated = size;
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
vector<type>::vector<type>(const vector<type> & v1)
|
||||
{
|
||||
mySize = v1.mySize;
|
||||
myAllocated = v1.myAllocated;
|
||||
myData = new (type *)[myAllocated];
|
||||
for (u32_t i = 0; i < mySize; i++)
|
||||
myData[i] = new type(*v1.myData[i]);
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
vector<type>::~vector<type>()
|
||||
{
|
||||
for (unsigned int i = 0; i < mySize; i++)
|
||||
delete myData[i];
|
||||
delete[] myData;
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
vector<type> & vector<type>::operator=(const vector<type> & v1)
|
||||
{
|
||||
mySize = v1.mySize;
|
||||
myAllocated = v1.myAllocated;
|
||||
myData = new (type *)[myAllocated];
|
||||
for (u32_t i = 0; i < mySize; i++)
|
||||
myData[i] = new type(*v1.myData[i]);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
u32_t vector<type>::size() const
|
||||
{
|
||||
return mySize;
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
const type & vector<type>::operator[](unsigned int index) const
|
||||
{
|
||||
return *myData[index];
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
type & vector<type>::operator[](unsigned int index)
|
||||
{
|
||||
return *myData[index];
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
vector<type> & vector<type>::add(type elem)
|
||||
{
|
||||
while (mySize >= myAllocated)
|
||||
grow();
|
||||
myData[mySize++] = new type(elem);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
void vector<type>::grow()
|
||||
{
|
||||
myAllocated <<= 1;
|
||||
if (myAllocated == 0)
|
||||
myAllocated = 1;
|
||||
type **data_new = new (type *)[myAllocated];
|
||||
for (unsigned int i = 0; i < mySize; i++)
|
||||
data_new[i] = myData[i];
|
||||
if (myData)
|
||||
delete[] myData;
|
||||
myData = data_new;
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
vector<type> & 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;
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
vector<type> & 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;
|
||||
}
|
||||
|
||||
|
||||
template<typename type>
|
||||
type **vector<type>::data()
|
||||
{
|
||||
return myData;
|
||||
}
|
||||
|
||||
#endif
|
25
kernel/link.ld
Normal file
25
kernel/link.ld
Normal file
@ -0,0 +1,25 @@
|
||||
OUTPUT_FORMAT("binary")
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
.text 0xC0108000 : {
|
||||
code = .; _code = .; __code = .;
|
||||
*(.text)
|
||||
}
|
||||
.gnulinkonce : {
|
||||
*(.gnu.linkonce*)
|
||||
. = ALIGN(4096);
|
||||
}
|
||||
.data : {
|
||||
data = .; _data = .; __data = .;
|
||||
*(.data)
|
||||
*(.rodata)
|
||||
. = ALIGN(4096);
|
||||
}
|
||||
.bss : {
|
||||
bss = .; _bss = .; __bss = .;
|
||||
*(.bss)
|
||||
. = ALIGN(4096);
|
||||
}
|
||||
end = .; _end = .; __end = .;
|
||||
}
|
155
kernel/mm/mm.c
Normal file
155
kernel/mm/mm.c
Normal file
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
27
kernel/mm/mm.h
Normal file
27
kernel/mm/mm.h
Normal file
@ -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
kernel/mm/vmm.c
Normal file
528
kernel/mm/vmm.c
Normal file
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
58
kernel/mm/vmm.h
Normal file
58
kernel/mm/vmm.h
Normal file
@ -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
|
||||
|
||||
|
16
kernel/module.h
Normal file
16
kernel/module.h
Normal file
@ -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
|
||||
|
145
kernel/multiboot.h
Normal file
145
kernel/multiboot.h
Normal file
@ -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
|
||||
|
117
kernel/proc/hash.cpp
Normal file
117
kernel/proc/hash.cpp
Normal file
@ -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");
|
||||
}
|
||||
|
58
kernel/proc/hash.h
Normal file
58
kernel/proc/hash.h
Normal file
@ -0,0 +1,58 @@
|
||||
// hash.h
|
||||
// Author: Josh Holtrop
|
||||
// Date: 08/28/05
|
||||
// Modified: 08/28/05
|
||||
// Implements a basic hash table (u32_t -> void*)
|
||||
|
||||
#ifndef __HOS_HASH_H__
|
||||
#define __HOS_HASH_H__ __HOS_HASH_H__
|
||||
|
||||
#include "hos_defines.h"
|
||||
#include "lang/vector.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32_t key;
|
||||
void *data;
|
||||
} hash_entry_t;
|
||||
|
||||
class hash
|
||||
{
|
||||
private:
|
||||
/* index into hash_primes[] */
|
||||
u32_t mySizeIndex;
|
||||
|
||||
/* How many values in the hash table */
|
||||
u32_t mySize;
|
||||
|
||||
/* array of hash entries */
|
||||
vector< vector<hash_entry_t> > myTable;
|
||||
|
||||
/* hash the key to a table index */
|
||||
u32_t hash_key(u32_t key);
|
||||
|
||||
public:
|
||||
/* Constructor */
|
||||
hash();
|
||||
|
||||
/* Add a value to the hash table */
|
||||
int add(u32_t key, void *val);
|
||||
|
||||
/* Retrieve a value from the hash table */
|
||||
void *get(u32_t key);
|
||||
|
||||
/* Remove a value from the hash table */
|
||||
int remove(u32_t key);
|
||||
|
||||
/* Check if the given key exists in the hash table */
|
||||
int exists(u32_t key);
|
||||
|
||||
/* Dump a hash */
|
||||
void dump();
|
||||
|
||||
/* How many values are in the hash table */
|
||||
u32_t size();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
214
kernel/proc/proc.cpp
Normal file
214
kernel/proc/proc.cpp
Normal file
@ -0,0 +1,214 @@
|
||||
// proc.c
|
||||
// Author: Josh Holtrop
|
||||
// Date; 08/18/05
|
||||
// Modified: 08/18/05
|
||||
|
||||
extern "C" {
|
||||
|
||||
#include "hos_defines.h"
|
||||
#include "mm/mm.h"
|
||||
#include "mm/vmm.h"
|
||||
#include "lang/lang.h"
|
||||
#include "kernel.h"
|
||||
#include "functions.h" //halt()
|
||||
|
||||
#include "display/kout.h"
|
||||
|
||||
extern u32_t mm_freepages;
|
||||
|
||||
}
|
||||
|
||||
#include "proc.h"
|
||||
#include "proc/hash.h"
|
||||
|
||||
extern "C" {
|
||||
u32_t cur_task = 0; /* PID of currently executing process */
|
||||
u32_t n_processes = 0; /* total number of processes */
|
||||
tss_t tss0;
|
||||
u32_t pid_base = 1024;
|
||||
u32_t pid_index = 0; /* index of running process in 'pids' vector */
|
||||
}
|
||||
|
||||
hash *processes;
|
||||
vector<u32_t> *pids;
|
||||
|
||||
int proc_init()
|
||||
{
|
||||
/* initialize tss0 */
|
||||
memset(&tss0, 0, sizeof(tss_t));
|
||||
tss0.ss0 = SEG_KERNEL_DATA;
|
||||
tss0.esp0 = VIRT_STACK_TOP;
|
||||
processes = new hash();
|
||||
process_t *proc = (process_t *)New(process_t);
|
||||
proc->p_page_dir = read_cr3();
|
||||
proc->page_dir = (u32_t *)0xFFFFF000;
|
||||
processes->add(0, proc);
|
||||
pids = new vector<u32_t>();
|
||||
pids->add(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
process_t *proc_get_struct(u32_t pid)
|
||||
{
|
||||
return (process_t *) processes->get(pid);
|
||||
}
|
||||
|
||||
void proc_sched(int_stack_t *int_stack)
|
||||
{
|
||||
u32_t new_pid_index = (pid_index + 1) % pids->size();
|
||||
switch_task(int_stack, (*pids)[new_pid_index]);
|
||||
pid_index = new_pid_index;
|
||||
}
|
||||
|
||||
u32_t get_pid()
|
||||
{
|
||||
u32_t potential = pid_base;
|
||||
while (processes->exists(potential))
|
||||
{
|
||||
potential++;
|
||||
if (potential == 0)
|
||||
potential = PROC_MIN_USER_PID;
|
||||
}
|
||||
pid_base = potential + 1;
|
||||
if (pid_base == 0)
|
||||
pid_base = PROC_MIN_USER_PID;
|
||||
return potential;
|
||||
}
|
||||
|
||||
void switch_task(int_stack_t *int_stack, u32_t new_task)
|
||||
{
|
||||
memcpy(&((process_t *)processes->get(cur_task))->int_stack, int_stack,
|
||||
sizeof(int_stack_t));
|
||||
cur_task = new_task;
|
||||
memcpy(int_stack, &((process_t *)processes->get(cur_task))->int_stack,
|
||||
sizeof(int_stack_t));
|
||||
write_cr3( ((process_t *)processes->get(cur_task))->p_page_dir );
|
||||
}
|
||||
|
||||
u32_t create_task(void *base, u32_t image_size, u32_t bss_size, void *entry)
|
||||
{
|
||||
u32_t pid = get_pid();
|
||||
processes->add(pid, create_process(base, image_size, bss_size, entry));
|
||||
pids->add(pid);
|
||||
return pid;
|
||||
}
|
||||
|
||||
/* Create process_t struct for a new process
|
||||
* image_size should be a multiple of 4096
|
||||
*/
|
||||
process_t *create_process(void *base, u32_t image_size, u32_t bss_size, void *entry)
|
||||
{
|
||||
if (mm_freepages < ((image_size + bss_size) >> 12) + 25)
|
||||
return 0;
|
||||
process_t *process = (process_t *) New(process_t); /* Allocate process_t struct */
|
||||
create_address_space(process);
|
||||
create_process_stack(process, entry);
|
||||
int i;
|
||||
u32_t *ptr32 = process->v_page_dir = (u32_t *) vmm_palloc();
|
||||
for (i = 0; i < 1024; i++)
|
||||
*ptr32++ = 0;
|
||||
u32_t code_data_pages = (image_size + 4095) >> 12;
|
||||
u32_t bss_pages = (bss_size + 4095) >> 12;
|
||||
/* Load program at address 0 */
|
||||
copy_into_address_space(0, (char *) base, code_data_pages, process);
|
||||
zero_address_space(code_data_pages << 12, bss_pages, process);
|
||||
ptr32 = process->v_page_dir;
|
||||
for (i = 0; i < 1024; i++)
|
||||
if (*ptr32)
|
||||
vmm_unmapp((void *)*ptr32);
|
||||
vmm_unmapp(process->v_page_dir);
|
||||
process->v_page_dir = 0;
|
||||
process->size = image_size + bss_size;
|
||||
return process;
|
||||
}
|
||||
|
||||
void create_address_space(process_t *p)
|
||||
{
|
||||
/* Allocate a new page directory */
|
||||
p->page_dir = (u32_t *) vmm_palloc_addr(&p->p_page_dir);
|
||||
int i;
|
||||
u32_t *ptr32 = p->page_dir;
|
||||
for (i = 0; i < 768; i++) /* zero 3 gigs */
|
||||
*ptr32++ = 0;
|
||||
memcpyd(ptr32, (void *)0xFFFFFC00, 256); /* 1 gig kernel mem */
|
||||
}
|
||||
|
||||
void create_process_stack(process_t *p, void *entry)
|
||||
{
|
||||
u32_t p_stack_table, p_stack;
|
||||
u32_t *v_stack_table = (u32_t *) vmm_palloc_addr(&p_stack_table);
|
||||
u32_t *v_stack = (u32_t *) vmm_palloc_addr(&p_stack);
|
||||
int i;
|
||||
u32_t *ptr32 = v_stack_table;
|
||||
for (i = 0; i < 1023; i++)
|
||||
*ptr32++ = 0;
|
||||
v_stack_table[1023] = p_stack | 0x7; /* user permissions */
|
||||
p->page_dir[511] = p_stack_table | 0x7; /* stack at 2GB */
|
||||
vmm_unmapp(v_stack_table);
|
||||
vmm_unmapp(v_stack);
|
||||
p->int_stack.ds = SEG_USER_DATA | 0x3;
|
||||
p->int_stack.es = SEG_USER_DATA | 0x3;
|
||||
p->int_stack.fs = SEG_USER_DATA | 0x3;
|
||||
p->int_stack.gs = SEG_USER_DATA | 0x3;
|
||||
p->int_stack.ss = SEG_USER_DATA | 0x3;
|
||||
p->int_stack.esp = 0x80000000; /* esp at 2GB */
|
||||
p->int_stack.eflags = 0x0202;
|
||||
p->int_stack.cs = SEG_USER_CODE | 0x3;
|
||||
p->int_stack.eip = (u32_t)entry;
|
||||
}
|
||||
|
||||
/* Copy pages into new address space (v_page_dir must be set up) */
|
||||
void copy_into_address_space(u32_t dest_addr,
|
||||
char *src_addr,
|
||||
u32_t pages,
|
||||
process_t *p)
|
||||
{
|
||||
u32_t pde, pte;
|
||||
void *page;
|
||||
while (pages)
|
||||
{
|
||||
pde = dest_addr >> 22;
|
||||
pte = (dest_addr >> 12) & 0x3FF;
|
||||
u32_t p_page_addr;
|
||||
if (!p->v_page_dir[pde])
|
||||
{
|
||||
/* Time for a new page table & page directory entry! */
|
||||
p->v_page_dir[pde] = (u32_t)vmm_palloc_addr(&p_page_addr);
|
||||
p->page_dir[pde] = p_page_addr | 0x7;
|
||||
}
|
||||
page = vmm_palloc_addr(&p_page_addr);
|
||||
((u32_t *)(p->v_page_dir[pde]))[pte] = p_page_addr | 0x7;
|
||||
memcpyd(page, src_addr, 1024);
|
||||
vmm_unmapp(page);
|
||||
dest_addr += 4096;
|
||||
src_addr += 4096;
|
||||
pages--;
|
||||
}
|
||||
}
|
||||
|
||||
/* Zeros pages into new address space (v_page_dir must be set up) */
|
||||
void zero_address_space(u32_t dest_addr, u32_t pages, process_t *p)
|
||||
{
|
||||
u32_t pde, pte;
|
||||
void *page;
|
||||
while (pages)
|
||||
{
|
||||
pde = dest_addr >> 22;
|
||||
pte = (dest_addr >> 12) & 0x3FF;
|
||||
u32_t p_page_addr;
|
||||
if (!p->v_page_dir[pde])
|
||||
{
|
||||
/* Time for a new page table & page directory entry! */
|
||||
p->v_page_dir[pde] = (u32_t)vmm_palloc_addr(&p_page_addr);
|
||||
p->page_dir[pde] = p_page_addr | 0x7;
|
||||
vmm_unmapp((void *)p->v_page_dir[pde]);
|
||||
}
|
||||
page = vmm_palloc_addr(&p_page_addr);
|
||||
((u32_t *)(p->v_page_dir[pde]))[pte] = p_page_addr | 0x7;
|
||||
memsetd(page, 0, 1024);
|
||||
vmm_unmapp(page);
|
||||
dest_addr += 4096;
|
||||
pages--;
|
||||
}
|
||||
}
|
||||
|
91
kernel/proc/proc.h
Normal file
91
kernel/proc/proc.h
Normal file
@ -0,0 +1,91 @@
|
||||
// proc.h
|
||||
// Author: Josh Holtrop
|
||||
// Date; 08/18/05
|
||||
// Modified: 08/18/05
|
||||
|
||||
#ifndef __HOS_PROC_H__
|
||||
#define __HOS_PROC_H__ __HOS_PROC_H__
|
||||
|
||||
#ifdef _HOS_CPP_
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "hos_defines.h"
|
||||
#include "kernel.h"
|
||||
|
||||
#define PROC_MIN_USER_PID 1024
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32_t *page_dir; /* Page directory with physical PT addys */
|
||||
u32_t *v_page_dir; /* Virtual page table addresses for init */
|
||||
u32_t p_page_dir; /* Physical address of page directory */
|
||||
u32_t size; /* Process size, bytes from 0 through bss */
|
||||
u32_t uid; /* Process owner */
|
||||
int_stack_t int_stack;
|
||||
} process_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u16_t backlink;
|
||||
u16_t reserved0;
|
||||
u32_t esp0;
|
||||
u16_t ss0;
|
||||
u16_t _ss0;
|
||||
u32_t esp1;
|
||||
u16_t ss1;
|
||||
u16_t _ss1;
|
||||
u32_t esp2;
|
||||
u16_t ss2;
|
||||
u16_t _ss2;
|
||||
u32_t pdbr;
|
||||
u32_t eip;
|
||||
u32_t eflags;
|
||||
u32_t eax;
|
||||
u32_t ecx;
|
||||
u32_t edx;
|
||||
u32_t ebx;
|
||||
u32_t esp;
|
||||
u32_t ebp;
|
||||
u32_t esi;
|
||||
u32_t edi;
|
||||
u16_t es;
|
||||
u16_t _es;
|
||||
u16_t cs;
|
||||
u16_t _cs;
|
||||
u16_t ss;
|
||||
u16_t _ss;
|
||||
u16_t ds;
|
||||
u16_t _ds;
|
||||
u16_t fs;
|
||||
u16_t _fs;
|
||||
u16_t gs;
|
||||
u16_t _gs;
|
||||
u16_t ldt;
|
||||
u16_t _ldt;
|
||||
u16_t trap;
|
||||
u16_t iomap;
|
||||
} __attribute__((packed)) tss_t;
|
||||
|
||||
int proc_init();
|
||||
process_t *proc_get_struct(u32_t pid);
|
||||
|
||||
void proc_sched(int_stack_t *int_stack);
|
||||
u32_t get_pid();
|
||||
void switch_task(int_stack_t *int_stack, u32_t new_task);
|
||||
u32_t create_task(void *base, u32_t image_size, u32_t bss_size, void *entry);
|
||||
process_t *create_process(void *base, u32_t image_size, u32_t bss_size, void *entry);
|
||||
void create_address_space(process_t *p);
|
||||
void create_process_stack(process_t *p, void *entry);
|
||||
void copy_into_address_space(u32_t dest_addr,
|
||||
char *src_addr,
|
||||
u32_t pages,
|
||||
process_t *p);
|
||||
void zero_address_space(u32_t dest_addr, u32_t pages, process_t *p);
|
||||
|
||||
#ifdef _HOS_CPP_
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
42
kernel/sys/cmos.c
Normal file
42
kernel/sys/cmos.c
Normal file
@ -0,0 +1,42 @@
|
||||
// cmos.c
|
||||
// Author: Josh Holtrop
|
||||
// Created: 02/26/04
|
||||
// Implements various CMOS function calls
|
||||
|
||||
#include "hos_defines.h"
|
||||
#include "sys/cmos.h"
|
||||
#include "sys/io.h"
|
||||
|
||||
//Returns the cmos type of floppy disk drive 0 (0 = not present)
|
||||
unsigned char cmos_getfd0()
|
||||
{
|
||||
outportb(0x70, 0x10);
|
||||
return (inportb(0x71) >> 4);
|
||||
}
|
||||
|
||||
|
||||
//Returns the cmos type of floppy disk drive 1 (0 = not present)
|
||||
unsigned char cmos_getfd1()
|
||||
{
|
||||
outportb(0x70, 0x10);
|
||||
return (inportb(0x71) & 0x0F);
|
||||
}
|
||||
|
||||
|
||||
//Returns the cmos type of hard disk drive 0 (0 = not present)
|
||||
unsigned char cmos_gethd0()
|
||||
{
|
||||
outportb(0x70, 0x12);
|
||||
return (inportb(0x71) >> 4);
|
||||
}
|
||||
|
||||
|
||||
//Returns the cmos type of hard disk drive 1 (0 = not present)
|
||||
unsigned char cmos_gethd1()
|
||||
{
|
||||
outportb(0x70, 0x12);
|
||||
return (inportb(0x71) & 0x0F);
|
||||
}
|
||||
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user