Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f5e3507ba | ||
|
|
a9a6f6f4d4 | ||
|
|
2d009273a1 | ||
|
|
2b936758ff | ||
|
|
509009d134 | ||
|
|
0aaf5db5ad | ||
|
|
89d962e33a | ||
|
|
712337c485 | ||
|
|
761e3f0483 | ||
|
|
98abfc2af0 | ||
|
|
677551fba5 | ||
|
|
7daa1c5336 | ||
|
|
79ca453f66 | ||
|
|
0521733e20 | ||
|
|
396c5f3452 | ||
|
|
9e03bfc8b6 | ||
|
|
2b67ff6f49 | ||
|
|
daa29212d0 | ||
|
|
83a5b032f8 | ||
|
|
345ef6c9f3 | ||
|
|
e1682a2fe7 | ||
|
|
2cefd9441c | ||
|
|
da90bcc164 | ||
|
|
4689c11cc8 | ||
|
|
692cf2fc08 | ||
|
|
b0132c866e | ||
|
|
14792ef954 | ||
|
|
bb8ff09e3f | ||
|
|
dfeabc39aa | ||
|
|
14148e4d80 | ||
|
|
80774c48fe | ||
|
|
862b36b37b | ||
|
|
4638656aaf | ||
|
|
3381041a8f | ||
|
|
f09ed66826 | ||
|
|
ba5906c7a3 | ||
|
|
05183a3949 | ||
|
|
d8580a9393 | ||
|
|
50285aa33b | ||
|
|
ee63a84c0e | ||
|
|
76a243d894 | ||
|
|
6bad3f2b96 | ||
|
|
51948ce081 | ||
|
|
b40a68f581 | ||
|
|
55b7429d4e | ||
|
|
7b805f2495 | ||
|
|
2445034e43 | ||
|
|
3c531f3b7b | ||
|
|
11cc0c87f3 | ||
|
|
bad7f79ed1 | ||
|
|
78272f6bc3 | ||
|
|
396d5015d2 | ||
|
|
1bf14ddefa | ||
|
|
c0dd3b529e | ||
|
|
8a8f56decb | ||
|
|
b9c77827bd | ||
|
|
cd02211b21 | ||
|
|
a50c2a1233 | ||
|
|
07e8a0f4cf | ||
|
|
6d23c76e84 | ||
|
|
11da8cb162 | ||
|
|
1063a68a21 | ||
|
|
286b5e9ae1 | ||
|
|
d4aadbea38 | ||
|
|
dfb71cc759 | ||
|
|
872d562d6a | ||
|
|
0729754659 |
No files matched your search
@@ -5,13 +5,13 @@ megs: 32
|
||||
romimage: file=/usr/share/bochs/BIOS-bochs-latest, address=0xf0000
|
||||
vgaromimage: /usr/share/bochs/VGABIOS-lgpl-latest
|
||||
boot: floppy
|
||||
floppya: 1_44="/dev/fd0", status=inserted
|
||||
floppya: 1_44="hos.flp", status=inserted
|
||||
# no floppyb
|
||||
ata0: enabled=0
|
||||
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
|
||||
ata1: enabled=0
|
||||
ata2: enabled=0
|
||||
ata3: enabled=0
|
||||
parport1: enabled=1, file=""
|
||||
parport1: enabled=1, file="parallel.out"
|
||||
com1: enabled=1, dev=""
|
||||
usb1: enabled=1, ioaddr=0xff80, irq=10
|
||||
# no sb16
|
||||
@@ -24,20 +24,20 @@ ips: 500000
|
||||
text_snapshot_check: 0
|
||||
mouse: enabled=0
|
||||
private_colormap: enabled=0
|
||||
i440fxsupport: enabled=0
|
||||
clock: sync=none, time0=local
|
||||
i440fxsupport: enabled=1
|
||||
clock: sync=realtime, time0=local
|
||||
# no ne2k
|
||||
newharddrivesupport: enabled=1
|
||||
#newharddrivesupport: enabled=1
|
||||
# no loader
|
||||
log: -
|
||||
logprefix: %t%e%d
|
||||
debugger_log: -
|
||||
panic: action=fatal
|
||||
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=none
|
||||
user_shortcut: keys=ctrlaltdel
|
||||
# no cmosimage
|
||||
@@ -0,0 +1,6 @@
|
||||
/hos.flp
|
||||
/hos_initrd
|
||||
/hos_initrd.gz
|
||||
*.lst
|
||||
*.map
|
||||
*.bin
|
||||
@@ -1,117 +1,88 @@
|
||||
#####################################################################
|
||||
# Author: Josh Holtrop / Benjamen R. Meyer #
|
||||
# Date: 02/15/04 Modified: 06/07/04 #
|
||||
# Purpose: To build Josh Holtrop's OS (HOS) using GNU make #
|
||||
# Note: This makefile is for use on Linux & other Unix-like systems #
|
||||
#####################################################################
|
||||
# Makefile for HOS
|
||||
# Josh Holtrop
|
||||
# Created: 07/09/04
|
||||
|
||||
##############
|
||||
# Variables: #
|
||||
##############
|
||||
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
|
||||
|
||||
# Information for creating a floppy image
|
||||
# Note: FLOPPY_FS and FLOPPY_FAT_SIZE are related fields.
|
||||
# FLOPPY_FAT_SIZE should be either 12 or 16,
|
||||
# depending on if FLOPPY_FS is FAT12 or FAT16, respectively.
|
||||
MKDOSFS_PROG=mkdosfs
|
||||
FLOPPY_IMAGE=floppy.img
|
||||
FLOPPY_BLOCK_COUNT=1440
|
||||
FLOPPY_FS=FAT12
|
||||
FLOPPY_FAT_SIZE=12
|
||||
FLOPPY_MOUNT=./floppy_image
|
||||
# Do not print "Entering directory ..."
|
||||
MAKEFLAGS += --no-print-directory
|
||||
|
||||
# Floppy images are good for programs like VMware and Bochs Pentium Emulator. ;-)
|
||||
.PHONY: all clean initrd apps grub_image install install_img depend copy_image bochs bochsq
|
||||
|
||||
# Program for copying
|
||||
COPY_BIN=cp
|
||||
|
||||
##########################################
|
||||
# Build the IPL (Boot Loader) and Kernel #
|
||||
##########################################
|
||||
all:
|
||||
# A word of warning to users :-> And a little helpful information ;-)
|
||||
@echo "Installation must be done as root."
|
||||
@echo "Type 'make install' to install to a floppy in drive '/dev/fd0'"
|
||||
@echo "Type 'make install_img' to create a floppy image and install to it."
|
||||
${MAKE} -C kernel
|
||||
${MAKE} -C rmmod
|
||||
|
||||
make -C boot
|
||||
make -C kernel
|
||||
|
||||
#################################################
|
||||
# Clean up the source directory of any binaries #
|
||||
#################################################
|
||||
clean:
|
||||
make -C boot clean
|
||||
make -C kernel 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
|
||||
|
||||
###########################################
|
||||
# The following is for the floppy drive #
|
||||
# Note: This must be done on *nix as root #
|
||||
###########################################
|
||||
copy_image:
|
||||
cp $(GRUB_IMAGE) $(FLOPPY_IMAGE)
|
||||
|
||||
##########################
|
||||
# Make install to floppy #
|
||||
##########################
|
||||
install: Install_IPL File_Copy
|
||||
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)
|
||||
|
||||
############################################
|
||||
# Write the Stage 1 IPL to the boot sector #
|
||||
############################################
|
||||
Install_IPL:
|
||||
$(MKDOSFS_PROG) /dev/fd0
|
||||
dd if=boot/stage1.bin of=/dev/fd0
|
||||
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
|
||||
|
||||
#################################
|
||||
# Copy the files onto the drive #
|
||||
#################################
|
||||
File_Copy:
|
||||
- mkdir floppy_mount
|
||||
@echo "Mounting floppy to ./floppy_mount..."
|
||||
mount /dev/fd0 ./floppy_mount
|
||||
depend:
|
||||
${MAKE} -C kernel depend
|
||||
|
||||
@echo "Copying stage 2 bootloader to the floppy..."
|
||||
$(COPY_BIN) boot/stage2.bin ./floppy_mount
|
||||
bochs:
|
||||
bochs
|
||||
|
||||
@echo "Copying kernel to the floppy..."
|
||||
$(COPY_BIN) kernel/kernel.bin ./floppy_mount
|
||||
|
||||
@echo "Unmounting floppy..."
|
||||
umount ./floppy_mount
|
||||
- rm -rf floppy_mount
|
||||
|
||||
|
||||
############################################
|
||||
# The following is for the floppy image. #
|
||||
# Note: This must be done on *nix as root. #
|
||||
############################################
|
||||
|
||||
######################################
|
||||
# Create and Format the floppy image #
|
||||
######################################
|
||||
install_img:
|
||||
$(MKDOSFS_PROG) -C -F $(FLOPPY_FAT_SIZE) -r 112 $(FLOPPY_IMAGE) $(FLOPPY_BLOCK_COUNT)
|
||||
|
||||
############################################
|
||||
# Write the Stage 1 IPL to the boot sector #
|
||||
############################################
|
||||
@echo "Writing boot sector to image..."
|
||||
dd if=boot/stage1.bin of=$(FLOPPY_IMAGE) seek=0
|
||||
|
||||
#################################
|
||||
# Copy the files onto the image #
|
||||
#################################
|
||||
- mkdir $(FLOPPY_MOUNT)
|
||||
@echo "Mounting floppy image..."
|
||||
mount $(FLOPPY_IMAGE) $(FLOPPY_MOUNT) -o loop
|
||||
|
||||
@echo "Copying stage 2 bootloader to the floppy image..."
|
||||
$(COPY_BIN) boot/stage2.bin $(FLOPPY_MOUNT)
|
||||
@echo "Copying kernel to the floppy image..."
|
||||
$(COPY_BIN) kernel/kernel.bin $(FLOPPY_MOUNT)
|
||||
|
||||
@echo "Unmounting floppy image..."
|
||||
mount $(FLOPPY_IMAGE) $(FLOPPY_MOUNT) -o loop
|
||||
bochsq:
|
||||
echo 'c' | bochs -q
|
||||
|
||||
wordcount:
|
||||
find . -regex '\(.*\.[ch]\)\|\(.*\.asm\)\|\(.*\.inc\)\|\(.*\.cpp\)' | xargs cat | wc
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
all:
|
||||
make -C hash
|
||||
nasm -f bin -l test1.lst test1.asm -o test1.app
|
||||
nasm -f bin test2.asm -o test2.app
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
all:
|
||||
nasm -f bin hash.asm -o hash
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
�0�
|
||||
@@ -0,0 +1,6 @@
|
||||
|
||||
[bits 32]
|
||||
|
||||
begin:
|
||||
int 0x30
|
||||
ret
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
; test app 1
|
||||
|
||||
[bits 32]
|
||||
org 0x0
|
||||
|
||||
;header:
|
||||
; dd 0x4D534F48 ; magic identifier "HOSM"
|
||||
; dd 2 ; test app
|
||||
; dd start ; start address
|
||||
; dd 0 ; reserved
|
||||
|
||||
start:
|
||||
mov ebx, astring
|
||||
mov eax, 2
|
||||
int 0x30
|
||||
jmp start
|
||||
ret
|
||||
|
||||
astring:
|
||||
db "Hello there from test1!", 10, 0
|
||||
@@ -0,0 +1,22 @@
|
||||
1 ; test app 1
|
||||
2
|
||||
3 [bits 32]
|
||||
4 org 0x0
|
||||
5
|
||||
6 ;header:
|
||||
7 ; dd 0x4D534F48 ; magic identifier "HOSM"
|
||||
8 ; dd 2 ; test app
|
||||
9 ; dd start ; start address
|
||||
10 ; dd 0 ; reserved
|
||||
11
|
||||
12 start:
|
||||
13 00000000 BB[0F000000] mov ebx, astring
|
||||
14 00000005 B802000000 mov eax, 2
|
||||
15 0000000A CD30 int 0x30
|
||||
16 0000000C EBF2 jmp start
|
||||
17 0000000E C3 ret
|
||||
18
|
||||
19 astring:
|
||||
20 0000000F 48656C6C6F20746865- db "Hello there from test1!", 10, 0
|
||||
21 00000018 72652066726F6D2074-
|
||||
22 00000021 65737431210A00
|
||||
Binary file not shown.
@@ -0,0 +1,17 @@
|
||||
; test app 1
|
||||
|
||||
[bits 32]
|
||||
org 0x0
|
||||
|
||||
;header:
|
||||
; dd 0x4D534F48 ; magic identifier "HOSM"
|
||||
; dd 2 ; test app
|
||||
; dd start ; start address
|
||||
; dd 0 ; reserved
|
||||
|
||||
start:
|
||||
mov eax, 1
|
||||
mov ebx, 'i'
|
||||
int 0x30
|
||||
jmp start
|
||||
ret
|
||||
@@ -1,32 +0,0 @@
|
||||
#####################################################################
|
||||
# Author: Josh Holtrop / Benjamen R. Meyer #
|
||||
# Date: 02/15/04 #
|
||||
# Purpose: To build Josh Holtrop's OS (HOS) using GNU make #
|
||||
# Note: This makefile is for use on Linux & other Unix-like systems #
|
||||
#####################################################################
|
||||
|
||||
# Assembler information:
|
||||
NASM_BIN=nasm
|
||||
|
||||
#################
|
||||
# Build the IPL #
|
||||
#################
|
||||
all: stage1 stage2
|
||||
|
||||
################
|
||||
# IPL: Stage 1 #
|
||||
################
|
||||
stage1: stage1.asm
|
||||
$(NASM_BIN) stage1.asm -o stage1.bin
|
||||
|
||||
################
|
||||
# IPL: Stage 2 #
|
||||
################
|
||||
stage2: stage2.asm
|
||||
$(NASM_BIN) stage2.asm -o stage2.bin
|
||||
|
||||
#########
|
||||
# Clean #
|
||||
#########
|
||||
clean:
|
||||
- rm *.bin *~
|
||||
@@ -1,26 +0,0 @@
|
||||
|
||||
%define VERSION "0.03" ;HOS bootloader version
|
||||
|
||||
%define BOOT_FAT_SEG 0x07E0 ;right after boot sector
|
||||
%define BOOT_ROOT_SEG 0x0900 ;right after FAT
|
||||
%define BOOT_KERNEL_SEG 0x0AC0 ;right after ROOT_DIR
|
||||
%define BOOT_STAGE2_SEG 0x0B00 ;right after KERNEL_SEG
|
||||
%define BOOT_STAGE2_ADD 0xB000 ;address of stage2 to jump to, org at
|
||||
%define BOOT_KERNEL_ADD 0x106000 ;final pmode kernel destination - physical
|
||||
%define BOOT_RD_ADD 0x200000 ;2mb for ram disk
|
||||
|
||||
%define BOOT_DATA_SEG 0x9000 ;data gathered by stage2 loader goes here
|
||||
|
||||
%define BOOT_HASRD 0x0000 ;1
|
||||
%define BOOT_VESA 0x0002 ;2 - 0 for console, otherwise VESA mode
|
||||
%define BOOT_VESA_OEM 0x0004 ;258 - null-terminated OEM identification string
|
||||
%define BOOT_VESA_VBE 0x0106 ;512 - copy of VESA VBEInfoBlock
|
||||
%define BOOT_VESA_INFO 0x0306 ;256 - copy of VESA ModeInfoBlock for selected mode
|
||||
%define BOOT_MEMENTRIES 0x040A ;4 - dword = number of memmap entries
|
||||
%define BOOT_MEMMAP 0x2000 ;? - memory map information
|
||||
|
||||
|
||||
|
||||
%define BOOT_DRIVE 0x7C24 ;1 - boot drive
|
||||
|
||||
|
||||
-235
@@ -1,235 +0,0 @@
|
||||
|
||||
;stage1.asm
|
||||
;This is the stage1 section of the HOS bootloader
|
||||
;It is 512 bytes to be put on the first sector of a floppy
|
||||
;Author: Josh Holtrop
|
||||
;Date: 03/11/04
|
||||
;Modified: 05/21/04
|
||||
|
||||
%include "bootdef.inc"
|
||||
|
||||
[bits 16]
|
||||
|
||||
org 0x7c00
|
||||
|
||||
jmp short start
|
||||
|
||||
; --------------------------------------------------
|
||||
; data portion of the "DOS BOOT RECORD"
|
||||
; ----------------------------------------------------------------------
|
||||
brINT13Flag DB 90H ; 0002h - 0EH for INT13 AH=42 READ
|
||||
brOEM DB 'MSDOS5.0' ; 0003h - OEM ID - Windows 95B
|
||||
brBPS DW 512 ; 000Bh - Bytes per sector
|
||||
brSPC DB 1 ; 000Dh - Sector per cluster
|
||||
brSc_b4_fat DW 1 ; 000Eh - Reserved sectors
|
||||
brFATs DB 2 ; 0010h - FAT copies
|
||||
brRootEntries DW 0E0H ; 0011h - Root directory entries
|
||||
brSectorCount DW 2880 ; 0013h - Sectors in volume, < 32MB
|
||||
brMedia DB 240 ; 0015h - Media descriptor
|
||||
brSPF DW 9 ; 0016h - Sectors per FAT
|
||||
brSc_p_trk DW 18 ; 0018h - Sectors per head/track
|
||||
brHPC DW 2 ; 001Ah - Heads per cylinder
|
||||
brSc_b4_prt DD 0 ; 001Ch - Hidden sectors
|
||||
brSectors DD 0 ; 0020h - Total number of sectors
|
||||
brDrive DB 0 ; 0024h - Physical drive no.
|
||||
DB 0 ; 0025h - Reserved (FAT32)
|
||||
DB 29H ; 0026h - Extended boot record sig (FAT32)
|
||||
brSerialNum DD 404418EAH ; 0027h - Volume serial number
|
||||
brLabel DB 'Holtrops OS' ; 002Bh - Volume label
|
||||
brFSID DB 'FAT12 ' ; 0036h - File System ID
|
||||
;------------------------------------------------------------------------
|
||||
|
||||
start:
|
||||
jmp 0:jmphere ;ensure that cs=0 and ip=0x7c00...
|
||||
jmphere:
|
||||
;dl=drive number, save it!
|
||||
xor ax, ax
|
||||
mov ds, ax
|
||||
mov [brDrive], dl
|
||||
cli
|
||||
mov ss, ax
|
||||
mov sp, 0x7Bfe ;right under boot sector
|
||||
sti
|
||||
|
||||
mov ax, 0xb800
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
|
||||
xor di, di
|
||||
mov ax, 0x0700
|
||||
mov cx, 2000
|
||||
cls:
|
||||
stosw
|
||||
loop cls
|
||||
|
||||
enable_a20:
|
||||
in al, 0x64
|
||||
test al, 2
|
||||
jnz enable_a20
|
||||
mov al, 0xD1
|
||||
out 0x64, al
|
||||
ea20_2: in al, 0x64
|
||||
and ax, byte 2
|
||||
jnz ea20_2
|
||||
mov al, 0xDF
|
||||
out 0x60, al
|
||||
|
||||
unreal:
|
||||
xor ax, ax
|
||||
mov es, ax
|
||||
mov ds, ax
|
||||
|
||||
lgdt [gdtr] ;load gdt
|
||||
cli
|
||||
push es
|
||||
push ds ;save segment values
|
||||
mov ebx, cr0
|
||||
inc bl
|
||||
mov cr0, ebx ;pmode!
|
||||
mov ax, KERNEL_DATA
|
||||
mov es, ax
|
||||
mov ds, ax ;load segment limits
|
||||
dec bl
|
||||
mov cr0, ebx ;back to real mode!
|
||||
pop ds
|
||||
pop es ;segments back, with 4gb limits!
|
||||
sti
|
||||
|
||||
;now lets read in the FAT and root directory so we can search for the stage2 file...
|
||||
mov ax, 0x0209 ;FAT1
|
||||
mov cx, 0x0002
|
||||
xor dh, dh
|
||||
mov dl, [brDrive]
|
||||
mov bx, BOOT_FAT_SEG
|
||||
mov es, bx
|
||||
xor bx, bx
|
||||
int 0x13
|
||||
|
||||
mov ax, 0x020E ;root directory
|
||||
mov cx, 0x0002 ;cyl/sect
|
||||
mov dh, 0x01 ;head
|
||||
mov dl, [brDrive] ;drive
|
||||
mov bx, BOOT_ROOT_SEG
|
||||
mov es, bx
|
||||
xor bx, bx
|
||||
int 0x13
|
||||
|
||||
;k now read root directory
|
||||
mov bx, BOOT_ROOT_SEG
|
||||
mov ds, bx
|
||||
xor si, si ;k now ds:si points to beginning of root directory
|
||||
mov es, si
|
||||
mov cx, 224 ;max root entries
|
||||
loop_compare:
|
||||
mov di, stage2
|
||||
push cx
|
||||
push si ;save pointer to root dir entry
|
||||
mov cx, 11
|
||||
loop_name:
|
||||
cmpsb
|
||||
loopz loop_name
|
||||
jnz goon ;cx didn't get to zero, bad file
|
||||
pop si
|
||||
pop cx
|
||||
jmp found_file ;good file, ds:si points to start of root directory entry
|
||||
goon:
|
||||
pop si
|
||||
pop cx
|
||||
add si, 32
|
||||
loop loop_compare
|
||||
|
||||
error:
|
||||
jmp $ ;halt! no kernel file found!
|
||||
|
||||
found_file: ;ds:si points to root dir entry
|
||||
xor ax, ax
|
||||
mov gs, ax
|
||||
mov ax, BOOT_STAGE2_SEG
|
||||
mov es, ax
|
||||
|
||||
mov ax, [ds:si+26]
|
||||
mov bx, BOOT_FAT_SEG
|
||||
mov ds, bx ;ds points to beginning of FAT
|
||||
xor di, di
|
||||
|
||||
readstage2_loop:
|
||||
cmp ax, 0xff7
|
||||
jg readstage2_done
|
||||
inc di
|
||||
push ax
|
||||
call getCHSfromCluster
|
||||
mov ax, 0x0201
|
||||
mov dl, [gs:BOOT_DRIVE]
|
||||
xor bx, bx
|
||||
int 0x13
|
||||
mov bx, es
|
||||
add bx, 0x0020
|
||||
mov es, bx
|
||||
pop ax ;current logical cluster #
|
||||
|
||||
mov cx, ax ;cx=logical cluster
|
||||
mov dx, 3
|
||||
mul dx
|
||||
shr ax, 1 ;ax=logical cluster * 3 / 2
|
||||
mov si, ax
|
||||
test cl, 1 ;is bit0 set?
|
||||
jnz odd_cluster
|
||||
even_cluster:
|
||||
lodsw
|
||||
and ax, 0x0fff
|
||||
jmp got_cluster
|
||||
odd_cluster:
|
||||
lodsw
|
||||
shr ax, 4
|
||||
got_cluster:
|
||||
jmp readstage2_loop
|
||||
|
||||
readstage2_done:
|
||||
|
||||
jmp 0:BOOT_STAGE2_ADD
|
||||
|
||||
;------------------------------------------------------
|
||||
getCHSfromCluster:
|
||||
;input: ax=lba of sector on floppy (0-2879)
|
||||
add ax, 31 ;convert logical cluster# to lba#
|
||||
xor dx, dx ;lba->chs
|
||||
mov bx, 18
|
||||
div bx
|
||||
inc dx
|
||||
mov cl, dl ;sector# (1-18)
|
||||
xor dx, dx
|
||||
mov bx, 2
|
||||
div bx
|
||||
mov ch, al ;cylinder# (0-79)
|
||||
mov dh, dl ;head# (0-1)
|
||||
ret
|
||||
|
||||
|
||||
;-------------------------------------------------------
|
||||
gdtr:
|
||||
dw gdt_end-gdt-1
|
||||
dd gdt
|
||||
gdt:
|
||||
dd 0
|
||||
dd 0
|
||||
|
||||
KERNEL_DATA equ $-gdt
|
||||
db 0xff ;segment 16 = 4gb data
|
||||
db 0xff
|
||||
db 0x00
|
||||
db 0x00
|
||||
db 0x00
|
||||
db 0x92
|
||||
db 0xcf ;cf
|
||||
db 0x00
|
||||
|
||||
gdt_end:
|
||||
|
||||
|
||||
|
||||
stage2: db "STAGE2 BIN"
|
||||
|
||||
times 510-($-$$) db 0
|
||||
|
||||
db 0x55, 0xaa
|
||||
|
||||
-978
@@ -1,978 +0,0 @@
|
||||
|
||||
;stage2.asm
|
||||
;This is the stage2 section of the HOS bootloader
|
||||
;It is to be copied into the normal FAT12 filesystem to be loaded by stage1
|
||||
;Author: Josh Holtrop
|
||||
;Date: 03/11/04
|
||||
;Modified: 05/21/04
|
||||
|
||||
%include "bootdef.inc"
|
||||
|
||||
%define VESA_MODEINFO_SEG 0x0120
|
||||
%define VESA_MODELIST_SEG 0x0140
|
||||
%define GOOD_MODELIST_SEG 0x0160
|
||||
|
||||
[bits 16]
|
||||
|
||||
org BOOT_STAGE2_ADD
|
||||
|
||||
|
||||
;k now read root directory
|
||||
mov bx, BOOT_ROOT_SEG
|
||||
mov ds, bx
|
||||
xor si, si ;k now ds:si points to beginning of root directory
|
||||
mov es, si
|
||||
mov cx, 224 ;max root entries
|
||||
loop_compare:
|
||||
mov di, kernel
|
||||
push cx
|
||||
push si ;save pointer to root dir entry
|
||||
mov cx, 11
|
||||
loop_name:
|
||||
cmpsb
|
||||
loopz loop_name
|
||||
jnz goon ;cx didn't get to zero, bad file
|
||||
pop si
|
||||
pop cx
|
||||
jmp found_file ;good file, ds:si points to start of root directory entry
|
||||
goon:
|
||||
pop si
|
||||
add si, 32
|
||||
pop cx
|
||||
loop loop_compare
|
||||
|
||||
error:
|
||||
jmp $ ;halt! no kernel file found!
|
||||
|
||||
found_file: ;ds:si points to root dir entry of kernel file
|
||||
xor ax, ax
|
||||
mov gs, ax
|
||||
mov ax, [ds:si+26]
|
||||
mov bx, BOOT_FAT_SEG
|
||||
mov ds, bx ;ds points to beginning of FAT
|
||||
mov edi, BOOT_KERNEL_ADD
|
||||
|
||||
readkernel_loop:
|
||||
cmp ax, 0xff7
|
||||
jg readkernel_done
|
||||
push ax
|
||||
call getCHSfromCluster
|
||||
mov ax, 0x0201
|
||||
mov dl, [gs:BOOT_DRIVE]
|
||||
mov bx, BOOT_KERNEL_SEG
|
||||
mov es, bx
|
||||
xor bx, bx
|
||||
int 0x13
|
||||
mov cx, 256
|
||||
xor ax, ax
|
||||
mov es, ax
|
||||
mov esi, BOOT_KERNEL_SEG*16
|
||||
copykernel_loop:
|
||||
mov ax, [es:esi]
|
||||
mov [es:edi], ax
|
||||
inc esi
|
||||
inc esi
|
||||
inc edi
|
||||
inc edi
|
||||
loop copykernel_loop
|
||||
|
||||
pop ax ;current logical cluster #
|
||||
|
||||
mov cx, ax ;cx=logical cluster
|
||||
mov dx, 3
|
||||
mul dx
|
||||
shr ax, 1 ;ax=logical cluster * 3 / 2
|
||||
mov si, ax
|
||||
test cl, 1 ;is bit0 set?
|
||||
jnz odd_cluster
|
||||
even_cluster:
|
||||
lodsw
|
||||
and ax, 0x0fff
|
||||
jmp got_cluster
|
||||
odd_cluster:
|
||||
lodsw
|
||||
shr ax, 4
|
||||
got_cluster:
|
||||
jmp readkernel_loop
|
||||
|
||||
;------------------------------------------------------
|
||||
readkernel_done: ;-------------put more real mode init stuff here!
|
||||
;----ask to load RD from floppy
|
||||
mov ax, 0xb800
|
||||
mov es, ax
|
||||
xor ax, ax
|
||||
mov ds, ax
|
||||
xor di, di
|
||||
mov cx, 2000
|
||||
mov ax, 0x0700
|
||||
cls_loop:
|
||||
stosw
|
||||
loop cls_loop
|
||||
|
||||
mov dx, 0x3d4 ;move cursor off screen...
|
||||
mov al, 0x0e
|
||||
out dx, al
|
||||
inc dx
|
||||
mov al, 0xff
|
||||
out dx, al
|
||||
dec dx
|
||||
mov al, 0x0f
|
||||
out dx, al
|
||||
inc dx
|
||||
out dx, al
|
||||
|
||||
xor di, di
|
||||
mov si, txt_welcome
|
||||
mov ah, 0x1f
|
||||
call puts
|
||||
|
||||
mov di, 160
|
||||
mov si, txt_rd1
|
||||
mov ah, 7
|
||||
call puts
|
||||
|
||||
mov si, txt_rd2
|
||||
mov di, 160*2
|
||||
call puts
|
||||
|
||||
mov di, 160*3
|
||||
mov si, txt_input
|
||||
call puts
|
||||
|
||||
get_rd:
|
||||
xor ax, ax
|
||||
int 0x16
|
||||
cmp al, '1'
|
||||
jz got_rd
|
||||
cmp al, '2'
|
||||
jnz get_rd
|
||||
got_rd:
|
||||
stosb
|
||||
sub al, '1'
|
||||
push ds
|
||||
mov bx, BOOT_DATA_SEG ;segment for data to send kernel
|
||||
mov ds, bx
|
||||
mov [ds:BOOT_HASRD], al
|
||||
pop ds ;ds=0
|
||||
cmp al, 0 ;dont load rd
|
||||
jnz yes_rd
|
||||
jmp no_rd
|
||||
yes_rd:
|
||||
mov cx, 80
|
||||
mov edi, 0xb8000+160*4
|
||||
filler_loop: ;draw a red bar
|
||||
mov word [ds:edi], 0x0400+177
|
||||
inc edi
|
||||
inc edi
|
||||
loop filler_loop
|
||||
|
||||
mov cx, 80 ;80 cylinders to read
|
||||
xor si, si ;start at cylinder 0
|
||||
mov edi, BOOT_RD_ADD ;ram disk address
|
||||
read_cylinder:
|
||||
push cx
|
||||
|
||||
mov bx, 0x0100 ;read sectors from head 0
|
||||
mov es, bx
|
||||
xor bx, bx ;es:bx = data buffer for read
|
||||
mov ax, 0x0212 ;ah = int 0x13 function 2, al = number of sectors to read
|
||||
mov cx, si ;what cyl. we are on is now in cx
|
||||
mov ch, cl ;ch = cyl. number
|
||||
mov cl, 1 ;cl = sector number 1-63
|
||||
xor dx, dx ;dh = head number
|
||||
mov dl, [gs:BOOT_DRIVE] ;dl = drive number
|
||||
int 0x13
|
||||
|
||||
mov bx, 0x0100 ;now read sectors from head 1
|
||||
mov es, bx
|
||||
mov bx, 9216 ;es:bx = data buffer for read
|
||||
mov ax, 0x0212 ;ah = int 0x13 function 2, al = number of sectors to read
|
||||
mov cx, si ;what cyl. we are on is now in cx
|
||||
mov ch, cl ;ch = cyl. number
|
||||
mov cl, 1 ;cl = sector number 1-63
|
||||
mov dh, 1 ;dh = head number
|
||||
mov dl, [gs:BOOT_DRIVE] ;dl = drive number
|
||||
int 0x13
|
||||
|
||||
mov ebx, 0xb8000
|
||||
add bx, si
|
||||
shl bl, 1
|
||||
mov word [ds:ebx+160*4], 0x0200+219
|
||||
|
||||
push si
|
||||
mov esi, 0x1000
|
||||
mov cx, 0x2400
|
||||
copydisk_loop:
|
||||
mov ax, [ds:esi]
|
||||
inc esi
|
||||
inc esi
|
||||
mov [ds:edi], ax
|
||||
inc edi
|
||||
inc edi
|
||||
loop copydisk_loop
|
||||
|
||||
pop si ;what cylinder# we are on...
|
||||
inc si
|
||||
pop cx
|
||||
loop read_cylinder
|
||||
|
||||
;------------------------------------------------------
|
||||
no_rd:
|
||||
mov ax, BOOT_DATA_SEG
|
||||
mov es, ax
|
||||
mov di, BOOT_MEMMAP ;store memmap info in es:di for kernel
|
||||
xor edx, edx
|
||||
mov ax, 0x0100
|
||||
mov ds, ax
|
||||
xor ebx, ebx
|
||||
getmemmap_loop:
|
||||
push es
|
||||
push di
|
||||
push edx
|
||||
mov ax, 0x0100 ;get memory map
|
||||
mov es, ax
|
||||
xor di, di
|
||||
mov eax, 0x0000E820
|
||||
mov ecx, 0x00000014
|
||||
;mov ebx, 0x00000000
|
||||
mov edx, 0x534D4150 ;'SMAP'
|
||||
int 0x15
|
||||
jc getmemmap_carry
|
||||
cmp eax, 0x534D4150 ;eax should be 'SMAP' on return...
|
||||
jnz getmemmap_error
|
||||
cmp ebx, 0
|
||||
jz getmemmap_done
|
||||
|
||||
pop edx ;now, copy memmap entry to es:di on the stack
|
||||
pop di
|
||||
pop es
|
||||
xor si, si
|
||||
mov cx, 20
|
||||
getmemmap_copymem_loop:
|
||||
lodsb
|
||||
stosb
|
||||
loop getmemmap_copymem_loop
|
||||
inc edx
|
||||
jmp getmemmap_loop
|
||||
|
||||
getmemmap_error:
|
||||
mov ax, 0xb800
|
||||
mov es, ax
|
||||
mov di, 160*24
|
||||
xor ax, ax
|
||||
mov ds, ax
|
||||
mov si, txt_memerror
|
||||
mov ah, 0x04
|
||||
call puts
|
||||
hlt
|
||||
jmp $
|
||||
|
||||
getmemmap_carry:
|
||||
dec edx
|
||||
getmemmap_done:
|
||||
pop edx
|
||||
pop di
|
||||
pop es
|
||||
|
||||
xor si, si
|
||||
mov cx, 20
|
||||
getmemmap_done_copymem_loop:
|
||||
lodsb
|
||||
stosb
|
||||
loop getmemmap_done_copymem_loop
|
||||
inc edx
|
||||
|
||||
mov di, BOOT_MEMENTRIES
|
||||
mov [es:di], edx ;save # of memmap entries for kernel
|
||||
|
||||
;on to vesa info...
|
||||
xor ax, ax
|
||||
mov gs, ax
|
||||
mov ds, ax
|
||||
mov ax, 0xb800
|
||||
mov es, ax
|
||||
mov di, 160
|
||||
mov cx, 2000-80
|
||||
mov ax, 0x0700
|
||||
cls_vesa_loop:
|
||||
stosw
|
||||
loop cls_vesa_loop
|
||||
mov si, txt_vesa
|
||||
mov di, 160*1
|
||||
mov ah, 7
|
||||
call puts
|
||||
|
||||
push di
|
||||
mov ax, 0x0100
|
||||
mov es, ax
|
||||
xor di, di
|
||||
mov dword [es:di], "2EBV"
|
||||
mov ax, 0x4F00
|
||||
|
||||
int 0x10
|
||||
pop di
|
||||
cmp ax, 0x004F
|
||||
jz vesa_good
|
||||
mov si, txt_novesa
|
||||
mov ax, 0xb800
|
||||
mov es, ax
|
||||
mov ah, 7
|
||||
call puts
|
||||
mov ax, BOOT_DATA_SEG
|
||||
mov ds, ax
|
||||
mov word [ds:BOOT_VESA], 0
|
||||
jmp vesa_done
|
||||
vesa_good:
|
||||
mov ax, 0xb800
|
||||
mov es, ax
|
||||
mov ax, 0x0100
|
||||
mov ds, ax
|
||||
xor si, si
|
||||
mov bx, [4]
|
||||
mov al, bh
|
||||
call puthex
|
||||
mov al, '.'
|
||||
stosb
|
||||
mov al, 7
|
||||
stosb
|
||||
mov al, bl
|
||||
call puthex
|
||||
add di, 4
|
||||
cmp bh, 2
|
||||
jge vesa_good2
|
||||
xor ax, ax
|
||||
mov ds, ax
|
||||
mov si, txt_vesaold
|
||||
mov ah, 7
|
||||
call puts
|
||||
mov ax, BOOT_DATA_SEG
|
||||
mov ds, ax
|
||||
mov word [ds:BOOT_VESA], 0
|
||||
jmp vesa_done
|
||||
vesa_good2:
|
||||
mov ebx, [6] ;something like 0x00000E60
|
||||
mov edx, [14]
|
||||
mov si, bx
|
||||
shr ebx, 16
|
||||
mov ds, bx ;ds:si points to null-terminated OEM identification string
|
||||
mov ah, 2
|
||||
push si
|
||||
call puts
|
||||
pop si
|
||||
mov ax, BOOT_DATA_SEG
|
||||
mov es, ax
|
||||
mov di, BOOT_VESA_OEM
|
||||
vesa_copyoem:
|
||||
lodsb
|
||||
stosb
|
||||
or al, al
|
||||
jnz vesa_copyoem
|
||||
mov ax, 0x0100
|
||||
mov ds, ax
|
||||
xor si, si
|
||||
mov di, BOOT_VESA_VBE
|
||||
mov cx, 512
|
||||
vesa_copyvbe:
|
||||
lodsb
|
||||
stosb
|
||||
loop vesa_copyvbe
|
||||
|
||||
mov si, dx
|
||||
shr edx, 16
|
||||
mov ds, dx ;ds:si points to video mode list
|
||||
mov ax, VESA_MODELIST_SEG
|
||||
mov es, ax
|
||||
xor di, di
|
||||
vesa_copymodes:
|
||||
lodsw
|
||||
stosw
|
||||
cmp ax, 0xffff
|
||||
jnz vesa_copymodes
|
||||
|
||||
mov ax, GOOD_MODELIST_SEG
|
||||
mov es, ax
|
||||
xor di, di
|
||||
mov cx, 256
|
||||
mov ax, 0xffff
|
||||
clear_good_mode_list_loop:
|
||||
stosw
|
||||
loop clear_good_mode_list_loop
|
||||
|
||||
mov ax, VESA_MODELIST_SEG
|
||||
mov ds, ax
|
||||
xor si, si ;ds:si points to video mode list where we can edit it :)
|
||||
mov ax, GOOD_MODELIST_SEG
|
||||
mov es, ax
|
||||
xor di, di
|
||||
xor dx, dx ;dx=what good mode # we are on
|
||||
vesa_readmodeinfo_loop:
|
||||
lodsw
|
||||
cmp ax, 0xffff
|
||||
jz vesa_endofmodes
|
||||
push ax ;save mode#
|
||||
call checkmode
|
||||
cmp ax, 0
|
||||
jz vesa_readmodeinfo_good
|
||||
pop ax
|
||||
jmp vesa_readmodeinfo_loop
|
||||
vesa_readmodeinfo_good:
|
||||
pop ax ;restore mode#
|
||||
stosw
|
||||
call vesa_showmodeinfo
|
||||
inc dx
|
||||
jmp vesa_readmodeinfo_loop
|
||||
|
||||
vesa_endofmodes: ;here we have a list of good modes at GOOD_MODELIST_SEG:0
|
||||
xor ax, ax
|
||||
mov ds, ax
|
||||
mov si, txt_consolemode
|
||||
mov ax, 0xb800
|
||||
mov es, ax
|
||||
mov di, 160*2
|
||||
mov ah, 7
|
||||
call puts
|
||||
mov di, 160*3
|
||||
mov cx, dx
|
||||
mov al, 'b'
|
||||
vesa_displaylabels:
|
||||
stosb
|
||||
push ax
|
||||
mov al, 7
|
||||
stosb
|
||||
mov al, '.'
|
||||
stosb
|
||||
mov al, 7
|
||||
stosb
|
||||
pop ax
|
||||
inc al
|
||||
add di, 160-4
|
||||
loop vesa_displaylabels ;done drawing screen of VESA choices, now ask for one
|
||||
;valid options are 'a' through (al-1)
|
||||
mov bl, al
|
||||
xor ax, ax
|
||||
mov ds, ax
|
||||
mov di, 160*24
|
||||
mov si, txt_input
|
||||
mov ah, 14
|
||||
call puts
|
||||
vesa_getchoice:
|
||||
xor ax, ax
|
||||
int 0x16
|
||||
cmp al, 'a'
|
||||
jl vesa_getchoice
|
||||
cmp al, bl
|
||||
jge vesa_getchoice
|
||||
stosb
|
||||
push ax
|
||||
mov al, 14
|
||||
stosb
|
||||
pop ax
|
||||
xor ah, ah
|
||||
sub ax, 'a'
|
||||
cmp ax, 0
|
||||
jz vesa_consolemode_only
|
||||
mov cx, ax ;cx holds good mode# (1=first good vesa mode)
|
||||
dec cx
|
||||
mov ax, GOOD_MODELIST_SEG
|
||||
mov ds, ax
|
||||
shl cx, 1
|
||||
mov si, cx ;ds:si points to word containing selected mode#
|
||||
lodsw
|
||||
mov cx, ax
|
||||
mov dx, ax ;cx and dx hold mode#
|
||||
|
||||
mov ax, VESA_MODEINFO_SEG
|
||||
mov es, ax
|
||||
xor di, di
|
||||
mov ax, 0x4F01
|
||||
int 0x10
|
||||
call checkvesa
|
||||
|
||||
mov ax, VESA_MODEINFO_SEG
|
||||
mov ds, ax
|
||||
xor si, si
|
||||
mov ax, BOOT_DATA_SEG
|
||||
mov es, ax
|
||||
mov di, BOOT_VESA_INFO
|
||||
mov cx, 256
|
||||
vesa_copymodeinfo_loop:
|
||||
lodsb
|
||||
stosb
|
||||
loop vesa_copymodeinfo_loop ;store ModeInfoBlock for current
|
||||
|
||||
mov [es:BOOT_VESA], dx ;store mode# for kernel
|
||||
|
||||
; mov ax, 0xb800
|
||||
; mov es, ax
|
||||
; xor di, di
|
||||
; mov al, dh
|
||||
; call puthex2
|
||||
; mov al, dl
|
||||
; call puthex2
|
||||
|
||||
mov bx, dx
|
||||
or bx, 0x4000 ;set "use LFB" bit of mode#
|
||||
mov ax, 0x4F02
|
||||
int 0x10 ;switch to graphics mode!!!
|
||||
call checkvesa
|
||||
|
||||
jmp vesa_done
|
||||
|
||||
vesa_consolemode_only:
|
||||
mov ax, BOOT_DATA_SEG
|
||||
mov es, ax
|
||||
mov word [es:BOOT_VESA], 0
|
||||
|
||||
jmp vesa_done
|
||||
|
||||
;------------------------------------------------------
|
||||
vesa_showmodeinfo:
|
||||
pusha
|
||||
push es
|
||||
push ds
|
||||
mov ax, VESA_MODEINFO_SEG
|
||||
mov ds, ax
|
||||
xor si, si
|
||||
mov ax, 0xb800
|
||||
mov es, ax
|
||||
|
||||
mov cx, dx
|
||||
|
||||
mov ax, 160
|
||||
mul dx ;ax=160*mod#
|
||||
add ax, 160*3+6 ;offset first line of modes and room on left for label
|
||||
mov di, ax
|
||||
|
||||
mov ax, [ds:18]
|
||||
call console_putDec
|
||||
add di, 10
|
||||
mov al, 'x'
|
||||
call console_putChar
|
||||
inc di
|
||||
inc di
|
||||
mov ax, [ds:20]
|
||||
call console_putDec
|
||||
add di, 10
|
||||
mov al, 'x'
|
||||
call console_putChar
|
||||
inc di
|
||||
inc di
|
||||
xor ah, ah
|
||||
mov al, [ds:25]
|
||||
call console_putDec
|
||||
add di, 8
|
||||
mov al, [ds:0]
|
||||
test al, 0x80
|
||||
jz vesa_showmodeinfo_done
|
||||
mov al, 'L'
|
||||
call console_putChar
|
||||
mov al, 'F'
|
||||
call console_putChar
|
||||
mov al, 'B'
|
||||
call console_putChar
|
||||
inc di
|
||||
inc di
|
||||
mov ebx, [ds:40]
|
||||
mov eax, ebx
|
||||
shr eax, 24
|
||||
call puthex2
|
||||
mov eax, ebx
|
||||
shr eax, 16
|
||||
call puthex2
|
||||
mov al, bh
|
||||
call puthex2
|
||||
mov al, bl
|
||||
call puthex2
|
||||
vesa_showmodeinfo_done:
|
||||
pop ds
|
||||
pop es
|
||||
popa
|
||||
ret
|
||||
|
||||
;------------------------------------------------------
|
||||
checkmode:
|
||||
push bx
|
||||
push cx
|
||||
push dx
|
||||
push es
|
||||
push ds
|
||||
push di
|
||||
push si
|
||||
mov cx, ax ;cx=modenumber
|
||||
mov ax, VESA_MODEINFO_SEG
|
||||
mov es, ax
|
||||
xor di, di
|
||||
mov ax, 0x4F01
|
||||
int 0x10
|
||||
call checkvesa
|
||||
xor di, di ;es:di -> ModeInfoBlock struc
|
||||
mov ax, [es:di] ;ModeAttributes
|
||||
test al, 1 ;mode supported
|
||||
jz vesa_modenogood
|
||||
test al, 8 ;color mode
|
||||
jz vesa_modenogood
|
||||
test al, 0x10 ;graphics mode
|
||||
jz vesa_modenogood
|
||||
test al, 0x80 ;Linear Frame Buffer supported
|
||||
jz vesa_modenogood
|
||||
mov al, [es:di+25] ;BitsPerPixel
|
||||
cmp al, 16
|
||||
jz vesa_bppok
|
||||
cmp al, 24
|
||||
jz vesa_bppok
|
||||
cmp al, 32
|
||||
jnz vesa_modenogood
|
||||
vesa_bppok:
|
||||
mov ax, [es:di+18] ;XResolution
|
||||
mov bx, [es:di+20] ;YResolution
|
||||
cmp ax, 640 ;640x480
|
||||
jnz res_goon1
|
||||
cmp bx, 480
|
||||
jnz vesa_modenogood
|
||||
jmp vesa_modegood
|
||||
res_goon1:
|
||||
cmp ax, 800
|
||||
jnz res_goon2
|
||||
cmp bx, 600
|
||||
jnz vesa_modenogood
|
||||
jmp vesa_modegood
|
||||
res_goon2:
|
||||
cmp ax, 1024
|
||||
jnz res_goon3
|
||||
cmp bx, 768
|
||||
jnz vesa_modenogood
|
||||
jmp vesa_modegood
|
||||
res_goon3:
|
||||
cmp ax, 1280
|
||||
jnz res_goon4
|
||||
cmp bx, 1024
|
||||
jz vesa_modegood
|
||||
cmp bx, 960
|
||||
jz vesa_modegood
|
||||
jmp vesa_modenogood
|
||||
res_goon4:
|
||||
cmp ax, 1600
|
||||
jnz vesa_modenogood
|
||||
cmp bx, 1200
|
||||
jnz vesa_modenogood
|
||||
vesa_modegood:
|
||||
pop si
|
||||
pop di
|
||||
pop ds
|
||||
pop es
|
||||
pop dx
|
||||
pop cx
|
||||
pop bx
|
||||
xor ax, ax
|
||||
ret
|
||||
vesa_modenogood:
|
||||
pop si
|
||||
pop di
|
||||
pop ds
|
||||
pop es
|
||||
pop dx
|
||||
pop cx
|
||||
pop bx
|
||||
mov ax, 0xffff
|
||||
ret
|
||||
|
||||
;------------------------------------------------------
|
||||
vesa_done:
|
||||
|
||||
; xor ax, ax ;wait for keypress...
|
||||
; int 0x16
|
||||
|
||||
jmp go_pm
|
||||
|
||||
;------------------------------------------------------
|
||||
puts:
|
||||
lodsb
|
||||
or al, al
|
||||
jz puts_done
|
||||
stosb
|
||||
mov al, ah
|
||||
stosb
|
||||
jmp puts
|
||||
puts_done:
|
||||
ret
|
||||
|
||||
;------------------------------------------------------
|
||||
checkvesa:
|
||||
cmp ax, 0x004F
|
||||
jnz vesaerror
|
||||
ret
|
||||
vesaerror:
|
||||
mov ax, 0xb800
|
||||
mov es, ax
|
||||
xor ax, ax
|
||||
mov ds, ax
|
||||
mov si, txt_vesaerror
|
||||
mov di, 160*24
|
||||
mov ah, 4
|
||||
call puts
|
||||
cli
|
||||
hlt
|
||||
|
||||
;-------Function console_putDec
|
||||
;input:
|
||||
; AX = number to display
|
||||
;output:
|
||||
; number written in decimal to es:di
|
||||
console_putDec:
|
||||
pusha
|
||||
xor dx, dx
|
||||
xor bh, bh ;no characters written yet
|
||||
mov cx, 10000
|
||||
div cx ;ax=quotiont, dx=remainder
|
||||
add ax, '0'
|
||||
cmp ax, '0'
|
||||
je .goon1
|
||||
call console_putChar
|
||||
mov bh, 1
|
||||
|
||||
.goon1:
|
||||
mov ax, dx ;load remainder to ax
|
||||
xor dx, dx
|
||||
mov cx, 1000
|
||||
div cx ;ax=quotiont, dx=remainder
|
||||
add ax, '0'
|
||||
cmp ax, '0'
|
||||
je .goon11
|
||||
call console_putChar
|
||||
mov bh, 1
|
||||
jmp .goon2
|
||||
.goon11:
|
||||
cmp bh, 0
|
||||
je .goon2
|
||||
call console_putChar
|
||||
|
||||
.goon2:
|
||||
mov ax, dx ;load remainder to ax
|
||||
xor dx, dx
|
||||
mov cx, 100
|
||||
div cx ;ax=quotiont, dx=remainder
|
||||
add ax, '0'
|
||||
cmp ax, '0'
|
||||
je .goon21
|
||||
call console_putChar
|
||||
mov bh, 1
|
||||
jmp .goon3
|
||||
.goon21:
|
||||
cmp bh, 0
|
||||
je .goon3
|
||||
call console_putChar
|
||||
|
||||
.goon3:
|
||||
mov ax, dx ;load remainder to ax
|
||||
xor dx, dx
|
||||
mov cx, 10
|
||||
div cx ;ax=quotiont, dx=remainder
|
||||
add ax, '0'
|
||||
cmp ax, '0'
|
||||
je .goon31
|
||||
call console_putChar
|
||||
mov bh, 1
|
||||
jmp .goon4
|
||||
.goon31:
|
||||
cmp bh, 0
|
||||
je .goon4
|
||||
call console_putChar
|
||||
.goon4: ;here dx contains last remainder
|
||||
mov ax, dx
|
||||
add ax, '0'
|
||||
call console_putChar
|
||||
|
||||
popa
|
||||
ret
|
||||
|
||||
;------------------------------------------------------
|
||||
console_putChar:
|
||||
stosb
|
||||
mov al, 7
|
||||
stosb
|
||||
ret
|
||||
|
||||
;------------------------------------------------------
|
||||
puthex:
|
||||
;es:di points to video memory
|
||||
;al holds hex value
|
||||
|
||||
push ax
|
||||
mov ah, al
|
||||
shr ax, 4
|
||||
and al, 0x0F
|
||||
add al, '0'
|
||||
cmp al, '9'
|
||||
jle puthex_goon1
|
||||
add al, 'A'-'9'-1
|
||||
puthex_goon1:
|
||||
cmp al, '0'
|
||||
jz puthex_skipzero
|
||||
stosb
|
||||
mov al, 7
|
||||
stosb
|
||||
puthex_skipzero:
|
||||
pop ax
|
||||
push ax
|
||||
and al, 0x0F
|
||||
add al, '0'
|
||||
cmp al, '9'
|
||||
jle puthex_goon2
|
||||
add al, 'A'-'9'-1
|
||||
puthex_goon2:
|
||||
stosb
|
||||
mov al, 7
|
||||
stosb
|
||||
pop ax
|
||||
ret
|
||||
|
||||
;------------------------------------------------------
|
||||
puthex2:
|
||||
;es:di points to video memory, always displays 2 characters!
|
||||
;al holds hex value
|
||||
|
||||
push ax
|
||||
mov ah, al
|
||||
shr ax, 4
|
||||
and al, 0x0F
|
||||
add al, '0'
|
||||
cmp al, '9'
|
||||
jle puthex2_goon1
|
||||
add al, 'A'-'9'-1
|
||||
puthex2_goon1:
|
||||
stosb
|
||||
mov al, 7
|
||||
stosb
|
||||
pop ax
|
||||
push ax
|
||||
and al, 0x0F
|
||||
add al, '0'
|
||||
cmp al, '9'
|
||||
jle puthex2_goon2
|
||||
add al, 'A'-'9'-1
|
||||
puthex2_goon2:
|
||||
stosb
|
||||
mov al, 7
|
||||
stosb
|
||||
pop ax
|
||||
ret
|
||||
|
||||
;------------------------------------------------------
|
||||
txt_welcome: db " HOS bootloader v", VERSION, "! ", 0
|
||||
txt_rd1: db "1. Do not load an initial ram disk", 0
|
||||
txt_rd2: db "2. Load initial ram disk from boot media", 0
|
||||
txt_input: db "Enter your selection: ", 0
|
||||
txt_vesa: db "VESA version: ", 0
|
||||
txt_vesaerror: db "VESA function call error! Halting system!", 0
|
||||
txt_novesa: db "VESA not found. Starting in console mode...", 0
|
||||
txt_vesaold: db "VESA version 2.0 required. Starting in console mode...", 0
|
||||
txt_consolemode: db "a. Console mode only.", 0
|
||||
txt_memerror: db "Extended Memory Map information unavailable! Halting system...", 0
|
||||
|
||||
;------------------------------------------------------
|
||||
getCHSfromCluster:
|
||||
;input: ax=lba of sector on floppy (0-2879)
|
||||
add ax, 31 ;convert logical cluster# to lba#
|
||||
xor dx, dx ;lba->chs
|
||||
mov bx, 18
|
||||
div bx
|
||||
inc dx
|
||||
mov cl, dl ;sector# (1-18)
|
||||
xor dx, dx
|
||||
mov bx, 2
|
||||
div bx
|
||||
mov ch, al ;cylinder# (0-79)
|
||||
mov dh, dl ;head# (0-1)
|
||||
ret
|
||||
|
||||
|
||||
;-------------------------------------------------------
|
||||
gdtr:
|
||||
dw gdt_end-gdt-1
|
||||
dd gdt
|
||||
gdt:
|
||||
dd 0
|
||||
dd 0
|
||||
|
||||
KERNEL_CODE equ $-gdt
|
||||
db 0xff ;limit 7:0
|
||||
db 0xff ;limit 15:8
|
||||
db 0x00 ;base 7:0
|
||||
db 0x00 ;base 15:8
|
||||
db 0x00 ;base 23:16
|
||||
db 0x9a ;access
|
||||
db 0xcf ;flags / limit 19:16
|
||||
db 0x00 ;base 31:24
|
||||
|
||||
KERNEL_DATA equ $-gdt
|
||||
db 0xff ;segment 16 = 4gb data
|
||||
db 0xff
|
||||
db 0x00
|
||||
db 0x00
|
||||
db 0x00
|
||||
db 0x92
|
||||
db 0xcf
|
||||
db 0x00
|
||||
|
||||
gdt_end:
|
||||
|
||||
|
||||
;-------------------------------------------------------
|
||||
gdtr32:
|
||||
dw gdt_end32-gdt32-1
|
||||
dd gdt32
|
||||
gdt32:
|
||||
dd 0
|
||||
dd 0
|
||||
|
||||
;a base of 0x4000_0000, when added to 0xC000_0000 will produce 0x0000_0000 physical before paging in effect
|
||||
KERNEL_CODE32 equ $-gdt32
|
||||
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_DATA32 equ $-gdt32
|
||||
db 0xff ;segment 16 = 4gb data
|
||||
db 0xff
|
||||
db 0x00
|
||||
db 0x00
|
||||
db 0x00
|
||||
db 0x92
|
||||
db 0xcf
|
||||
db 0x40
|
||||
|
||||
gdt_end32:
|
||||
|
||||
;------------------------------------------------------
|
||||
go_pm:
|
||||
xor ax, ax
|
||||
mov ds, ax
|
||||
lgdt [gdtr]
|
||||
cli
|
||||
mov eax, cr0
|
||||
inc eax
|
||||
mov cr0, eax
|
||||
|
||||
jmp KERNEL_CODE:pmode
|
||||
|
||||
bits 32
|
||||
pmode:
|
||||
lgdt [gdtr32]
|
||||
jmp KERNEL_CODE32:pmode_offsetted+0xC0000000
|
||||
|
||||
pmode_offsetted:
|
||||
mov ax, KERNEL_DATA32
|
||||
mov es, ax
|
||||
mov ds, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
jmp KERNEL_CODE:BOOT_KERNEL_ADD+0xC0000000
|
||||
|
||||
kernel: db "KERNEL BIN", 0
|
||||
|
||||
|
||||
@@ -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.
Symlink
+1
@@ -0,0 +1 @@
|
||||
test_file
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
# Change this file to contain the machines that you want to use
|
||||
# to run MPI jobs on. The format is one host name per line, with either
|
||||
# hostname
|
||||
# or
|
||||
# hostname:n
|
||||
# where n is the number of processors in an SMP. The hostname should
|
||||
# be the same as the result from the command "hostname"
|
||||
#
|
||||
#non-functional machines
|
||||
#stallman.cs.calvin.edu
|
||||
#zuse.cs.calvin.edu
|
||||
#knuth.cs.calvin.edu
|
||||
|
||||
stroustrup.cs.calvin.edu
|
||||
kernighan.cs.calvin.edu
|
||||
ritchie.cs.calvin.edu
|
||||
aiken.cs.calvin.edu
|
||||
backus-naur.cs.calvin.edu
|
||||
codd.cs.calvin.edu
|
||||
eckert-mauchly.cs.calvin.edu
|
||||
atanasoff.cs.calvin.edu
|
||||
thompson.cs.calvin.edu
|
||||
augusta.cs.calvin.edu
|
||||
babbage.cs.calvin.edu
|
||||
turing.cs.calvin.edu
|
||||
hoare.cs.calvin.edu
|
||||
wall.cs.calvin.edu
|
||||
englebart.cs.calvin.edu
|
||||
vonneuman.cs.calvin.edu
|
||||
hopper.cs.calvin.edu
|
||||
dijkstra.cs.calvin.edu
|
||||
chomsky.cs.calvin.edu
|
||||
leibniz.cs.calvin.edu
|
||||
schreyer.cs.calvin.edu
|
||||
wirth.cs.calvin.edu
|
||||
cray.cs.calvin.edu
|
||||
hillis.cs.calvin.edu
|
||||
taylor.cs.calvin.edu
|
||||
goldberg.cs.calvin.edu
|
||||
kay.cs.calvin.edu
|
||||
boole.cs.calvin.edu
|
||||
church.cs.calvin.edu
|
||||
sutherland.cs.calvin.edu
|
||||
noyce-kilby.cs.calvin.edu
|
||||
hollerith.cs.calvin.edu
|
||||
|
||||
+117
-64
@@ -1,76 +1,129 @@
|
||||
#####################################################################
|
||||
# Author: Josh Holtrop / Benjamen R. Meyer #
|
||||
# Date: 02/15/04 Modified: 06/16/04 #
|
||||
# Purpose: To build Josh Holtrop's OS (HOS) using GNU make #
|
||||
# Note: This makefile is for use on Linux & other Unix-like systems #
|
||||
#####################################################################
|
||||
# Makefile for HOS
|
||||
# Josh Holtrop
|
||||
# Created: 07/08/04
|
||||
# Modified: 06/13/05
|
||||
|
||||
##############
|
||||
# Variables: #
|
||||
##############
|
||||
# Assembler Information:
|
||||
NASM=nasm
|
||||
NASM_FLAGS=-f elf32
|
||||
|
||||
# Format of kernel object files:
|
||||
# Do not change unless you know what you are doing
|
||||
KERNEL_FORMAT=aout
|
||||
|
||||
# Assembler information:
|
||||
NASM_BIN=nasm
|
||||
NASM_FLAGS=-f $(KERNEL_FORMAT)
|
||||
|
||||
# C++ Compile Information:
|
||||
CPP=g++
|
||||
CPP_FLAGS=-fleading-underscore -fno-builtin -nostdlib -nostdinc++ -nostartfiles -fno-rtti -fno-exceptions -nodefaultlibs -I. -Wall
|
||||
# C/C++ Information:
|
||||
CPPFLAGS=-ffreestanding -fno-builtin -nostdlib -nostartfiles -nodefaultlibs -I. -Wall -m32 -fno-pic
|
||||
# -S -masm=intel
|
||||
CC=gcc
|
||||
CXX=g++
|
||||
CXXFLAGS=-fno-rtti -fno-exceptions -D_HOS_CPP_ -std=gnu++98
|
||||
|
||||
# Linker Information:
|
||||
LD=ld
|
||||
LD_FLAGS=-nodefaultlibs -nostdlib --no-demangle -T link.ld
|
||||
LD=gcc
|
||||
LDFLAGS=-ffreestanding -fno-builtin -nostartfiles -nodefaultlibs -nostdlib -Wl,--no-demangle -T link.ld -m32
|
||||
LIBS=-static-libgcc
|
||||
|
||||
# Files
|
||||
OBJS=boot.o lang/lang_a.o \
|
||||
kernel.o mm/mm.o mm/vmm.o lang/conv.o display/kout.o \
|
||||
display/display.o sys/pic.o char/keyboard.o lang/lang.o \
|
||||
sys/pci_classes.o syscall.o \
|
||||
proc/proc.o proc/hash.o \
|
||||
lang/string.o lang/new.o char/misc_char.o char/vconsole.o \
|
||||
devices.o block/ramdisk.o fs/vfs.o fs/FileSystem.o fs/VFSMount.o \
|
||||
fs/ext2/ext2.o fs/sysfs/sysfs.o fs/sysfs/sysfs_entry.o \
|
||||
sys/pci.o fs/OpenFile.o fs/OpenDirectory.o \
|
||||
fs/ext2/Ext2OpenDirectory.o fs/ext2/Ext2OpenFile.o \
|
||||
fs/ext2/Ext2BlockCache.o
|
||||
CSRC=kernel.c mm/mm.c mm/vmm.c lang/conv.c display/kout.c \
|
||||
display/display.c sys/pic.c char/keyboard.c lang/lang.c \
|
||||
sys/pci_classes.c syscall.c
|
||||
CXXSRC=lang/string.cpp lang/new.cpp char/misc_char.cpp char/vconsole.cpp \
|
||||
block/ramdisk.cpp devices.cpp fs/vfs.cpp fs/FileSystem.o fs/VFSMount.o\
|
||||
fs/ext2/ext2.cpp fs/sysfs/sysfs.cpp fs/sysfs/sysfs_entry.cpp \
|
||||
sys/pci.cpp proc/proc.cpp proc/hash.cpp fs/OpenFile.cpp \
|
||||
fs/OpenDirectory.cpp fs/ext2/Ext2OpenDirectory.cpp \
|
||||
fs/ext2/Ext2OpenFile.cpp fs/ext2/Ext2BlockCache.cpp
|
||||
|
||||
###############################
|
||||
# Linking the kernel together #
|
||||
###############################
|
||||
all: Asm_Kernel Asm_Functions C_Kernel
|
||||
$(LD) $(LD_FLAGS) -o kernel.bin -Map ./lst/LDout.doc ks.o kernel.o asmfuncs.o fdc.o keyboard.o kio.o mm.o mouse.o stdfont.o video.o vmm.o rtc.o pic.o io.o cstring.o string.o cmos.o hos_defines.o vfs.o devfs.o Mount.o
|
||||
.PHONY: all depend clean html
|
||||
|
||||
##########################
|
||||
# Assembly Kernel Loader #
|
||||
##########################
|
||||
Asm_Kernel: kernel.asm
|
||||
$(NASM_BIN) $(NASM_FLAGS) -o ks.o -l ./lst/kernel.lst kernel.asm
|
||||
all: $(OBJS)
|
||||
$(LD) $(LDFLAGS) -Wl,-Map -Wl,kernel.map $(OBJS) -o kernel.bin $(LIBS)
|
||||
@echo ' Kernel built: ' `ls -sk kernel.bin | cut -d' ' -f1`kb
|
||||
|
||||
#################################
|
||||
# Assembly Functions for Kernel #
|
||||
#################################
|
||||
Asm_Functions: asmfuncs.asm
|
||||
$(NASM_BIN) $(NASM_FLAGS) -o asmfuncs.o -l ./lst/asmfuncs.lst asmfuncs.asm
|
||||
depend:
|
||||
makedepend -- $(CPPFLAGS) -- $(CSRC) $(CXXSRC)
|
||||
|
||||
############
|
||||
# C Kernel #
|
||||
############
|
||||
C_Kernel:
|
||||
$(CPP) $(CPP_FLAGS) -c kernel.cpp -o kernel.o
|
||||
$(CPP) $(CPP_FLAGS) -c kio.cpp -o kio.o
|
||||
$(CPP) $(CPP_FLAGS) -c sys/rtc.cpp -o rtc.o
|
||||
$(CPP) $(CPP_FLAGS) -c sys/pic.cpp -o pic.o
|
||||
$(CPP) $(CPP_FLAGS) -c sys/io.cpp -o io.o
|
||||
$(CPP) $(CPP_FLAGS) -c sys/cmos.cpp -o cmos.o
|
||||
$(CPP) $(CPP_FLAGS) -c lang/cstring.cpp -o cstring.o
|
||||
$(CPP) $(CPP_FLAGS) -c lang/string.cpp -o string.o
|
||||
$(CPP) $(CPP_FLAGS) -c video/stdfont.cpp -o stdfont.o
|
||||
$(CPP) $(CPP_FLAGS) -c video/video.cpp -o video.o
|
||||
$(CPP) $(CPP_FLAGS) -c block/fdc.cpp -o fdc.o
|
||||
$(CPP) $(CPP_FLAGS) -c char/keyboard.cpp -o keyboard.o
|
||||
$(CPP) $(CPP_FLAGS) -c char/mouse.cpp -o mouse.o
|
||||
$(CPP) $(CPP_FLAGS) -c mm/mm.cpp -o mm.o
|
||||
$(CPP) $(CPP_FLAGS) -c mm/vmm.cpp -o vmm.o
|
||||
$(CPP) $(CPP_FLAGS) -c hos_defines.cpp -o hos_defines.o
|
||||
$(CPP) $(CPP_FLAGS) -c fs/vfs.cpp -o vfs.o
|
||||
$(CPP) $(CPP_FLAGS) -c fs/devfs.cpp -o devfs.o
|
||||
$(CPP) $(CPP_FLAGS) -c fs/Mount.cpp -o Mount.o
|
||||
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 up the source directory of any binaries #
|
||||
#################################################
|
||||
clean:
|
||||
- rm *.s *.o *.bin *~ block/*~ char/*~ fs/*~ lang/*~ mm/*~ sys/*~ video/*~
|
||||
-rm -f $(OBJS) *.bin *.map *.lst *.out
|
||||
-find . -name '*~' | xargs rm -f
|
||||
|
||||
html:
|
||||
-rm -rf html
|
||||
-mkdir html
|
||||
source-highlight --output-dir=html -f xhtml -n $(CSRC) $(CXXSRC)
|
||||
|
||||
# The following is used by 'make' to automatically
|
||||
# generate dependency information
|
||||
# DO NOT DELETE
|
||||
|
||||
kernel.o: kernel.h hos_defines.h multiboot.h module.h lang/lang.h functions.h
|
||||
kernel.o: sys/io.h mm/mm.h mm/vmm.h lang/conv.h devices.h display/display.h
|
||||
kernel.o: display/kout.h sys/pic.h char/keyboard.h block/ramdisk.h fs/vfs.h
|
||||
kernel.o: fs/ext2/ext2.h sys/pci.h proc/proc.h
|
||||
mm/mm.o: kernel.h hos_defines.h multiboot.h mm/mm.h
|
||||
mm/vmm.o: hos_defines.h kernel.h multiboot.h mm/vmm.h lang/lang.h mm/mm.h
|
||||
lang/conv.o: lang/conv.h hos_defines.h
|
||||
display/kout.o: hos_defines.h display/kout.h lang/conv.h devices.h
|
||||
display/kout.o: char/misc_char.h char/misc_char.h functions.h sys/io.h
|
||||
display/display.o: devices.h hos_defines.h char/vconsole.h display/display.h
|
||||
display/display.o: lang/lang.h kernel.h multiboot.h char/keyboard.h
|
||||
display/display.o: display/kout.h
|
||||
sys/pic.o: hos_defines.h sys/pic.h sys/io.h
|
||||
char/keyboard.o: hos_defines.h char/keyboard.h sys/io.h functions.h
|
||||
char/keyboard.o: lang/conv.h display/kout.h display/display.h devices.h
|
||||
lang/lang.o: lang/lang.h hos_defines.h
|
||||
sys/pci_classes.o: hos_defines.h sys/pci.h
|
||||
lang/string.o: lang/string.h lang/lang.h hos_defines.h
|
||||
lang/new.o: hos_defines.h mm/vmm.h multiboot.h
|
||||
char/misc_char.o: hos_defines.h devices.h char/misc_char.h sys/io.h
|
||||
char/vconsole.o: hos_defines.h mm/vmm.h multiboot.h lang/lang.h
|
||||
char/vconsole.o: display/display.h devices.h functions.h sys/io.h
|
||||
char/vconsole.o: char/vconsole.h
|
||||
block/ramdisk.o: functions.h hos_defines.h sys/io.h mm/vmm.h multiboot.h
|
||||
block/ramdisk.o: lang/lang.h block/ramdisk.h devices.h
|
||||
devices.o: hos_defines.h devices.h char/misc_char.h char/misc_char.h
|
||||
devices.o: char/vconsole.h block/ramdisk.h
|
||||
fs/vfs.o: hos_defines.h display/kout.h functions.h sys/io.h lang/lang.h
|
||||
fs/vfs.o: fs/vfs.h devices.h fs/FileSystem.h fs/OpenDirectory.h lang/string.h
|
||||
fs/vfs.o: fs/OpenFile.h fs/VFSMount.h fs/FileSystem.h fs/ext2/ext2.h fs/vfs.h
|
||||
fs/vfs.o: lang/vector.h
|
||||
fs/ext2/ext2.o: display/kout.h hos_defines.h mm/vmm.h multiboot.h lang/lang.h
|
||||
fs/ext2/ext2.o: fs/ext2/ext2.h fs/vfs.h devices.h fs/ext2/Ext2OpenDirectory.h
|
||||
fs/ext2/ext2.o: fs/ext2/Ext2BlockCache.h fs/ext2/Ext2OpenFile.h fs/OpenFile.h
|
||||
fs/sysfs/sysfs.o: display/kout.h hos_defines.h fs/vfs.h devices.h
|
||||
fs/sysfs/sysfs.o: fs/sysfs/sysfs.h fs/sysfs/sysfs_entry.h lang/vector.h
|
||||
fs/sysfs/sysfs.o: lang/string.h
|
||||
fs/sysfs/sysfs_entry.o: fs/sysfs/sysfs_entry.h lang/vector.h hos_defines.h
|
||||
fs/sysfs/sysfs_entry.o: lang/string.h
|
||||
sys/pci.o: hos_defines.h display/kout.h sys/io.h sys/pci.h lang/vector.h
|
||||
proc/proc.o: hos_defines.h mm/mm.h kernel.h multiboot.h mm/vmm.h lang/lang.h
|
||||
proc/proc.o: functions.h sys/io.h display/kout.h proc/proc.h proc/hash.h
|
||||
proc/proc.o: lang/vector.h
|
||||
proc/hash.o: hos_defines.h proc/hash.h lang/vector.h display/kout.h mm/vmm.h
|
||||
proc/hash.o: multiboot.h
|
||||
fs/OpenFile.o: fs/OpenFile.h hos_defines.h
|
||||
fs/OpenDirectory.o: fs/vfs.h hos_defines.h devices.h fs/OpenDirectory.h
|
||||
fs/OpenDirectory.o: lang/string.h
|
||||
fs/ext2/Ext2OpenDirectory.o: lang/lang.h hos_defines.h fs/vfs.h devices.h
|
||||
fs/ext2/Ext2OpenDirectory.o: fs/ext2/Ext2OpenDirectory.h fs/ext2/ext2.h
|
||||
fs/ext2/Ext2OpenDirectory.o: fs/ext2/Ext2BlockCache.h fs/ext2/Ext2OpenFile.h
|
||||
fs/ext2/Ext2OpenDirectory.o: fs/OpenFile.h
|
||||
fs/ext2/Ext2OpenFile.o: fs/ext2/Ext2OpenFile.h fs/ext2/ext2.h fs/vfs.h
|
||||
fs/ext2/Ext2OpenFile.o: hos_defines.h devices.h fs/OpenFile.h
|
||||
fs/ext2/Ext2OpenFile.o: fs/ext2/Ext2BlockCache.h lang/lang.h functions.h
|
||||
fs/ext2/Ext2OpenFile.o: sys/io.h
|
||||
fs/ext2/Ext2BlockCache.o: fs/vfs.h hos_defines.h devices.h
|
||||
fs/ext2/Ext2BlockCache.o: fs/ext2/Ext2BlockCache.h fs/ext2/ext2.h
|
||||
@@ -0,0 +1,123 @@
|
||||
# Makefile for HOS
|
||||
# Josh Holtrop
|
||||
# Created: 07/08/04
|
||||
# Modified: 06/13/05
|
||||
|
||||
# Assembler Information:
|
||||
NASM=nasm
|
||||
NASM_FLAGS=-f aout
|
||||
|
||||
# C/C++ Information:
|
||||
CPPFLAGS=-fleading-underscore -fno-builtin -nostdlib -nostartfiles -nodefaultlibs -I. -Wall
|
||||
# -S -masm=intel
|
||||
CC=gcc
|
||||
CXX=g++
|
||||
CXXFLAGS=-fno-rtti -fno-exceptions -D_HOS_CPP_
|
||||
|
||||
# Linker Information:
|
||||
LD=ld
|
||||
LDFLAGS=-nodefaultlibs -nostdlib --no-demangle -T link.ld
|
||||
|
||||
# Files
|
||||
OBJS=boot.o lang/lang_a.o \
|
||||
kernel.o mm/mm.o mm/vmm.o lang/conv.o display/kout.o \
|
||||
display/display.o sys/pic.o char/keyboard.o lang/lang.o \
|
||||
sys/pci_classes.o syscall.o \
|
||||
proc/proc.o proc/hash.o \
|
||||
lang/string.o lang/new.o char/misc_char.o char/vconsole.o \
|
||||
devices.o block/ramdisk.o fs/vfs.o fs/FileSystem.o fs/VFSMount.o \
|
||||
fs/ext2/ext2.o fs/sysfs/sysfs.o fs/sysfs/sysfs_entry.o \
|
||||
sys/pci.o fs/OpenFile.o fs/OpenDirectory.o \
|
||||
fs/ext2/Ext2OpenDirectory.o fs/ext2/Ext2OpenFile.o \
|
||||
fs/ext2/Ext2BlockCache.o
|
||||
CSRC=kernel.c mm/mm.c mm/vmm.c lang/conv.c display/kout.c \
|
||||
display/display.c sys/pic.c char/keyboard.c lang/lang.c \
|
||||
sys/pci_classes.c syscall.c
|
||||
CXXSRC=lang/string.cpp lang/new.cpp char/misc_char.cpp char/vconsole.cpp \
|
||||
block/ramdisk.cpp devices.cpp fs/vfs.cpp fs/FileSystem.o fs/VFSMount.o\
|
||||
fs/ext2/ext2.cpp fs/sysfs/sysfs.cpp fs/sysfs/sysfs_entry.cpp \
|
||||
sys/pci.cpp proc/proc.cpp proc/hash.cpp fs/OpenFile.cpp \
|
||||
fs/OpenDirectory.cpp fs/ext2/Ext2OpenDirectory.cpp \
|
||||
fs/ext2/Ext2OpenFile.cpp fs/ext2/Ext2BlockCache.cpp
|
||||
|
||||
.PHONY: all depend clean html
|
||||
|
||||
all: $(OBJS)
|
||||
$(LD) $(LDFLAGS) -Map kernel.map $(OBJS) -o kernel.bin
|
||||
@echo ' Kernel built: ' `ls -sk kernel.bin | cut -d' ' -f1`kb
|
||||
|
||||
depend:
|
||||
makedepend -- $(CPPFLAGS) -- $(CSRC) $(CXXSRC)
|
||||
|
||||
boot.o: boot.asm idt.inc gdt.inc
|
||||
$(NASM) $(NASM_FLAGS) -l boot.lst boot.asm -o boot.o
|
||||
|
||||
lang/lang_a.o: lang/lang.asm
|
||||
$(NASM) $(NASM_FLAGS) -l lang.lst lang/lang.asm -o lang/lang_a.o
|
||||
|
||||
clean:
|
||||
-rm -f $(OBJS) *.bin *.map *.lst *.out
|
||||
-find . -name '*~' | xargs rm -f
|
||||
|
||||
html:
|
||||
-rm -rf html
|
||||
-mkdir html
|
||||
source-highlight --output-dir=html -f xhtml -n $(CSRC) $(CXXSRC)
|
||||
|
||||
# The following is used by 'make' to automatically
|
||||
# generate dependency information
|
||||
# DO NOT DELETE
|
||||
|
||||
kernel.o: kernel.h hos_defines.h multiboot.h module.h lang/lang.h functions.h
|
||||
kernel.o: sys/io.h mm/mm.h mm/vmm.h lang/conv.h devices.h display/display.h
|
||||
kernel.o: display/kout.h sys/pic.h char/keyboard.h block/ramdisk.h fs/vfs.h
|
||||
kernel.o: fs/ext2/ext2.h sys/pci.h proc/proc.h
|
||||
mm/mm.o: kernel.h hos_defines.h multiboot.h mm/mm.h
|
||||
mm/vmm.o: hos_defines.h kernel.h multiboot.h mm/vmm.h lang/lang.h mm/mm.h
|
||||
lang/conv.o: lang/conv.h hos_defines.h
|
||||
display/kout.o: hos_defines.h display/kout.h lang/conv.h devices.h
|
||||
display/kout.o: char/misc_char.h char/misc_char.h functions.h sys/io.h
|
||||
display/display.o: devices.h hos_defines.h char/vconsole.h display/display.h
|
||||
display/display.o: lang/lang.h kernel.h multiboot.h char/keyboard.h
|
||||
display/display.o: display/kout.h
|
||||
sys/pic.o: hos_defines.h sys/pic.h sys/io.h
|
||||
char/keyboard.o: hos_defines.h char/keyboard.h sys/io.h functions.h
|
||||
char/keyboard.o: lang/conv.h display/kout.h display/display.h devices.h
|
||||
lang/lang.o: lang/lang.h hos_defines.h
|
||||
sys/pci_classes.o: hos_defines.h sys/pci.h
|
||||
lang/string.o: lang/string.h lang/lang.h hos_defines.h
|
||||
lang/new.o: hos_defines.h mm/vmm.h multiboot.h
|
||||
char/misc_char.o: hos_defines.h devices.h char/misc_char.h sys/io.h
|
||||
char/vconsole.o: hos_defines.h mm/vmm.h multiboot.h lang/lang.h
|
||||
char/vconsole.o: display/display.h devices.h functions.h sys/io.h
|
||||
char/vconsole.o: char/vconsole.h
|
||||
block/ramdisk.o: functions.h hos_defines.h sys/io.h mm/vmm.h multiboot.h
|
||||
block/ramdisk.o: lang/lang.h block/ramdisk.h devices.h
|
||||
devices.o: hos_defines.h devices.h char/misc_char.h char/misc_char.h
|
||||
devices.o: char/vconsole.h block/ramdisk.h
|
||||
fs/vfs.o: hos_defines.h display/kout.h functions.h sys/io.h lang/lang.h
|
||||
fs/vfs.o: fs/vfs.h devices.h fs/FileSystem.h fs/OpenDirectory.h fs/OpenFile.h
|
||||
fs/vfs.o: lang/string.h fs/VFSMount.h fs/FileSystem.h fs/ext2/ext2.h fs/vfs.h
|
||||
fs/vfs.o: lang/vector.h
|
||||
fs/ext2/ext2.o: display/kout.h hos_defines.h mm/vmm.h multiboot.h lang/lang.h
|
||||
fs/ext2/ext2.o: fs/ext2/ext2.h fs/vfs.h devices.h fs/ext2/Ext2OpenDirectory.h
|
||||
fs/ext2/ext2.o: fs/OpenDirectory.h fs/vfs.h fs/OpenFile.h lang/string.h
|
||||
fs/ext2/ext2.o: fs/ext2/Ext2OpenFile.h fs/OpenFile.h
|
||||
fs/sysfs/sysfs.o: display/kout.h hos_defines.h fs/vfs.h devices.h
|
||||
fs/sysfs/sysfs.o: fs/sysfs/sysfs.h fs/sysfs/sysfs_entry.h lang/vector.h
|
||||
fs/sysfs/sysfs.o: lang/string.h
|
||||
fs/sysfs/sysfs_entry.o: fs/sysfs/sysfs_entry.h lang/vector.h hos_defines.h
|
||||
fs/sysfs/sysfs_entry.o: lang/string.h
|
||||
sys/pci.o: hos_defines.h display/kout.h sys/io.h sys/pci.h lang/vector.h
|
||||
proc/proc.o: hos_defines.h mm/mm.h kernel.h multiboot.h mm/vmm.h lang/lang.h
|
||||
proc/proc.o: functions.h sys/io.h display/kout.h proc/proc.h proc/hash.h
|
||||
proc/proc.o: lang/vector.h
|
||||
proc/hash.o: hos_defines.h proc/hash.h lang/vector.h display/kout.h mm/vmm.h
|
||||
proc/hash.o: multiboot.h
|
||||
fs/OpenFile.o: fs/OpenFile.h hos_defines.h
|
||||
fs/OpenDirectory.o: fs/vfs.h hos_defines.h devices.h fs/OpenDirectory.h
|
||||
fs/OpenDirectory.o: fs/OpenFile.h lang/string.h
|
||||
fs/ext2/Ext2OpenDirectory.o: display/kout.h hos_defines.h lang/lang.h
|
||||
fs/ext2/Ext2OpenDirectory.o: fs/vfs.h devices.h fs/ext2/Ext2OpenDirectory.h
|
||||
fs/ext2/Ext2OpenDirectory.o: fs/OpenDirectory.h fs/vfs.h fs/OpenFile.h
|
||||
fs/ext2/Ext2OpenDirectory.o: lang/string.h fs/ext2/ext2.h
|
||||
@@ -1,36 +0,0 @@
|
||||
// asmfuncs.h
|
||||
// Author: Josh Holtrop
|
||||
// Created: 02/26/04
|
||||
// Modified: 05/21/04
|
||||
|
||||
#ifndef __HOS_ASMFUNCS__
|
||||
#define __HOS_ASMFUNCS__ __HOS_ASMFUNCS__
|
||||
|
||||
#include "hos_defines.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
dword write_cr0(dword cr0);
|
||||
dword read_cr0();
|
||||
dword write_cr3(dword cr3);
|
||||
dword read_cr2();
|
||||
dword read_cr3();
|
||||
void writeCursorPosition(dword pos);
|
||||
dword getCursorPosition();
|
||||
int puts(char *str);
|
||||
int putDec(int number);
|
||||
int putDecu(dword number);
|
||||
void strcpy(char *dest, const char *src);
|
||||
void memcpy(void *dest, const void *src, dword n);
|
||||
void memcpyd(void *dest, const void *src, dword 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);
|
||||
dword strlen(const char *str);
|
||||
void invlpg_(dword addr);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
//fdc.c
|
||||
//Author: Josh Holtrop
|
||||
//Created: 10/30/03
|
||||
//Modified: 02/26/04
|
||||
|
||||
#include "fdc.h"
|
||||
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
//fdc.h
|
||||
//Author: Josh Holtrop
|
||||
//Date: 10/30/03
|
||||
//Modified: 02/26/04
|
||||
|
||||
#ifndef __HOS_FDC__
|
||||
#define __HOS_FDC__ __HOS_FDC__
|
||||
|
||||
#include "sys/io.h"
|
||||
|
||||
#define FDC_DOR 0x3f2
|
||||
#define FDC_MSR 0x3f4
|
||||
|
||||
//inline void fdc_sendDOR(byte dor);
|
||||
|
||||
static inline void fdc_sendDOR(byte dor)
|
||||
{
|
||||
outportb(FDC_DOR, dor);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
// loop.c
|
||||
// Author: Josh Holtrop
|
||||
// Date: 03/16/04
|
||||
// Provides a loop-back device for mounting files on existing volumes as new volumes
|
||||
|
||||
#include "hos_defines.h"
|
||||
#include "loop.h"
|
||||
#include "fs/vfs.h"
|
||||
|
||||
int loop_readSector(LoopDevice *ld, dword sector, byte *buffer)
|
||||
{
|
||||
return vfs_readFileBlock(ld->vol, ld->filePath, sector * LOOP_SECTOR_SIZE, buffer, LOOP_SECTOR_SIZE);
|
||||
}
|
||||
|
||||
|
||||
int loop_writeSector(LoopDevice *ld, dword sector, byte *buffer)
|
||||
{
|
||||
return vfs_writeFileBlock(ld->vol, ld->filePath, sector * LOOP_SECTOR_SIZE, buffer, LOOP_SECTOR_SIZE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
// loop.h
|
||||
// Author: Josh Holtrop
|
||||
// Date: 03/16/04
|
||||
// Provides a loop-back device for mounting files on existing volumes as new volumes
|
||||
|
||||
#ifndef __HOS_LOOP__
|
||||
#define __HOS_LOOP__ __HOS_LOOP__
|
||||
|
||||
#include "hos_includes.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Volume *vol;
|
||||
char filePath[256];
|
||||
} LoopDevice;
|
||||
|
||||
int loop_readSector(LoopDevice *ld, dword sector, byte *buffer);
|
||||
int loop_writeSector(LoopDevice *ld, dword sector, byte *buffer);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
// ramdisk.cpp
|
||||
// Author: Josh Holtrop
|
||||
// Date: 08/20/04
|
||||
// Modified: 05/11/05
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "functions.h"
|
||||
#include "mm/vmm.h"
|
||||
#include "lang/lang.h"
|
||||
}
|
||||
|
||||
#include "block/ramdisk.h"
|
||||
#include "devices.h"
|
||||
|
||||
ramdisk_t *ramdisks[256];
|
||||
|
||||
minor_t ramdisk_new(u32_t size)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
if (!ramdisks[i])
|
||||
{
|
||||
void *start;
|
||||
if (( start = kmalloc(size) ))
|
||||
{
|
||||
ramdisks[i] = (ramdisk_t *)New(ramdisk_t);
|
||||
ramdisks[i]->start = start;
|
||||
ramdisks[i]->size = size;
|
||||
return i;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
minor_t ramdisk_register(void *ramdisk, u32_t size)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
if (!ramdisks[i])
|
||||
{
|
||||
ramdisks[i] = (ramdisk_t *)New(ramdisk_t);
|
||||
ramdisks[i]->start = ramdisk;
|
||||
ramdisks[i]->size = size;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ramdisk_remove(minor_t minor)
|
||||
{
|
||||
if (ramdisks[minor])
|
||||
{
|
||||
kfree(ramdisks[minor]->start);
|
||||
kfree(ramdisks[minor]);
|
||||
ramdisks[minor] = NULL;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int Ramdisk::block_read(minor_t minor, u32_t blockStart, u32_t blocks, void *buffer)
|
||||
{
|
||||
if (!ramdisks[minor])
|
||||
return -1;
|
||||
if ((blockStart << BLOCK_SIZE_LOG) >= ramdisks[minor]->size)
|
||||
return -2;
|
||||
void *rdAddr = (void *)((u32_t)ramdisks[minor]->start + (blockStart << BLOCK_SIZE_LOG));
|
||||
u32_t copyLen = min(blocks << BLOCK_SIZE_LOG, ramdisks[minor]->size + (u32_t)ramdisks[minor]->start - (u32_t)rdAddr);
|
||||
memcpyd(buffer, rdAddr, copyLen >> 2);
|
||||
return copyLen;
|
||||
}
|
||||
|
||||
int Ramdisk::block_write(minor_t minor, u32_t blockStart, u32_t blocks, void *buffer)
|
||||
{
|
||||
if (!ramdisks[minor])
|
||||
return -1;
|
||||
if ((blockStart << BLOCK_SIZE_LOG) >= ramdisks[minor]->size)
|
||||
return -2;
|
||||
void *rdAddr = (void *)((u32_t)ramdisks[minor]->start + (blockStart << BLOCK_SIZE_LOG));
|
||||
u32_t copyLen = min(blocks << BLOCK_SIZE_LOG, ramdisks[minor]->size + (u32_t)ramdisks[minor]->start - (u32_t)rdAddr);
|
||||
memcpyd(rdAddr, buffer, copyLen >> 2);
|
||||
return copyLen;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// ramdisk.h
|
||||
// Author: Josh Holtrop
|
||||
// Date: 08/20/04
|
||||
// Modified: 08/22/04
|
||||
|
||||
#ifndef __HOS_RD_H__
|
||||
#define __HOS_RD_H__ __HOS_RD_H__
|
||||
|
||||
#ifdef _HOS_CPP_
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "hos_defines.h"
|
||||
#include "devices.h"
|
||||
|
||||
typedef struct {
|
||||
void *start;
|
||||
u32_t size;
|
||||
} ramdisk_t;
|
||||
|
||||
minor_t ramdisk_new(u32_t size);
|
||||
minor_t ramdisk_register(void *ramdisk, u32_t size);
|
||||
int ramdisk_remove(minor_t minor);
|
||||
|
||||
#ifdef _HOS_CPP_
|
||||
}
|
||||
|
||||
class Ramdisk : public DeviceDriver
|
||||
{
|
||||
public:
|
||||
int block_read(minor_t minor, u32_t blockStart, u32_t blocks, void *buffer);
|
||||
int block_write(minor_t minor, u32_t blockStart, u32_t blocks, void *buffer);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
// ramdisk.c
|
||||
// Author: Josh Holtrop
|
||||
// Date: 08/20/04
|
||||
// Modified: 08/22/04
|
||||
|
||||
#include "block/ramdisk.h"
|
||||
#include "fs/devices.h"
|
||||
#include "functions.h"
|
||||
#include "mm/vmm.h"
|
||||
#include "lang/lang.h"
|
||||
|
||||
ramdisk_t *ramdisks[256];
|
||||
|
||||
int ramdisk_init(major_t major)
|
||||
{
|
||||
dev_driver_t *ramdisk_driver;
|
||||
if (( ramdisk_driver = New(dev_driver_t) ))
|
||||
{
|
||||
ramdisk_driver->block_read = ramdisk_block_read;
|
||||
ramdisk_driver->block_write = ramdisk_block_write;
|
||||
devices_register_major('b', major, ramdisk_driver);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
minor_t ramdisk_new(u32_t size)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
if (!ramdisks[i])
|
||||
{
|
||||
void *start;
|
||||
if (( start = kmalloc(size) ))
|
||||
{
|
||||
ramdisks[i] = New(ramdisk_t);
|
||||
ramdisks[i]->start = start;
|
||||
ramdisks[i]->size = size;
|
||||
return i;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
minor_t ramdisk_register(void *ramdisk, u32_t size)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
if (!ramdisks[i])
|
||||
{
|
||||
ramdisks[i] = New(ramdisk_t);
|
||||
ramdisks[i]->start = ramdisk;
|
||||
ramdisks[i]->size = size;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ramdisk_remove(minor_t minor)
|
||||
{
|
||||
if (ramdisks[minor])
|
||||
{
|
||||
kfree(ramdisks[minor]->start);
|
||||
kfree(ramdisks[minor]);
|
||||
ramdisks[minor] = NULL;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ramdisk_block_read(minor_t minor, u32_t blockNum, u32_t count, void *buffer)
|
||||
{
|
||||
if (!ramdisks[minor])
|
||||
return -1;
|
||||
if ((blockNum << BLOCK_SIZE_LOG) >= ramdisks[minor]->size)
|
||||
return -2;
|
||||
void *rdAddr = ramdisks[minor]->start + (blockNum << BLOCK_SIZE_LOG);
|
||||
u32_t copyLen = min(count << BLOCK_SIZE_LOG, ramdisks[minor]->size + (u32_t)ramdisks[minor]->start - (u32_t)rdAddr);
|
||||
memcpyd(buffer, rdAddr, copyLen >> 2);
|
||||
return copyLen;
|
||||
}
|
||||
|
||||
int ramdisk_block_write(minor_t minor, u32_t blockNum, u32_t count, void *buffer)
|
||||
{
|
||||
if (!ramdisks[minor])
|
||||
return -1;
|
||||
if ((blockNum << BLOCK_SIZE_LOG) >= ramdisks[minor]->size)
|
||||
return -2;
|
||||
void *rdAddr = ramdisks[minor]->start + (blockNum << BLOCK_SIZE_LOG);
|
||||
u32_t copyLen = min(count << BLOCK_SIZE_LOG, ramdisks[minor]->size + (u32_t)ramdisks[minor]->start - (u32_t)rdAddr);
|
||||
memcpyd(rdAddr, buffer, copyLen >> 2);
|
||||
return copyLen;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
// ramdisk.h
|
||||
// Author: Josh Holtrop
|
||||
// Date: 08/20/04
|
||||
// Modified: 08/22/04
|
||||
|
||||
#ifndef __HOS_RD_H__
|
||||
#define __HOS_RD_H__ __HOS_RD_H__
|
||||
|
||||
#include "hos_defines.h"
|
||||
#include "fs/devices.h"
|
||||
|
||||
typedef struct {
|
||||
void *start;
|
||||
u32_t size;
|
||||
} ramdisk_t;
|
||||
|
||||
int ramdisk_init(major_t major);
|
||||
minor_t ramdisk_new(u32_t size);
|
||||
minor_t ramdisk_register(void *ramdisk, u32_t size);
|
||||
int ramdisk_remove(minor_t minor);
|
||||
int ramdisk_block_read(minor_t minor, u32_t blockNum, u32_t count, void *buffer);
|
||||
int ramdisk_block_write(minor_t minor, u32_t blockNum, u32_t count, void *buffer);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
// rd.c
|
||||
// Author: Josh Holtrop
|
||||
// Date: 03/11/04
|
||||
|
||||
#include "rd.h"
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
// rd.h
|
||||
// Author: Josh Holtrop
|
||||
// Date: 03/11/04
|
||||
|
||||
#ifndef __HOS_RD__
|
||||
#define __HOS_RD__ __HOS_RD__
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+236
@@ -0,0 +1,236 @@
|
||||
;boot.asm
|
||||
;Author: Josh Holtrop
|
||||
;Date: 07/08/04
|
||||
;Modified: 11/01/05
|
||||
|
||||
|
||||
%define MULTIBOOT_MAGIC 0x1BADB002
|
||||
%define MULTIBOOT_FLAGS 0x00010003
|
||||
|
||||
%define VIRT_OFFSET 0xC0000000 ;3gb virtual address
|
||||
%define PHYS_START 0x00100000 ;1mb physical address
|
||||
%define VIRT_STACK_TOP 0xD0000000 ;3gb+256mb virtual address
|
||||
%define GDT_P PHYS_START ;1mb physical - Global Descriptor Table space
|
||||
%define GDT_V GDT_P+VIRT_OFFSET
|
||||
%define IDT_P PHYS_START+0x2000 ;1mb+8kb - Interrupt Descriptor Table space
|
||||
%define IDT_V IDT_P+VIRT_OFFSET
|
||||
%define PDBR_P PHYS_START+0x4000 ;1mb+16kb - Page Directory Base Register (first PD)
|
||||
%define PDBR_V PDBR_P+VIRT_OFFSET
|
||||
%define LOPT_P PHYS_START+0x5000 ;1mb+20kb - LOw Page Table for mapping first 4mb
|
||||
%define LOPT_V LOPT_P+VIRT_OFFSET
|
||||
%define PT_STACK_P PHYS_START+0x6000 ;1mb+24kb - page table for initial kernel stack pages (under 0xD0000000)
|
||||
%define PT_STACK_V PT_STACK_P+VIRT_OFFSET
|
||||
%define STACK_P PHYS_START+0x7000 ;1mb+28kb - initial 4kb kernel stack page
|
||||
%define STACK_V STACK_P+VIRT_OFFSET
|
||||
%define KERNEL_P PHYS_START+0x8000 ;1mb+32kb - the kernel's physical address
|
||||
%define KERNEL_V KERNEL_P+VIRT_OFFSET ;3gb+1mb+32kb, the virtual address of the kernel
|
||||
|
||||
extern k_init, isr, k_mbsave, end, rm_params, initrd, tss0
|
||||
|
||||
[bits 32]
|
||||
|
||||
[global start]
|
||||
start:
|
||||
|
||||
multiboot_header:
|
||||
dd MULTIBOOT_MAGIC ;magic
|
||||
dd MULTIBOOT_FLAGS ;flags
|
||||
dd -(MULTIBOOT_MAGIC + MULTIBOOT_FLAGS) ;checksum
|
||||
|
||||
dd 0x100000000+multiboot_header-VIRT_OFFSET ;header_addr
|
||||
dd 0x100000000+start-VIRT_OFFSET ;load_addr
|
||||
dd 0 ;load_end_addr
|
||||
dd 0x100000000+end-VIRT_OFFSET ;bss_end_addr
|
||||
dd 0x100000000+multiboot_entry-VIRT_OFFSET ;entry_addr
|
||||
|
||||
; dd 1 ;mode_type
|
||||
; dd 80 ;width
|
||||
; dd 25 ;height
|
||||
; dd 0 ;depth
|
||||
|
||||
[global multiboot_entry]
|
||||
multiboot_entry:
|
||||
;This is where the kernel begins execution from the bootloader.
|
||||
;At this point, a temporary gdt is set up to "map" 0xC000_0000 to 0x0.
|
||||
cli ;should already be off...
|
||||
lgdt [0x100000000+gdtrbs32-VIRT_OFFSET]
|
||||
jmp KERNEL_CODE_BS32:segmented_start
|
||||
segmented_start:
|
||||
mov cx, KERNEL_DATA_BS32
|
||||
mov ss, cx
|
||||
mov ds, cx
|
||||
mov es, cx
|
||||
mov gs, cx
|
||||
mov fs, cx
|
||||
mov esp, STACK_V+0x1000 ;ok, now we can access our data
|
||||
|
||||
;Then the multiboot info structures are saved to local data variables.
|
||||
add ebx, VIRT_OFFSET
|
||||
push eax
|
||||
push ebx ;pointer to multiboot info structure
|
||||
call k_mbsave ;save multiboot info structures
|
||||
add esp, 8
|
||||
|
||||
cmp eax, 0 ; eax = pointer to mb_module_t struct for rmmod
|
||||
jz pm_return
|
||||
|
||||
;go back to real mode to initialize video mode
|
||||
mov ebx, eax ; pointer to mb_module_t
|
||||
mov ecx, [ebx+4] ; end of module
|
||||
mov eax, [ebx] ; start of module
|
||||
mov esi, eax ; start of module
|
||||
sub ecx, eax ; ecx = length of rmmod
|
||||
shr ecx, 2 ; ecx = length of rmmod in dwords
|
||||
mov edi, 0xC0005000 ; where to copy rmmod to (0x5000 physical)
|
||||
|
||||
rep movsd ; copy rmmod to first 1mb
|
||||
|
||||
mov ebx, pm_return ; return address
|
||||
mov ecx, rm_params ; put real mode params here (video mode etc...)
|
||||
sub ecx, VIRT_OFFSET
|
||||
|
||||
jmp 0xC0005010 ; jump to rmmod
|
||||
|
||||
;Next we enable paging with the first 4mb mapped 1:1 virtual:physical
|
||||
; and with the 4mb starting at 0xC000_0000 mapped to the first 4mb physical.
|
||||
pm_return:
|
||||
mov esp, STACK_V+0x1000 ;ok, now we can access our data again
|
||||
xor eax, eax
|
||||
mov edi, PDBR_V
|
||||
mov ecx, 1024 ;clear the PDBR
|
||||
rep stosd
|
||||
mov edi, PT_STACK_V
|
||||
mov ecx, 1024 ;clear the PT_STACK
|
||||
rep stosd
|
||||
mov [PDBR_V], dword LOPT_P|0x03 ;store the physical address of the LOw Page Table | (read/write, present)
|
||||
mov [PDBR_V+0xC00], dword LOPT_P|0x03 ;store the physical address of the LOw Page Table | (read/write, present)
|
||||
mov [PDBR_V+0xCFC], dword PT_STACK_P|0x03 ;store the physical address of the initial stack page page table | (read/write, present)
|
||||
mov [PDBR_V+0xFFC], dword PDBR_P|0x03 ;store the physical address of the page directory (identity map) | (read/write, present)
|
||||
mov [PT_STACK_V+0xFFC], dword STACK_P|0x03 ;store the physical address of the initial stack page | (read/write, present)
|
||||
|
||||
mov edi, LOPT_V
|
||||
mov ecx, 1024
|
||||
mov eax, 0x03 ;starting physical address = 0x0 | (read/write, present flags)
|
||||
fill_lopt_loop: ;fill the page table
|
||||
stosd
|
||||
add eax, 4096 ;increment next phsyical address by 4kb
|
||||
loop fill_lopt_loop
|
||||
|
||||
mov eax, PDBR_P
|
||||
mov cr3, eax ;store the Page Directory Base Address
|
||||
mov eax, cr0
|
||||
or eax, 0x80000000 ;set Page Enable bit
|
||||
mov cr0, eax ;now paging is active!
|
||||
|
||||
mov edi, GDT_V
|
||||
mov esi, gdt
|
||||
mov ecx, gdt_end-gdt
|
||||
rep movsb
|
||||
|
||||
mov edi, IDT_V ;destination
|
||||
mov esi, isr_0 ;address of isr0
|
||||
mov edx, isr_1-isr_0 ;distance between isr labels
|
||||
mov ecx, 50 ;number of isrlabels
|
||||
fill_idt:
|
||||
mov ebx, esi
|
||||
mov ax, si
|
||||
stosw ;0 offset 15:0
|
||||
mov ax, KERNEL_CODE
|
||||
stosw ;2 selector 15:0
|
||||
mov ax, 0x8E00
|
||||
stosw ;4 [P][DPL][0][TYPE][0][0][0][0][0][0][0][0]
|
||||
shr esi, 16
|
||||
mov ax, si
|
||||
stosw ;6 offset 31:16
|
||||
mov esi, ebx
|
||||
add esi, edx
|
||||
loop fill_idt
|
||||
mov word [IDT_V+0x30*8+4], 0xEE00 ;interrupt 0x30 has user priviledges
|
||||
|
||||
;Then we can start using our "real" gdt, then unmap the lower 4mb.
|
||||
lgdt [gdtr] ;load gdt
|
||||
jmp KERNEL_CODE:newgdtcontinue
|
||||
newgdtcontinue:
|
||||
mov ax, KERNEL_DATA
|
||||
mov es, ax
|
||||
mov ds, ax
|
||||
mov gs, ax
|
||||
mov fs, ax
|
||||
mov ss, ax
|
||||
mov esp, VIRT_STACK_TOP ;stack just under 3gb+256mb, moves downward
|
||||
lidt [idtr] ;load idt
|
||||
mov [PDBR_V], dword 0 ;unmap 0x0, we are running completely paged at 0xC000_0000
|
||||
|
||||
mov edi, GDT_V + TSS0_SEG + 2 ; copy tss0 base address
|
||||
mov eax, tss0 ; into the GDT descrtiptor
|
||||
stosw ; for TSS0
|
||||
shr eax, 16
|
||||
stosb
|
||||
add edi, 2
|
||||
shr eax, 8
|
||||
stosb
|
||||
|
||||
call k_init ;C kernel initialization
|
||||
|
||||
mov ax, TSS0_SEG
|
||||
ltr ax
|
||||
|
||||
mov eax, esp
|
||||
push KERNEL_DATA
|
||||
push eax
|
||||
|
||||
idle_loop: ; system idle loop
|
||||
sti
|
||||
hlt
|
||||
jmp idle_loop
|
||||
|
||||
;-------------------------------------------------------
|
||||
gdtrbs32:
|
||||
dw gdt_endbs32-gdtbs32-1
|
||||
dd 0x100000000+gdtbs32-VIRT_OFFSET
|
||||
gdtbs32: ; 0 = null descriptor
|
||||
dd 0
|
||||
dd 0
|
||||
|
||||
;a base of 0x4000_0000, when added to 0xC000_0000 will produce 0x0000_0000 physical before paging in effect
|
||||
KERNEL_CODE_BS32 equ $-gdtbs32 ; 8
|
||||
db 0xff ;limit 7:0
|
||||
db 0xff ;limit 15:8
|
||||
db 0x00 ;base 7:0
|
||||
db 0x00 ;base 15:8
|
||||
db 0x00 ;base 23:16
|
||||
db 0x9a ;access
|
||||
db 0xcf ;flags / limit 19:16
|
||||
db 0x40 ;base 31:24
|
||||
|
||||
KERNEL_DATA_BS32 equ $-gdtbs32 ; 16
|
||||
db 0xff ;limit 7:0
|
||||
db 0xff ;limit 15:8
|
||||
db 0x00 ;base 7:0
|
||||
db 0x00 ;base 15:8
|
||||
db 0x00 ;base 23:16
|
||||
db 0x92 ;access
|
||||
db 0xcf ;flags / limit 19:16
|
||||
db 0x40 ;base 31:24
|
||||
|
||||
KERNEL_CODE_BS6_ equ $-gdtbs32 ; 24
|
||||
dw 0xffff ;limit 15:0
|
||||
dw 0x0000 ;base 15:0
|
||||
db 0x00 ;base 23:16
|
||||
db 0x9A ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A])
|
||||
db 0x00 ;flags ([G][D/B][0][0]) / limit 19:16
|
||||
db 0x00 ;base 31:24
|
||||
|
||||
KERNEL_DATA_BS16 equ $-gdtbs32 ; 32
|
||||
dw 0xffff ;limit 15:0
|
||||
dw 0x0000 ;base 15:0
|
||||
db 0x00 ;base 23:16
|
||||
db 0x92 ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A])
|
||||
db 0x00 ;flags ([G][D/B][0][0]) / limit 19:16
|
||||
db 0x00 ;base 31:24
|
||||
|
||||
gdt_endbs32:
|
||||
|
||||
%include "gdt.inc"
|
||||
%include "idt.inc"
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
// keyboard.c
|
||||
// Author: Josh Holtrop
|
||||
// Created: 04/17/03
|
||||
// Modified: 05/19/05
|
||||
|
||||
#include "hos_defines.h"
|
||||
#include "char/keyboard.h"
|
||||
#include "sys/io.h" // inportb, outportb
|
||||
#include "functions.h"
|
||||
#include "lang/conv.h" // asciiSwitchCase()
|
||||
#include "display/kout.h" // kprintf()
|
||||
#include "display/display.h" // display_activate()
|
||||
|
||||
u8_t kbdFlags = 0; // holds current keyboard flags - caps/num/scroll/shift/ctrl/alt
|
||||
u8_t lastWasE0 = 0; // was the last byte 0x0E ?
|
||||
u8_t rawIgnore = 0; // how many signals to blatantly ignore
|
||||
u8_t ackReason = 0; // used to record the reason why we would get an acknowledge byte (0xFA)
|
||||
|
||||
//these arrays convert a keyboard scan code to an ASCII character value
|
||||
const u8_t SCAN2ASCII[129] = // for normal keys
|
||||
"\000\0331234567890-=\010\011" // null,esc,1234567890-=,bksp,tab
|
||||
"qwertyuiop[]\n\000as" // qwertyuiop[],enter,lctrl,as
|
||||
"dfghjkl;'`\000\\zxcv" // dfghjkl;'`,lshift,\zxcv
|
||||
"bnm,./\000*\000 \000\000\000\000\000\000" // bnm,./,rshift,*,alt,space,caps,f1,f2,f3,f4,f5
|
||||
"\000\000\000\000\000\000\000\000\000\000-\000\000\000+\000" // f6,f7,f8,f9,f10,num,scrl,home,up,pgup,dash,left,center,right,plus,end
|
||||
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" // down,pgdn,ins,del,?,?,?,f11,f12,?,?,winL,winR,menu,?,?
|
||||
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" // ?
|
||||
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"; // ?
|
||||
const u8_t SCAN2ASCII2[129] = // for shifted or numlocked keys
|
||||
"\000\033!@#$%^&*()_+\010\011" // null,esc,!@#$%^&*()_+,bksp,tab
|
||||
"QWERTYUIOP{}\n\000AS" // QWERTYUIOP{},enter,lctrl,AS
|
||||
"DFGHJKL:\"~\000|ZXCV" // DFGHJKL:"~,lshift,|ZXCV
|
||||
"BNM<>?\000*\000 \000\000\000\000\000\000" // BNM<>?,rshift,*,alt,space,caps,f1,f2,f3,f4,f5
|
||||
"\000\000\000\000\000\000\000789-456+1" // f6,f7,f8,f9,f10,num,scrl,789-456+1
|
||||
"230.\000\000\000\000\000\000\000\000\000\000\000\000" // 230.,?,?,?,f11,f12,?,?,winL,winR,menu,?,?
|
||||
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" // ?
|
||||
"\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"; // ?
|
||||
|
||||
// The Keyboard Interrupt Service Routine
|
||||
void isr_keyboard()
|
||||
{
|
||||
u8_t kbdScan = inportb(0x60);
|
||||
u8_t inState = inportb(0x61);
|
||||
outportb(0x61, inState|0x80);
|
||||
outportb(0x61, inState);
|
||||
|
||||
if (kbdScan == 0xFA) //250 // ACKnowledge
|
||||
{
|
||||
//printf("KBD_ACK 0x%x!\n", ackReason);
|
||||
switch (ackReason)
|
||||
{
|
||||
case 0xED: // reset LEDs
|
||||
outportb(0x60, (kbdFlags & 0x07));
|
||||
break;
|
||||
}
|
||||
ackReason = 0;
|
||||
}
|
||||
if (rawIgnore) // ignore keycodes
|
||||
{
|
||||
rawIgnore--;
|
||||
return;
|
||||
}
|
||||
if (lastWasE0 && (kbdScan == 0x2A || kbdScan == 0xAA)) // ignore extended "shift"
|
||||
{
|
||||
lastWasE0 = 0;
|
||||
return;
|
||||
}
|
||||
if (kbdScan == 0xE0) // 0xE0 == extended key
|
||||
{
|
||||
lastWasE0 = 1;
|
||||
return;
|
||||
}
|
||||
if (kbdScan == 0xE1) // 0xE1 == 2nd-set-extended key
|
||||
{
|
||||
rawIgnore = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (kbdScan) // handle control keys
|
||||
{
|
||||
case KBD_SCAN_LSHIFT:
|
||||
kbdFlags |= KBDF_SHIFT;
|
||||
break;
|
||||
case KBD_SCAN_RSHIFT:
|
||||
kbdFlags |= KBDF_SHIFT;
|
||||
break;
|
||||
case KBD_SCAN_CTRL:
|
||||
kbdFlags |= KBDF_CTRL;
|
||||
break;
|
||||
case KBD_SCAN_ALT:
|
||||
kbdFlags |= KBDF_ALT;
|
||||
break;
|
||||
|
||||
case KBD_SCAN_LSHIFT + KBD_SCAN_RELEASED:
|
||||
kbdFlags &= (KBDF_SHIFT ^ 0xFF);
|
||||
break;
|
||||
case KBD_SCAN_RSHIFT + KBD_SCAN_RELEASED:
|
||||
kbdFlags &= (KBDF_SHIFT ^ 0xFF);
|
||||
break;
|
||||
case KBD_SCAN_CTRL + KBD_SCAN_RELEASED:
|
||||
kbdFlags &= (KBDF_CTRL ^ 0xFF);
|
||||
break;
|
||||
case KBD_SCAN_ALT + KBD_SCAN_RELEASED:
|
||||
kbdFlags &= (KBDF_ALT ^ 0xFF);
|
||||
break;
|
||||
|
||||
case KBD_SCAN_CAPS+KBD_SCAN_RELEASED:
|
||||
kbdFlags ^= KBDF_CAPS;
|
||||
kbd_resetLEDs(); // update LEDs
|
||||
break;
|
||||
case KBD_SCAN_SCROLL+KBD_SCAN_RELEASED:
|
||||
kbdFlags ^= KBDF_SCROLL;
|
||||
kbd_resetLEDs(); // update LEDs
|
||||
break;
|
||||
case KBD_SCAN_NUM+KBD_SCAN_RELEASED:
|
||||
kbdFlags ^= KBDF_NUM;
|
||||
kbd_resetLEDs(); // update LEDs
|
||||
break;
|
||||
}
|
||||
u8_t kbdAscii;
|
||||
// shift or (numlock and key from numpad)
|
||||
if ( (kbdFlags & KBDF_SHIFT) || ((kbdFlags & KBDF_NUM) && (kbdScan >= 71) && (kbdScan <= 83)) )
|
||||
kbdAscii = SCAN2ASCII2[kbdScan & 0x7F];
|
||||
else // normal key
|
||||
kbdAscii = SCAN2ASCII[kbdScan & 0x7F];
|
||||
if (kbdFlags & KBDF_CAPS)
|
||||
kbdAscii = asciiSwitchCase(kbdAscii); // won't affect non-letter characters
|
||||
|
||||
//====do something with key::
|
||||
// kprintf("kbdScan = \e[31;1m0x%x\e[0m\tkbdAscii = \e[1;32m0x%x\e[0m (\e[35m%c\e[0m)\tkbdFlags = \e[34m0x%x\e[0m\n", kbdScan, kbdAscii, kbdAscii, kbdFlags);
|
||||
if ((kbdScan == 83) && (kbdFlags & KBDF_CTRL) && (kbdFlags & KBDF_ALT))
|
||||
{
|
||||
kprintf("Initiating reboot.");
|
||||
restart();
|
||||
}
|
||||
if (kbdScan & KBD_SCAN_RELEASED)
|
||||
kbdAscii = 0;
|
||||
|
||||
// send a key event to the display subsystem
|
||||
display_key_event((kbdFlags << 16) | (kbdScan << 8) | kbdAscii);
|
||||
}
|
||||
|
||||
//Resets the keyboard LEDs to reflect the current state of the num lock, caps lock, and scroll lock bits
|
||||
void kbd_resetLEDs()
|
||||
{
|
||||
outportb(0x60, 0xED);
|
||||
ackReason = 0xED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,252 +0,0 @@
|
||||
// keyboard.c
|
||||
// Author: Josh Holtrop
|
||||
// Created: 04/17/03
|
||||
// Modified: 03/02/04
|
||||
|
||||
#include "hos_defines.h"
|
||||
#include "keyboard.h"
|
||||
#include "sys/io.h"
|
||||
#include "sys/pic.h"
|
||||
#include "functions.h"
|
||||
#include "kio.h"
|
||||
|
||||
#define KBD_BUFFER_LENGTH 64
|
||||
|
||||
extern "C" {
|
||||
|
||||
byte kbdFlags = 0; //holds current keyboard flags - caps/num/scroll/shift/ctrl/alt
|
||||
byte kbdAscii = 0; //holds ASCII value of a key pressed
|
||||
byte kbdScan = 0; //holds the keyboard scan code of a key pressed
|
||||
|
||||
dword kbdBuffer[KBD_BUFFER_LENGTH]; //a buffer for all keypresses
|
||||
int kbdBufferStart = 0; //position of next key in buffer
|
||||
int kbdBufferLen = 0; //number of keys left in the buffer
|
||||
byte kbdExt = 0; //# of extended key codes left to input
|
||||
byte kbdExt2 = 0; //# of 2nd-set-extended key codes left to input
|
||||
byte 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
|
||||
//nul esc bksp tab lctl lsft rsft lalt caps F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 numScrlNumPad------- unknown---- F11 F12 unknown....
|
||||
const byte SCAN2ASCII[129] = "\000\0331234567890-=\010\011qwertyuiop[]\n\001asdfghjkl;'`\001\\zxcvbnm,./\001*\001 \001\001\001\001\001\001\001\001\001\001\001\001\001\001\001\001-\001\001\001+\001\001\001\001\001\002\002\002\001\001\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002";
|
||||
const byte SCAN2ASCIISHIFT[129] = "\000\033!@#$%^&*()_+\010\011QWERTYUIOP{}\n\001ASDFGHJKL:\"~\001|ZXCVBNM<>?\001*\001 \001\001\001\001\001\001\001\001\001\001\001\001\001789-456+1230.\002\002\002\001\001\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002";
|
||||
|
||||
//====FUNCTIONS:
|
||||
// The Keyboard Interrupt Service Routine
|
||||
void isr_keyboard()
|
||||
{
|
||||
kbdScan = inportb(0x60);
|
||||
//printf("\nKEYBOARD INTERRUPT: 0x%x", kbdScan);
|
||||
byte inState = inportb(0x61);
|
||||
outportb(0x61, inState|0x80);
|
||||
outportb(0x61, inState);
|
||||
|
||||
//printf("IRQ 1: %x\n", kbdScan);
|
||||
|
||||
if (kbdScan == 0xFA) //250 //ACKnowledge
|
||||
{
|
||||
//printf("KBD_ACK 0x%x!\n", ackReason);
|
||||
if (ackReason == 0xED) //reset LEDs
|
||||
{
|
||||
outportb(0x60, (kbdFlags & 0x07));
|
||||
}
|
||||
ackReason = 0;
|
||||
}
|
||||
if (kbdScan == 224) //extended key
|
||||
{
|
||||
kbdExt = 1;
|
||||
pic_eoi();
|
||||
return;
|
||||
}
|
||||
if (kbdScan == 225) //2nd-set-extended key
|
||||
{
|
||||
kbdExt2 = 2;
|
||||
pic_eoi();
|
||||
return;
|
||||
}
|
||||
|
||||
//====handle control keys::
|
||||
kbdAscii = 2;
|
||||
switch (kbdScan) //control keys
|
||||
{
|
||||
case KBD_SCAN_LSHIFT:
|
||||
kbdFlags |= KBD_SHIFT;
|
||||
kbdAscii = 1;
|
||||
break;
|
||||
case KBD_SCAN_RSHIFT:
|
||||
kbdFlags |= KBD_SHIFT;
|
||||
kbdAscii = 1;
|
||||
break;
|
||||
case KBD_SCAN_LCTRL:
|
||||
kbdFlags |= KBD_CTRL;
|
||||
kbdAscii = 1;
|
||||
break;
|
||||
case KBD_SCAN_LALT:
|
||||
kbdFlags |= KBD_ALT;
|
||||
kbdAscii = 1;
|
||||
break;
|
||||
|
||||
case KBD_SCAN_LSHIFT + KBD_SCAN_RELEASED:
|
||||
kbdFlags &= (KBD_SHIFT ^ 0xFF);
|
||||
kbdAscii = 1;
|
||||
break;
|
||||
case KBD_SCAN_RSHIFT + KBD_SCAN_RELEASED:
|
||||
kbdFlags &= (KBD_SHIFT ^ 0xFF);
|
||||
kbdAscii = 1;
|
||||
break;
|
||||
case KBD_SCAN_LCTRL + KBD_SCAN_RELEASED:
|
||||
kbdFlags &= (KBD_CTRL ^ 0xFF);
|
||||
kbdAscii = 1;
|
||||
break;
|
||||
case KBD_SCAN_LALT + KBD_SCAN_RELEASED:
|
||||
kbdFlags &= (KBD_ALT ^ 0xFF);
|
||||
kbdAscii = 1;
|
||||
break;
|
||||
|
||||
case KBD_SCAN_CAPS+KBD_SCAN_RELEASED:
|
||||
kbdFlags ^= KBD_CAPS;
|
||||
kbdAscii = 1;
|
||||
kbd_resetLEDs(); //update LEDs
|
||||
break;
|
||||
case KBD_SCAN_SCROLL+KBD_SCAN_RELEASED:
|
||||
kbdFlags ^= KBD_SCROLL;
|
||||
kbdAscii = 1;
|
||||
kbd_resetLEDs(); //update LEDs
|
||||
break;
|
||||
case KBD_SCAN_NUM+KBD_SCAN_RELEASED:
|
||||
kbdFlags ^= KBD_NUM;
|
||||
kbdAscii = 1;
|
||||
kbd_resetLEDs(); //update LEDs
|
||||
break;
|
||||
}
|
||||
if (kbdAscii == 1)
|
||||
{
|
||||
if (kbdExt > 0)
|
||||
kbdExt--;
|
||||
pic_eoi();
|
||||
return;
|
||||
}
|
||||
//====determine ASCII value of key::
|
||||
if (kbdExt > 0) //extended key, kbdScan holds extended key
|
||||
{
|
||||
kbdExt--;
|
||||
kbdAscii = 1;
|
||||
switch (kbdScan)
|
||||
{
|
||||
case KBD_SCANE_ENTER:
|
||||
kbdAscii = '\n'; break;
|
||||
case 53: // '/' character (divide on numpad)
|
||||
kbdAscii = '/'; break;
|
||||
}
|
||||
}
|
||||
else if (kbdExt2 > 0) //extended key 2
|
||||
{
|
||||
kbdExt2--;
|
||||
// if (kbdScan == 69) // (pause|break)
|
||||
// kbdAscii = 2; //flag ascii value of 1 means control character (pausebreak)
|
||||
// else
|
||||
kbdAscii = 2; //flag ascii value of 2 means ignore key (or unknown value)
|
||||
}
|
||||
else //not an extended key
|
||||
{
|
||||
// if letter key
|
||||
if (((kbdScan >= 16) && (kbdScan <= 25)) || ((kbdScan >= 30) && (kbdScan <= 38)) || ((kbdScan >= 44) && (kbdScan <= 50)))
|
||||
{
|
||||
// if caps and shift are different (either one pressed, not both)
|
||||
if (((kbdFlags & KBD_SHIFT) != 0) & ((kbdFlags & KBD_CAPS) != 0))
|
||||
kbdAscii = SCAN2ASCII[kbdScan & 0x7F];
|
||||
else if (((kbdFlags & KBD_SHIFT) == 0) & ((kbdFlags & KBD_CAPS) == 0))
|
||||
kbdAscii = SCAN2ASCII[kbdScan & 0x7F];
|
||||
else
|
||||
kbdAscii = SCAN2ASCIISHIFT[kbdScan & 0x7F];
|
||||
}
|
||||
// if numpad key
|
||||
else if ((kbdScan >= 71) && (kbdScan <= 83))
|
||||
{
|
||||
// if numlock on
|
||||
if (kbdFlags & KBD_NUM)
|
||||
kbdAscii = SCAN2ASCIISHIFT[kbdScan & 0x7F];
|
||||
else
|
||||
kbdAscii = SCAN2ASCII[kbdScan & 0x7F];
|
||||
}
|
||||
// other key
|
||||
else
|
||||
{
|
||||
if ((kbdFlags & KBD_SHIFT) != 0)
|
||||
kbdAscii = SCAN2ASCIISHIFT[kbdScan & 0x7F];
|
||||
else
|
||||
kbdAscii = SCAN2ASCII[kbdScan & 0x7F];
|
||||
}
|
||||
}
|
||||
|
||||
//====do something with key::
|
||||
// printf("kbdScan == %d\nkbdAscii == %d\nkbdFlags == %d\n", kbdScan, kbdAscii, kbdFlags);
|
||||
if ((kbdScan == 83) && (kbdFlags & KBD_CTRL) && (kbdFlags & KBD_ALT))
|
||||
{
|
||||
printf("Initiating reboot.");
|
||||
restart();
|
||||
}
|
||||
if (kbdAscii == 2) //unknown key / ignore key
|
||||
{
|
||||
pic_eoi();
|
||||
return;
|
||||
}
|
||||
if (kbdScan < KBD_SCAN_RELEASED) //a key was pressed, save it
|
||||
{
|
||||
if (kbdBufferLen >= KBD_BUFFER_LENGTH) //no key slots available
|
||||
{
|
||||
pic_eoi();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
kbdBuffer[(kbdBufferStart+kbdBufferLen++)%KBD_BUFFER_LENGTH] = (dword) ((kbdFlags << 16) | (kbdScan << 8) | kbdAscii);
|
||||
// printf("S:%d\tL:%d\tR:%x\n", kbdBufferStart, kbdBufferLen, kbdBuffer[kbdBufferStart]);
|
||||
}
|
||||
}
|
||||
|
||||
pic_eoi();
|
||||
|
||||
}
|
||||
|
||||
//Gets a key from the buffer, returns 0 if no keys available, returns immediately
|
||||
dword kbdGetKey()
|
||||
{
|
||||
if (kbdBufferLen == 0) //buffer empty
|
||||
return 0;
|
||||
dword retVal = kbdBuffer[kbdBufferStart];
|
||||
kbdBufferStart++;
|
||||
kbdBufferLen--;
|
||||
if (kbdBufferStart >= KBD_BUFFER_LENGTH)
|
||||
kbdBufferStart = 0;
|
||||
return retVal;
|
||||
}
|
||||
|
||||
//Gets a key from the buffer, if no keys available, waits for one to be entered
|
||||
dword kbdWaitKey()
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (kbdBufferLen != 0) //buffer empty
|
||||
break;
|
||||
}
|
||||
dword retVal = kbdBuffer[kbdBufferStart];
|
||||
kbdBufferStart++;
|
||||
kbdBufferLen--;
|
||||
if (kbdBufferStart >= KBD_BUFFER_LENGTH)
|
||||
kbdBufferStart = 0;
|
||||
return retVal;
|
||||
}
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
+18
-35
@@ -1,53 +1,36 @@
|
||||
// keyboard.h
|
||||
// Author: Josh Holtrop
|
||||
// Created: 04/17/03
|
||||
// Modified: 03/02/04
|
||||
// Modified: 05/19/05
|
||||
|
||||
#include "hos_defines.h"
|
||||
|
||||
#ifndef __HOS_KEYBOARD__
|
||||
#define __HOS_KEYBOARD__ __HOS_KEYBOARD__
|
||||
|
||||
#define KBD_SCROLL 0x01
|
||||
#define KBD_NUM 0x02
|
||||
#define KBD_CAPS 0x04
|
||||
#define KBD_SHIFT 0x10
|
||||
#define KBD_CTRL 0x20
|
||||
#define KBD_ALT 0x40
|
||||
#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 128
|
||||
#define KBD_SCAN_RELEASED 0x80
|
||||
|
||||
#define KBD_SCAN_LCTRL 29
|
||||
#define KBD_SCAN_LSHIFT 42
|
||||
#define KBD_SCAN_RSHIFT 54
|
||||
#define KBD_SCAN_LALT 56
|
||||
#define KBD_SCAN_SCROLL 70
|
||||
#define KBD_SCAN_CAPS 58
|
||||
#define KBD_SCAN_NUM 69
|
||||
#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_SCANE_PRINTSCREEN 55
|
||||
#define KBD_SCANE_INS 82
|
||||
#define KBD_SCANE_HOME 71
|
||||
#define KBD_SCANE_PGUP 73
|
||||
#define KBD_SCANE_DEL 83
|
||||
#define KBD_SCANE_END 79
|
||||
#define KBD_SCANE_PGDN 81
|
||||
#define KBD_SCANE_ENTER 28
|
||||
|
||||
#define KBD_SCANE_NULL 42
|
||||
|
||||
|
||||
|
||||
//====PROTOTYPES:
|
||||
|
||||
extern "C" {
|
||||
#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();
|
||||
dword kbdGetKey();
|
||||
dword kbdWaitKey();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
// misc_char.cpp
|
||||
// Miscellaneous character devices
|
||||
// Author: Josh Holtrop
|
||||
// Date: 05/11/05
|
||||
// Modified: 05/11/05
|
||||
|
||||
#include "hos_defines.h"
|
||||
#include "devices.h"
|
||||
#include "misc_char.h"
|
||||
#include "sys/io.h"
|
||||
|
||||
int MiscChar::char_read(minor_t minor)
|
||||
{
|
||||
switch (minor)
|
||||
{
|
||||
case MISC_CHAR_NULL:
|
||||
return DEV_EOF;
|
||||
case MISC_CHAR_ZERO:
|
||||
return 0;
|
||||
case MISC_CHAR_LP0:
|
||||
return DEV_INVALID_ACCESS;
|
||||
default:
|
||||
return DEV_INVALID_ACCESS;
|
||||
}
|
||||
}
|
||||
|
||||
int MiscChar::char_write(minor_t minor, int c)
|
||||
{
|
||||
switch (minor)
|
||||
{
|
||||
case MISC_CHAR_NULL:
|
||||
return 0;
|
||||
case MISC_CHAR_ZERO:
|
||||
return 0;
|
||||
case MISC_CHAR_LP0:
|
||||
outportb(0x37a, 0xc);
|
||||
outportb(0x378, c);
|
||||
outportb(0x37a, 0x1);
|
||||
return 0;
|
||||
default:
|
||||
return DEV_INVALID_ACCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
// misc_char.h
|
||||
// Miscellaneous character devices
|
||||
// Author: Josh Holtrop
|
||||
// Date: 05/11/05
|
||||
// Modified: 05/11/05
|
||||
|
||||
#ifndef __HOS_MISC_CHAR__
|
||||
#define __HOS_MISC_CHAR__ __HOS_MISC_CHAR__
|
||||
|
||||
#define MISC_CHAR_NULL 3
|
||||
#define MISC_CHAR_ZERO 5
|
||||
#define MISC_CHAR_LP0 10
|
||||
|
||||
#include "hos_defines.h"
|
||||
#include "devices.h"
|
||||
#include "misc_char.h"
|
||||
|
||||
#ifdef _HOS_CPP_
|
||||
|
||||
class MiscChar : public DeviceDriver
|
||||
{
|
||||
public:
|
||||
int char_read(minor_t minor);
|
||||
int char_write(minor_t minor, int c);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,19 +1,13 @@
|
||||
// mouse.c
|
||||
// Author: Josh Holtrop
|
||||
// Date: 10/03/03
|
||||
// Modified: 05/21/04
|
||||
// Modified: 08/02/04
|
||||
|
||||
#include "mouse.h"
|
||||
#include "hos_defines.h"
|
||||
#include "char/mouse.h"
|
||||
#include "video/video.h"
|
||||
#include "sys/io.h"
|
||||
|
||||
#define MOUSE_BUFFER_LENGTH 16
|
||||
|
||||
extern "C" {
|
||||
|
||||
int mouse_x;
|
||||
int mouse_y;
|
||||
int mouse_bytesRead;
|
||||
byte mouse_inbuffer[MOUSE_BUFFER_LENGTH];
|
||||
|
||||
@@ -23,16 +17,13 @@ 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(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_x = video_getWidth() >> 1;
|
||||
mouse_y = video_getHeight() >> 1;
|
||||
|
||||
mouse_bytesRead = 0;
|
||||
|
||||
//outportb(0x64, 0xD4);
|
||||
@@ -53,24 +44,9 @@ void isr_mouse()
|
||||
mouse_bytesRead = 0;
|
||||
int adjx = (char) mouse_inbuffer[1];
|
||||
int adjy = (char) mouse_inbuffer[2];
|
||||
mouse_x += adjx;
|
||||
mouse_y -= adjy; //-= because screen y coordinates are opposite mouse y coordinates
|
||||
if (mouse_x < 0)
|
||||
mouse_x = 0;
|
||||
if (mouse_x >= video_getWidth())
|
||||
mouse_x = video_getWidth() - 1;
|
||||
if (mouse_y < 0)
|
||||
mouse_y = 0;
|
||||
if (mouse_y >= video_getHeight())
|
||||
mouse_y = video_getHeight() - 1;
|
||||
if (mouse_inbuffer[0] & 0x01) //left button
|
||||
video_pset(mouse_x, mouse_y, 0x00FF9900);
|
||||
else
|
||||
video_pset(mouse_x, mouse_y, 0x00FFFFFF);
|
||||
// TODO: do something with adjx, adjy...
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+2
-4
@@ -1,17 +1,15 @@
|
||||
// mouse.h
|
||||
// Author: Josh Holtrop
|
||||
// Date: 10/03/03
|
||||
// Modified: 03/02/04
|
||||
// Modified: 08/02/04
|
||||
|
||||
#ifndef __HOS_MOUSE__
|
||||
#define __HOS_MOUSE__ __HOS_MOUSE__
|
||||
|
||||
extern "C" {
|
||||
#define MOUSE_BUFFER_LENGTH 16
|
||||
|
||||
void mouse_init();
|
||||
void isr_mouse();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,274 @@
|
||||
// vconsole.cpp
|
||||
// Author: Josh Holtrop
|
||||
// Date: 08/02/04
|
||||
// Modified: 05/11/05
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "hos_defines.h"
|
||||
#include "mm/vmm.h"
|
||||
#include "lang/lang.h"
|
||||
#include "display/display.h"
|
||||
#include "functions.h"
|
||||
}
|
||||
|
||||
#include "devices.h"
|
||||
#include "char/vconsole.h"
|
||||
|
||||
VConsole *vconsoles[VCONSOLE_MAX]; // pointer to virtual console structs
|
||||
char ansi2vgaAttr[8] = {0, 4, 2, 6, 1, 5, 3, 7};
|
||||
|
||||
void vconsole_setup(int width, int height)
|
||||
{
|
||||
for (int i = 0; i < VCONSOLE_MAX; i++)
|
||||
vconsoles[i] = new VConsole(width, height);
|
||||
}
|
||||
|
||||
int vconsole_activate(u32_t id)
|
||||
{
|
||||
if (id >= VCONSOLE_MAX)
|
||||
return -1;
|
||||
vconsoles[id]->activate();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vconsole_deactivate(u32_t id)
|
||||
{
|
||||
if (id >= VCONSOLE_MAX)
|
||||
return -1;
|
||||
vconsoles[id]->deactivate();
|
||||
return 0;
|
||||
}
|
||||
|
||||
VConsoleDriver::~VConsoleDriver()
|
||||
{
|
||||
for (int i = 0; i < VCONSOLE_MAX; i++)
|
||||
if (vconsoles[i])
|
||||
delete vconsoles[i];
|
||||
}
|
||||
|
||||
int VConsoleDriver::char_write(minor_t minor, int c)
|
||||
{
|
||||
if (minor < 0 || minor >= VCONSOLE_MAX)
|
||||
return -1;
|
||||
if (!vconsoles[minor])
|
||||
return -2;
|
||||
return vconsoles[minor]->char_write(c);
|
||||
}
|
||||
|
||||
VConsole::VConsole(int width, int height)
|
||||
{
|
||||
myBuffer = new u16_t[width * height];
|
||||
myBuffer2 = NULL;
|
||||
myWidth = width;
|
||||
myHeight = height;
|
||||
myAttribute = myForeground = 0x07;
|
||||
memsetw(myBuffer, 0x0720, width * height);
|
||||
myCursorPosition = 0;
|
||||
myCursorStackPosition = myEscapeLevel = myEscapePosition = myBackground =
|
||||
myBold = myReverse = myBlink = myConcealed = myActive = 0;
|
||||
|
||||
}
|
||||
|
||||
VConsole::~VConsole()
|
||||
{
|
||||
delete[] myBuffer;
|
||||
}
|
||||
|
||||
void VConsole::activate()
|
||||
{
|
||||
if (myActive) // don't activate if already active
|
||||
return;
|
||||
myActive = 1;
|
||||
myBuffer2 = myBuffer;
|
||||
myBuffer = (u16_t *)CONSOLE_MEMORY;
|
||||
memcpyd(myBuffer, myBuffer2, (myWidth * myHeight) >> 1);
|
||||
writeCursorPosition(myCursorPosition);
|
||||
}
|
||||
|
||||
void VConsole::deactivate()
|
||||
{
|
||||
if (!myActive) // don't deactivate non-active console
|
||||
return;
|
||||
myActive = 0;
|
||||
myBuffer = myBuffer2;
|
||||
myBuffer2 = NULL;
|
||||
memcpyd(myBuffer, (u16_t *)CONSOLE_MEMORY, (myWidth * myHeight) >> 1);
|
||||
}
|
||||
|
||||
int VConsole::char_write(int c)
|
||||
{
|
||||
int cursorY = myCursorPosition / myWidth;
|
||||
int cursorX = myCursorPosition % myWidth;
|
||||
switch (myEscapeLevel)
|
||||
{
|
||||
case 2:
|
||||
if (c >= '0' && c <= '9') // c is part of an escape value
|
||||
{
|
||||
myEscapeValue[myEscapePosition] *= 10;
|
||||
myEscapeValue[myEscapePosition] += c - '0';
|
||||
return 0;
|
||||
}
|
||||
else if (c == ';')
|
||||
{
|
||||
if (myEscapePosition < 7)
|
||||
myEscapePosition++;
|
||||
return 0;
|
||||
}
|
||||
switch (c)
|
||||
{
|
||||
case 'A': // move cursor up n rows
|
||||
update_cursor_coord(cursorY - myEscapeValue[0], cursorX);
|
||||
break;
|
||||
case 'B': // move cursor down n rows
|
||||
update_cursor_coord(cursorY + myEscapeValue[0], cursorX);
|
||||
break;
|
||||
case 'C': // move cursor left n columns
|
||||
update_cursor_coord(cursorY, cursorX - myEscapeValue[0]);
|
||||
break;
|
||||
case 'D': // move cursor right n columns
|
||||
update_cursor_coord(cursorY, cursorX + myEscapeValue[0]);
|
||||
break;
|
||||
case 'H':
|
||||
case 'f': // move cursor to position (x,y) upper left is (1,1)
|
||||
update_cursor_coord(myEscapeValue[1] - 1, myEscapeValue[0] - 1);
|
||||
break;
|
||||
case 'J': // clear screen, home cursor
|
||||
memsetw(myBuffer, 0x0720, myWidth * myHeight);
|
||||
update_cursor_coord(0, 0);
|
||||
break;
|
||||
case 'K': // erase line from cursor position (including char. under cursor) to end of line
|
||||
memsetw(myBuffer + myCursorPosition, 0x0720, myWidth - cursorX);
|
||||
break;
|
||||
case 's': // push cursor position on an internal stack
|
||||
if (myCursorStackPosition < 16)
|
||||
myCursorStack[myCursorStackPosition++] = myCursorPosition;
|
||||
break;
|
||||
case 'u': // pop cursor position from stack
|
||||
if (myCursorStackPosition > 0)
|
||||
update_cursor(myCursorStack[--myCursorStackPosition]);
|
||||
break;
|
||||
case 'm': // set text attributes
|
||||
for (int evalEscapePosition = 0; evalEscapePosition <= myEscapePosition; evalEscapePosition++)
|
||||
{
|
||||
switch (myEscapeValue[evalEscapePosition])
|
||||
{
|
||||
case 0:
|
||||
myForeground = 0x07;
|
||||
myBackground = myConcealed = myReverse = myBlink = myBold = 0;
|
||||
update_attribute();
|
||||
break;
|
||||
case 1:
|
||||
myBold = 1;
|
||||
update_attribute();
|
||||
break;
|
||||
case 5:
|
||||
myBlink = 1;
|
||||
update_attribute();
|
||||
break;
|
||||
case 7:
|
||||
myReverse = 1;
|
||||
update_attribute();
|
||||
break;
|
||||
case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37:
|
||||
myForeground = ansi2vgaAttr[myEscapeValue[evalEscapePosition] - 30];
|
||||
update_attribute();
|
||||
break;
|
||||
case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47:
|
||||
myBackground = ansi2vgaAttr[myEscapeValue[evalEscapePosition] - 40];
|
||||
update_attribute();
|
||||
break;
|
||||
}
|
||||
}
|
||||
myEscapePosition = 0;
|
||||
break;
|
||||
}
|
||||
memsetd(myEscapeValue, 0, 8);
|
||||
myEscapePosition = 0;
|
||||
myEscapeLevel = 0;
|
||||
return 0;
|
||||
case 1:
|
||||
if (c == '[')
|
||||
myEscapeLevel = 2;
|
||||
break;
|
||||
myEscapeLevel = 0;
|
||||
return 0; // invalid escape sequence
|
||||
default:
|
||||
if (c == '\e')
|
||||
{
|
||||
myEscapeLevel = 1;
|
||||
return 0;
|
||||
}
|
||||
put_char(c);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void VConsole::put_char(int c)
|
||||
{
|
||||
if (!myConcealed)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '\t':
|
||||
if (myCursorPosition % 8)
|
||||
update_cursor(myCursorPosition + (8 - (myCursorPosition % 8)));
|
||||
else
|
||||
update_cursor(myCursorPosition + 8);
|
||||
break;
|
||||
case '\n':
|
||||
if (myCursorPosition % myWidth)
|
||||
update_cursor(myCursorPosition + (myWidth - (myCursorPosition % myWidth)));
|
||||
else
|
||||
update_cursor(myCursorPosition + myWidth);
|
||||
break;
|
||||
default:
|
||||
myBuffer[myCursorPosition] = c | (myAttribute << 8);
|
||||
update_cursor(myCursorPosition + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VConsole::update_cursor_coord(int y, int x)
|
||||
{
|
||||
if (y < 0)
|
||||
y = 0;
|
||||
else if (y >= myHeight)
|
||||
y = myHeight - 1;
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
else if (x >= myWidth)
|
||||
x = myWidth - 1;
|
||||
update_cursor(myWidth * y + x);
|
||||
}
|
||||
|
||||
void VConsole::update_cursor(u16_t position)
|
||||
{
|
||||
myCursorPosition = position;
|
||||
if (position >= (myWidth * myHeight)) // time to scroll console
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < myCursorStackPosition; i++)
|
||||
{
|
||||
myCursorStack[i] -= myWidth;
|
||||
if (myCursorStack[i] < 0)
|
||||
myCursorStack[i] = 0;
|
||||
}
|
||||
myCursorPosition -= myWidth;
|
||||
memcpyw(myBuffer, myBuffer + myWidth, myWidth * (myHeight - 1));
|
||||
memsetw(myBuffer + (myWidth * (myHeight - 1)), 0x0720, myWidth);
|
||||
}
|
||||
if (myActive)
|
||||
writeCursorPosition(position);
|
||||
}
|
||||
|
||||
void VConsole::update_attribute()
|
||||
{
|
||||
if (myReverse)
|
||||
myAttribute = myBlink << 7 | myForeground << 4 | myBold << 3 | myBackground;
|
||||
else
|
||||
myAttribute = myBlink << 7 | myBackground << 4 | myBold << 3 | myForeground;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
// vconsole.h
|
||||
// Author: Josh Holtrop
|
||||
// Date: 08/02/04
|
||||
// Modified: 05/11/05
|
||||
|
||||
#ifndef __HOS_VCONSOLE__
|
||||
#define __HOS_VCONSOLE__ __HOS_VCONSOLE__
|
||||
|
||||
#define VCONSOLE_MAX 12
|
||||
|
||||
#ifdef _HOS_CPP_
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "hos_defines.h"
|
||||
|
||||
void vconsole_setup(int width, int height);
|
||||
int vconsole_activate(u32_t id);
|
||||
int vconsole_deactivate(u32_t id);
|
||||
|
||||
|
||||
#ifdef _HOS_CPP_
|
||||
}
|
||||
|
||||
#include "devices.h"
|
||||
|
||||
class VConsoleDriver : public DeviceDriver
|
||||
{
|
||||
public:
|
||||
~VConsoleDriver();
|
||||
int char_write(minor_t minor, int c);
|
||||
};
|
||||
|
||||
class VConsole
|
||||
{
|
||||
protected:
|
||||
u16_t *myBuffer;
|
||||
u16_t *myBuffer2;
|
||||
u16_t myWidth;
|
||||
u16_t myHeight;
|
||||
u16_t myCursorPosition;
|
||||
|
||||
short myCursorStack[16];
|
||||
u8_t myCursorStackPosition;
|
||||
|
||||
u32_t myEscapeValue[8];
|
||||
u8_t myEscapeLevel;
|
||||
u8_t myEscapePosition;
|
||||
|
||||
u8_t myAttribute;
|
||||
u8_t myForeground;
|
||||
u8_t myBackground;
|
||||
u8_t myBold;
|
||||
u8_t myReverse;
|
||||
u8_t myBlink;
|
||||
u8_t myConcealed;
|
||||
|
||||
u8_t myActive;
|
||||
|
||||
public:
|
||||
VConsole(int width, int height);
|
||||
~VConsole();
|
||||
int char_read();
|
||||
int char_write(int c);
|
||||
void put_char(int c);
|
||||
void update_cursor(u16_t position);
|
||||
void update_cursor_coord(int y, int x);
|
||||
void update_attribute();
|
||||
void activate();
|
||||
void deactivate();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
// devices.cpp
|
||||
// Device subsystem for HOS
|
||||
// Author: Josh Holtrop
|
||||
// Date: 05/11/05
|
||||
// Modified: 05/11/05
|
||||
|
||||
#include "hos_defines.h"
|
||||
#include "devices.h"
|
||||
#include "char/misc_char.h"
|
||||
#include "char/vconsole.h"
|
||||
#include "block/ramdisk.h"
|
||||
|
||||
DeviceDriver *drivers[256];
|
||||
|
||||
int devices_init()
|
||||
{
|
||||
drivers[MAJOR_MISC_CHAR] = new MiscChar();
|
||||
drivers[MAJOR_VCONSOLE] = new VConsoleDriver();
|
||||
drivers[MAJOR_RAMDISK] = new Ramdisk();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int block_read(major_t major, minor_t minor, u32_t blockStart, u32_t blocks, void *buffer)
|
||||
{
|
||||
if (drivers[major & 0xFF])
|
||||
return drivers[major & 0xFF]->block_read(minor, blockStart, blocks, buffer);
|
||||
return DEV_INVALID_DEVICE;
|
||||
}
|
||||
|
||||
int block_write(major_t major, minor_t minor, u32_t blockStart, u32_t blocks, void *buffer)
|
||||
{
|
||||
if (drivers[major & 0xFF])
|
||||
return drivers[major & 0xFF]->block_write(minor, blockStart, blocks, buffer);
|
||||
return DEV_INVALID_DEVICE;
|
||||
}
|
||||
|
||||
int char_read(major_t major, minor_t minor)
|
||||
{
|
||||
if (drivers[major & 0xFF])
|
||||
return drivers[major & 0xFF]->char_read(minor);
|
||||
return DEV_INVALID_DEVICE;
|
||||
}
|
||||
|
||||
int char_write(major_t major, minor_t minor, int c)
|
||||
{
|
||||
if (drivers[major & 0xFF])
|
||||
return drivers[major & 0xFF]->char_write(minor, c);
|
||||
return DEV_INVALID_DEVICE;
|
||||
}
|
||||
|
||||
DeviceDriver::DeviceDriver() {}
|
||||
DeviceDriver::~DeviceDriver() {}
|
||||
|
||||
int DeviceDriver::char_read(minor_t minor)
|
||||
{ return DEV_INVALID_ACCESS; }
|
||||
|
||||
int DeviceDriver::char_write(minor_t minor, int c)
|
||||
{ return DEV_INVALID_ACCESS; }
|
||||
|
||||
int DeviceDriver::block_read(minor_t minor, u32_t blockStart, u32_t blocks, void *buffer)
|
||||
{ return DEV_INVALID_ACCESS; }
|
||||
|
||||
int DeviceDriver::block_write(minor_t minor, u32_t blockStart, u32_t blocks, void *buffer)
|
||||
{ return DEV_INVALID_ACCESS; }
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
// devices.h
|
||||
// Device subsystem for HOS
|
||||
// Author: Josh Holtrop
|
||||
// Date: 05/11/05
|
||||
// Modified: 06/02/05
|
||||
|
||||
#ifndef __HOS_DEVICES_H__
|
||||
#define __HOS_DEVICES_H__ __HOS_DEVICES_H__
|
||||
|
||||
#include "hos_defines.h"
|
||||
|
||||
#define DEV_INVALID_ACCESS -256
|
||||
#define DEV_INVALID_DEVICE -257
|
||||
#define DEV_EOF -1
|
||||
|
||||
#define MAJOR_MISC_CHAR 1
|
||||
#define MAJOR_RAMDISK 2
|
||||
#define MAJOR_VCONSOLE 4
|
||||
|
||||
#define BLOCK_SIZE 512
|
||||
#define BLOCK_SIZE_LOG 9
|
||||
|
||||
#define DEV_MAJOR(x) (((x) >> 8) & 0xFF)
|
||||
#define DEV_MINOR(x) ((x) & 0xFF)
|
||||
#define DEV(x,y) ((x) << 8 | (y))
|
||||
|
||||
typedef short major_t;
|
||||
typedef short minor_t;
|
||||
typedef u32_t device_t;
|
||||
|
||||
#ifdef _HOS_CPP_
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int devices_init();
|
||||
int block_read(major_t major, minor_t minor, u32_t blockStart, u32_t blocks, void *buffer);
|
||||
int block_write(major_t major, minor_t minor, u32_t blockStart, u32_t blocks, void *buffer);
|
||||
int char_read(major_t major, minor_t minor);
|
||||
int char_write(major_t major, minor_t minor, int c);
|
||||
|
||||
#ifdef _HOS_CPP_
|
||||
}
|
||||
|
||||
class DeviceDriver
|
||||
{
|
||||
public:
|
||||
DeviceDriver();
|
||||
virtual ~DeviceDriver();
|
||||
virtual int char_read(minor_t minor);
|
||||
virtual int char_write(minor_t minor, int c);
|
||||
virtual int block_read(minor_t minor, u32_t blockStart, u32_t blocks, void *buffer);
|
||||
virtual int block_write(minor_t minor, u32_t blockStart, u32_t blocks, void *buffer);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
// display.c
|
||||
// Author: Josh Holtrop
|
||||
// Date: 08/07/04
|
||||
// Modified: 03/19/05
|
||||
|
||||
#include "devices.h"
|
||||
#include "char/vconsole.h"
|
||||
#include "display.h"
|
||||
#include "lang/lang.h"
|
||||
#include "kernel.h"
|
||||
#include "char/keyboard.h"
|
||||
#include "display/kout.h"
|
||||
|
||||
extern real_mode_param_t rm_params; // check if a video mode is activated
|
||||
int display_type;
|
||||
int display_activeConsole = -1; // start with no active console
|
||||
|
||||
|
||||
// initialization routine for display subsystem
|
||||
int display_init()
|
||||
{
|
||||
if (!rm_params.vid_addr) // framebuffer mode
|
||||
{
|
||||
vconsole_setup(80, 25);
|
||||
display_activate(KERNEL_MSG_CONSOLE);
|
||||
display_type = DISPLAY_CONSOLE;
|
||||
}
|
||||
else
|
||||
display_type = DISPLAY_GRAPHICAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// activate the given display
|
||||
int display_activate(u32_t id)
|
||||
{
|
||||
if (id == display_activeConsole)
|
||||
return 0;
|
||||
if (display_type != DISPLAY_CONSOLE)
|
||||
return -1;
|
||||
if (id >= VCONSOLE_MAX)
|
||||
return -2;
|
||||
if (display_activeConsole >= 0)
|
||||
vconsole_deactivate(display_activeConsole);
|
||||
if (vconsole_activate(id)) // if true, didn't work to activate console
|
||||
{
|
||||
vconsole_activate(display_activeConsole); // restore old one
|
||||
return -3;
|
||||
}
|
||||
display_activeConsole = id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void display_key_event(u32_t keyCode)
|
||||
{
|
||||
if (display_type == DISPLAY_CONSOLE)
|
||||
{
|
||||
u32_t kbdScan = KBD_SCAN(keyCode);
|
||||
if ( /* kbdFlags & KBDF_ALT && */ kbdScan >= 0x3B && kbdScan <= 0x44) // switch displays F1-F10
|
||||
{
|
||||
display_activate(kbdScan - 0x3B);
|
||||
return;
|
||||
}
|
||||
if ( /* kbdFlags & KBDF_ALT && */ kbdScan >= 0x57 && kbdScan <= 0x58) // F11-F12
|
||||
{
|
||||
display_activate(kbdScan - 0x4D);
|
||||
return;
|
||||
}
|
||||
if (KBD_ASCII(keyCode))
|
||||
putc(KBD_ASCII(keyCode));
|
||||
}
|
||||
/* TODO: send key to process on active console
|
||||
or graphical control process */
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// display.h
|
||||
// Author: Josh Holtrop
|
||||
// Date: 08/07/04
|
||||
// Modified: 03/19/05
|
||||
|
||||
#ifndef __HOS_CONSOLE__
|
||||
#define __HOS_CONSOLE__ __HOS_CONSOLE__
|
||||
|
||||
#include "hos_defines.h"
|
||||
#include "devices.h"
|
||||
|
||||
#define DISPLAY_CONSOLE 0
|
||||
#define DISPLAY_GRAPHICAL 1
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int type;
|
||||
minor_t id;
|
||||
} display_t;
|
||||
|
||||
int display_init();
|
||||
int display_activate(u32_t id);
|
||||
|
||||
void display_key_event(u32_t keyCode);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
// kout.c
|
||||
// Author: Josh Holtrop
|
||||
// Date: 08/02/04
|
||||
// Modified: 11/02/05
|
||||
|
||||
#include "hos_defines.h"
|
||||
#include "kout.h"
|
||||
#include "lang/conv.h"
|
||||
#include "devices.h"
|
||||
#include "char/misc_char.h"
|
||||
#include "functions.h"
|
||||
|
||||
char buffer[64]; // for hex/oct/dec/ascii conversion
|
||||
|
||||
// print a character
|
||||
void putc(int c)
|
||||
{
|
||||
#ifdef PARALLEL_DEBUG
|
||||
outportb(0x37a, 0xc);
|
||||
outportb(0x378, c);
|
||||
outportb(0x37a, 0x1);
|
||||
// char_write(MAJOR_MISC_CHAR, MISC_CHAR_LP0, c);
|
||||
#endif
|
||||
char_write(MAJOR_VCONSOLE, KERNEL_MSG_CONSOLE, c);
|
||||
}
|
||||
|
||||
|
||||
// print a formatted string
|
||||
void kprintf(char *fmt, ...)
|
||||
{
|
||||
u32_t *params = ((u32_t *)(&fmt)) + 1; // points to the first paramater
|
||||
int i;
|
||||
int special = 0;
|
||||
for (i = 0; ; i++)
|
||||
{
|
||||
if (special)
|
||||
{
|
||||
special = 0;
|
||||
switch (fmt[i])
|
||||
{
|
||||
case 0:
|
||||
return;
|
||||
case '%':
|
||||
putc('%');
|
||||
break;
|
||||
case 's': case 'S':
|
||||
puts((char *)*params);
|
||||
params++;
|
||||
break;
|
||||
case 'c': case 'C':
|
||||
putc(*params);
|
||||
params++;
|
||||
break;
|
||||
case 'd': case 'D': case 'i': case 'I':
|
||||
putDec(*params);
|
||||
params++;
|
||||
break;
|
||||
case 'u': case 'U':
|
||||
putDecu(*params);
|
||||
params++;
|
||||
break;
|
||||
case 'x': case 'X':
|
||||
putHex(*params);
|
||||
params++;
|
||||
break;
|
||||
case 'o': case 'O':
|
||||
putOct(*params);
|
||||
params++;
|
||||
break;
|
||||
case 'b': case 'B':
|
||||
kio_putBCD(*params);
|
||||
params++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (fmt[i])
|
||||
{
|
||||
case '%':
|
||||
special = 1;
|
||||
break;
|
||||
case 0:
|
||||
return;
|
||||
default:
|
||||
putc(fmt[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This function prints a raw string
|
||||
void puts(char *str)
|
||||
{
|
||||
while (*str)
|
||||
{
|
||||
putc(*str++);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This function prints a signed, decimal integer
|
||||
void putDec(int num)
|
||||
{
|
||||
itoa(num, buffer);
|
||||
puts(buffer);
|
||||
}
|
||||
|
||||
|
||||
// This function prints an unsigned, decimal integer
|
||||
void putDecu(u32_t num)
|
||||
{
|
||||
utoa(num, buffer);
|
||||
puts(buffer);
|
||||
}
|
||||
|
||||
|
||||
// This function displays a number in hexadecimal
|
||||
void putHex(u32_t num)
|
||||
{
|
||||
itox(num, buffer);
|
||||
puts(buffer);
|
||||
}
|
||||
|
||||
|
||||
// This function displays a number in octal
|
||||
void putOct(u32_t num)
|
||||
{
|
||||
itoo(num, buffer);
|
||||
puts(buffer);
|
||||
}
|
||||
|
||||
|
||||
// This function prints a two-digit binary-coded-decimal value
|
||||
void kio_putBCD(u32_t bcd)
|
||||
{
|
||||
bcdtoa(bcd, buffer);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// kout.h
|
||||
// Author: Josh Holtrop
|
||||
// Date: 08/02/04
|
||||
|
||||
#ifndef __HOS_KOUT__
|
||||
#define __HOS_KOUT__ __HOS_KOUT__
|
||||
|
||||
#include "hos_defines.h"
|
||||
|
||||
void kprintf(char *fmt, ...);
|
||||
void putHex(u32_t number);
|
||||
void kio_putBCD(u32_t bcd);
|
||||
void putc(int c);
|
||||
void puts(char *str);
|
||||
void putDec(int num);
|
||||
void putDecu(u32_t num);
|
||||
void putOct(u32_t number);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
// vesafb.c
|
||||
// Author: Josh Holtrop
|
||||
// Date: 03/19/05
|
||||
// Modified: 03/19/05
|
||||
|
||||
#include "display/display.h"
|
||||
#include "display/vesafb.h"
|
||||
#include "lang/lang.h"
|
||||
#include "hos_defines.h" // BIOS_CHAR_MAP
|
||||
|
||||
u16_t *vmem16 = (u16_t *) VESAFB_VID_ADDR;
|
||||
u32_t *vmem32 = (u32_t *) VESAFB_VID_ADDR;
|
||||
int vesafb_bpp;
|
||||
int vesafb_multiplier;
|
||||
int vesafb_width; // pixels
|
||||
int vesafb_height;
|
||||
int vesafb_xres; // characters
|
||||
int vesafb_yres;
|
||||
int vesafb_cursor; // -1 to hide, 0+ for cursor position
|
||||
|
||||
int vesafb_init(int width, int height, int bpp)
|
||||
{
|
||||
switch(vesafb_bpp = bpp)
|
||||
{
|
||||
case 15: case 16:
|
||||
vesafb_multiplier = 2;
|
||||
break;
|
||||
case 24:
|
||||
vesafb_multiplier = 3;
|
||||
break;
|
||||
case 32:
|
||||
vesafb_multiplier = 4;
|
||||
break;
|
||||
}
|
||||
vesafb_width = width;
|
||||
vesafb_height = height;
|
||||
vesafb_xres = (width >> 3) & 0xFFF8; // columns divisible by 8
|
||||
vesafb_yres = height >> 3;
|
||||
return vesafb_cursor = 0;
|
||||
}
|
||||
|
||||
void vesafb_clear()
|
||||
{
|
||||
memset(vmem32, 0, vesafb_width * vesafb_height * vesafb_multiplier);
|
||||
vesafb_update_cursor(0);
|
||||
}
|
||||
|
||||
void vesafb_update_cursor(int position)
|
||||
{
|
||||
vesafb_draw_cursor(vesafb_cursor, 0);
|
||||
vesafb_draw_cursor(vesafb_cursor = position, 1);
|
||||
}
|
||||
|
||||
void vesafb_draw_cursor(int position, int onoff)
|
||||
{
|
||||
int x = (position % vesafb_xres) << 3;
|
||||
int y = ( (position / vesafb_xres) << 3 ) + 7;
|
||||
int i;
|
||||
for (i = 0; i < 7; i++)
|
||||
vesafb_pset(x + i, y, onoff);
|
||||
}
|
||||
|
||||
void vesafb_pset(int x, int y, int onoff)
|
||||
{
|
||||
switch (vesafb_bpp)
|
||||
{
|
||||
case 15: case 16:
|
||||
*(vmem16 + vesafb_width*y + x) = (onoff ? 0xFFFF : 0);
|
||||
break;
|
||||
case 24:
|
||||
*((u32_t *)(((u32_t)vmem32) + 3*vesafb_width*y + 3*x)) = (onoff ? 0x00FFFFFF : 0);
|
||||
break;
|
||||
case 32:
|
||||
*(vmem32 + vesafb_width*y + x) = (onoff ? 0x00FFFFFF : 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int vesafb_getWidth()
|
||||
{
|
||||
return vesafb_xres;
|
||||
}
|
||||
|
||||
int vesafb_getHeight()
|
||||
{
|
||||
return vesafb_yres;
|
||||
}
|
||||
|
||||
void vesafb_draw_char(int position, u16_t chr)
|
||||
{
|
||||
int x = (position % vesafb_xres) << 3;
|
||||
int y = (position / vesafb_xres) << 3;
|
||||
int xi, yi;
|
||||
u8_t *charMap = (u8_t *) ( BIOS_CHAR_MAP + ((chr & 0xFF) << 3) );
|
||||
for (yi = 0; yi < 7; yi++)
|
||||
{
|
||||
for (xi = 0; xi < 7; xi++)
|
||||
vesafb_pset(x + xi, y + yi, (*charMap & (0x80 >> xi)));
|
||||
charMap++;
|
||||
}
|
||||
}
|
||||
|
||||
int vesafb_draw(u16_t *buffer, int buff_len, int cursor_position)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < buff_len; i++)
|
||||
vesafb_draw_char(i, *buffer++);
|
||||
vesafb_update_cursor(cursor_position);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
// vesafb.h
|
||||
// Author: Josh Holtrop
|
||||
// Date: 03/19/05
|
||||
// Modified: 03/19/05
|
||||
|
||||
#ifndef __HOS_VESAFB__
|
||||
#define __HOS_VESAFB__ __HOS_VESAFB__
|
||||
|
||||
#include "hos_defines.h"
|
||||
|
||||
#define VESAFB_VID_ADDR 0xF0000000
|
||||
|
||||
int vesafb_init(int width, int height, int bpp);
|
||||
void vesafb_clear();
|
||||
void vesafb_update_cursor(int position);
|
||||
void vesafb_draw_cursor(int position, int onoff);
|
||||
void vesafb_pset(int x, int y, int onoff);
|
||||
int vesafb_getWidth();
|
||||
int vesafb_getHeight();
|
||||
void vesafb_draw_char(int position, u16_t chr);
|
||||
int vesafb_draw(u16_t *buffer, int buff_len, int cursor_position);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
// FileSystem.cpp
|
||||
// Virtual file system subsystem for HOS
|
||||
// Author: Josh Holtrop
|
||||
// Date: 06/21/05
|
||||
// Modified: 06/21/05
|
||||
|
||||
#include "vfs.h"
|
||||
#include "FileSystem.h"
|
||||
|
||||
FileSystem::FileSystem() {}
|
||||
FileSystem::~FileSystem() {}
|
||||
u32_t FileSystem::totalBlocks() {return 0;}
|
||||
u32_t FileSystem::freeBlocks() {return 0;}
|
||||
u32_t FileSystem::totalInodes() {return 0;}
|
||||
u32_t FileSystem::freeInodes() {return 0;}
|
||||
u32_t FileSystem::getRootInodeNumber() {return 0;}
|
||||
|
||||
OpenDirectory *FileSystem::openDirectory(u32_t inum, int mode) {return NULL;}
|
||||
OpenFile *FileSystem::openFile(u32_t inum, int mode) {return NULL;}
|
||||
int FileSystem::stat(u32_t inum, vfs_stat_t *buf) {return -1;}
|
||||
int FileSystem::link_deref(u32_t inum, char *buf) {return -1;}
|
||||
@@ -0,0 +1,35 @@
|
||||
// FileSystem.h
|
||||
// Virtual file system subsystem for HOS
|
||||
// Author: Josh Holtrop
|
||||
// Date: 06/21/05
|
||||
// Modified: 06/21/05
|
||||
|
||||
#ifndef __HOS_FILESYSTEM__
|
||||
#define __HOS_FILESYSTEM__ __HOS_FILESYSTEM__
|
||||
|
||||
#include "hos_defines.h"
|
||||
#include "vfs.h"
|
||||
#include "OpenDirectory.h"
|
||||
#include "OpenFile.h"
|
||||
|
||||
class FileSystem
|
||||
{
|
||||
public:
|
||||
FileSystem();
|
||||
virtual ~FileSystem();
|
||||
|
||||
virtual u32_t totalBlocks(); /* 512 byte blocks */
|
||||
virtual u32_t freeBlocks();
|
||||
|
||||
virtual u32_t totalInodes();
|
||||
virtual u32_t freeInodes();
|
||||
|
||||
virtual u32_t getRootInodeNumber();
|
||||
|
||||
virtual OpenDirectory *openDirectory(u32_t inum, int mode);
|
||||
virtual OpenFile *openFile(u32_t inum, int mode);
|
||||
virtual int stat(u32_t inum, vfs_stat_t *buf);
|
||||
virtual int link_deref(u32_t inum, char *buf);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,28 +0,0 @@
|
||||
|
||||
// Mount.cpp
|
||||
// Author: Josh Holtrop
|
||||
// Date: 06/16/04
|
||||
// Modified: 06/16/04
|
||||
|
||||
#include "lang/string.h"
|
||||
#include "Mount.h"
|
||||
|
||||
Mount::Mount()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Mount::Mount(string dev, string mount)
|
||||
{
|
||||
mountPoint = mount;
|
||||
device = dev;
|
||||
}
|
||||
|
||||
|
||||
bool Mount::operator==(const Mount & second) const
|
||||
{
|
||||
/* Match *either* device or mountPoint to signal an invalid mount attempt */
|
||||
return (device == second.device || mountPoint == second.mountPoint);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
|
||||
// Mount.h
|
||||
// Author: Josh Holtrop
|
||||
// Date: 06/16/04
|
||||
// Modified: 06/16/04
|
||||
|
||||
#ifndef __HOS_MOUNT__
|
||||
#define __HOS_MOUNT__ __HOS_MOUNT__
|
||||
|
||||
#include "hos_defines.h"
|
||||
|
||||
class Mount
|
||||
{
|
||||
public:
|
||||
string mountPoint;
|
||||
string device;
|
||||
dword major;
|
||||
dword minor;
|
||||
|
||||
Mount();
|
||||
Mount(string dev, string mount);
|
||||
|
||||
bool operator==(const Mount & second) const;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// OpenDirectory.cpp
|
||||
// Author: Josh Holtrop
|
||||
// Date: 12/19/05
|
||||
|
||||
#include "vfs.h"
|
||||
#include "OpenDirectory.h"
|
||||
#include "lang/string.h"
|
||||
|
||||
OpenDirectory::OpenDirectory() {}
|
||||
OpenDirectory::~OpenDirectory() {}
|
||||
int OpenDirectory::seek(int pos, int mode) { return -1; }
|
||||
int OpenDirectory::read(vfs_dir_entry_t *ent) { return -1; }
|
||||
int OpenDirectory::create(char *name, int mode, u32_t permissions, u32_t dev)
|
||||
{ return -1; }
|
||||
int OpenDirectory::unlink(char *name) { return -1; }
|
||||
@@ -0,0 +1,23 @@
|
||||
// OpenDirectory.h
|
||||
// Author: Josh Holtrop
|
||||
// Date: 12/19/05
|
||||
|
||||
#ifndef __HOS_OPENDIRECTORY_H__
|
||||
#define __HOS_OPENDIRECTORY_H__ __HOS_OPENDIRECTORY_H__
|
||||
|
||||
#include "vfs.h"
|
||||
#include "lang/string.h"
|
||||
|
||||
class OpenDirectory
|
||||
{
|
||||
public:
|
||||
OpenDirectory();
|
||||
virtual ~OpenDirectory();
|
||||
virtual int seek(int pos, int mode);
|
||||
virtual int read(vfs_dir_entry_t *ent);
|
||||
virtual int create(char *name, int mode, u32_t permissions, u32_t dev);
|
||||
virtual int unlink(char *name);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// OpenFile.cpp
|
||||
// Author: Josh Holtrop
|
||||
// Date: 12/19/05
|
||||
|
||||
#include "OpenFile.h"
|
||||
|
||||
OpenFile::OpenFile() {}
|
||||
OpenFile::~OpenFile() {}
|
||||
int OpenFile::seek(int pos, int mode) { return -1; }
|
||||
int OpenFile::read() { return -1; }
|
||||
int OpenFile::read(void *buf, u32_t num) { return -1; }
|
||||
int OpenFile::write(int chr) { return -1; }
|
||||
int OpenFile::write(void *ptr, u32_t num) { return -1; }
|
||||
@@ -0,0 +1,23 @@
|
||||
// OpenFile.h
|
||||
// Author: Josh Holtrop
|
||||
// Date: 12/19/05
|
||||
|
||||
#ifndef __HOS_OPENFILE_H__
|
||||
#define __HOS_OPENFILE_H__ __HOS_OPENFILE_H__
|
||||
|
||||
#include "hos_defines.h"
|
||||
|
||||
class OpenFile
|
||||
{
|
||||
public:
|
||||
OpenFile();
|
||||
virtual ~OpenFile();
|
||||
virtual int seek(int pos, int mode);
|
||||
virtual int read();
|
||||
virtual int read(void *buf, u32_t num);
|
||||
virtual int write(int chr);
|
||||
virtual int write(void *ptr, u32_t num);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// VFSMount.cpp
|
||||
// Virtual file system subsystem for HOS
|
||||
// Author: Josh Holtrop
|
||||
// Date: 06/21/05
|
||||
// Modified: 06/21/05
|
||||
|
||||
extern "C" {
|
||||
#include "display/kout.h"
|
||||
}
|
||||
|
||||
#include "vfs.h"
|
||||
#include "VFSMount.h"
|
||||
#include "hos_defines.h"
|
||||
#include "devices.h"
|
||||
#include "lang/string.h"
|
||||
|
||||
VFSMount::VFSMount(device_t dev, string fsType, FileSystem *fs,
|
||||
string mountPoint,
|
||||
inode_num_t mountInode, inode_num_t thisInode)
|
||||
{
|
||||
myDev = dev;
|
||||
myFSType = fsType;
|
||||
myFS = fs;
|
||||
myMountPoint = mountPoint;
|
||||
myMountInode = mountInode;
|
||||
myThisInode = thisInode;
|
||||
}
|
||||
|
||||
VFSMount::~VFSMount()
|
||||
{
|
||||
if (umount_safe())
|
||||
kprintf("Filesystem uncleanly mounted from %s\n", myMountPoint.data());
|
||||
delete myFS;
|
||||
}
|
||||
|
||||
int VFSMount::umount_safe()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// VFSMount.h
|
||||
// Virtual file system subsystem for HOS
|
||||
// Author: Josh Holtrop
|
||||
// Date: 06/21/05
|
||||
// Modified: 06/21/05
|
||||
|
||||
#ifndef __HOS_VFSMOUNT__
|
||||
#define __HOS_VFSMOUNT__ __HOS_VFSMOUNT__
|
||||
|
||||
#include "lang/string.h"
|
||||
#include "devices.h"
|
||||
#include "FileSystem.h"
|
||||
|
||||
class VFSMount
|
||||
{
|
||||
public:
|
||||
device_t myDev;
|
||||
string myFSType;
|
||||
FileSystem *myFS;
|
||||
string myMountPoint;
|
||||
inode_num_t myMountInode;
|
||||
inode_num_t myThisInode;
|
||||
|
||||
VFSMount(device_t dev, string fsType, FileSystem *fs,
|
||||
string mountPoint,
|
||||
inode_num_t mountInode, inode_num_t thisInode);
|
||||
~VFSMount();
|
||||
int umount_safe();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,25 +0,0 @@
|
||||
|
||||
// devfs.cpp
|
||||
// device filesystem for HOS
|
||||
// Author: Josh Holtrop
|
||||
// Date: 06/03/04
|
||||
// Modified: 06/16/04
|
||||
|
||||
#include "devfs.h"
|
||||
#include "kio.h"
|
||||
#include "lang/string.h"
|
||||
#include "vfs.h"
|
||||
|
||||
void devfs_init(string mountPoint)
|
||||
{
|
||||
vfs_mount("devfs ", mountPoint);
|
||||
vfs_mount("testdev ", "/mnt/win");
|
||||
vfs_mount("/dev/hda6", "/scratch");
|
||||
vfs_mount("/dev/rd0 ", "/");
|
||||
vfs_mount("/dev/sda1", "/mnt/usb");
|
||||
vfs_mount("sysfs ", "/sys");
|
||||
vfs_mount("sysfs ", "/tmp");
|
||||
vfs_mount("otherfs ", "/sys");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
// devfs.h
|
||||
// device filesystem for HOS
|
||||
// Author: Josh Holtrop
|
||||
// Date: 06/03/04
|
||||
// Modified: 06/08/04
|
||||
|
||||
#ifndef __HOS_DEVFS__
|
||||
#define __HOS_DEVFS__ __HOS_DEVFS__
|
||||
|
||||
#include "lang/string.h"
|
||||
|
||||
void devfs_init(string mountPoint);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
// Ext2BlockCache.cpp
|
||||
// Author: Josh Holtrop
|
||||
// Date: 12/29/05
|
||||
// Modified: 12/29/05
|
||||
|
||||
#include "fs/vfs.h"
|
||||
#include "Ext2BlockCache.h"
|
||||
|
||||
Ext2BlockCache::Ext2BlockCache(Ext2fs *fs, u32_t inum, ext2_inode_t *inode)
|
||||
{
|
||||
myFS = fs;
|
||||
myInum = inum;
|
||||
myInodeDirty = 0;
|
||||
myInode = inode;
|
||||
myBlockSize = 1024 << fs->getSuper()->s_log_block_size;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
myCache[i] = new u8_t[myBlockSize];
|
||||
myCacheAddress[i] = 0;
|
||||
myCacheDirty[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Ext2BlockCache::~Ext2BlockCache()
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (myCacheDirty[i])
|
||||
myFS->writeBlock(myCacheAddress[i], myCache[i]);
|
||||
delete[] myCache[i];
|
||||
}
|
||||
if (myInodeDirty)
|
||||
myFS->writeInode(myInum, myInode);
|
||||
}
|
||||
|
||||
int Ext2BlockCache::readBlock(u32_t blockNum, void *buf)
|
||||
{
|
||||
u32_t fsblock = getFSBlock(blockNum, 0);
|
||||
if (fsblock == 0)
|
||||
return -1;
|
||||
return myFS->readBlock(fsblock, buf);
|
||||
}
|
||||
|
||||
int Ext2BlockCache::writeBlock(u32_t blockNum, void *buf)
|
||||
{
|
||||
u32_t fsblock = getFSBlock(blockNum, 1);
|
||||
if (fsblock == 0)
|
||||
return -1;
|
||||
return myFS->writeBlock(fsblock, buf);
|
||||
}
|
||||
|
||||
void Ext2BlockCache::setCache(u32_t level, u32_t fsblock)
|
||||
{
|
||||
if (myCacheAddress[level] == fsblock)
|
||||
return;
|
||||
if (myCacheDirty[level])
|
||||
myFS->writeBlock(myCacheAddress[level], myCache[level]);
|
||||
myCacheAddress[level] = fsblock;
|
||||
myCacheDirty[level] = 0;
|
||||
myFS->readBlock(fsblock, myCache[level]);
|
||||
}
|
||||
|
||||
u32_t Ext2BlockCache::getFSBlock(u32_t blockNum, int create)
|
||||
{
|
||||
if (blockNum < 12) /* direct pointer */
|
||||
{
|
||||
if (create && myInode->i_block[blockNum] == 0)
|
||||
{
|
||||
myInode->i_block[blockNum] = myFS->allocBlock();
|
||||
myInodeDirty = 1;
|
||||
}
|
||||
return myInode->i_block[blockNum];
|
||||
}
|
||||
blockNum -= 12;
|
||||
if (blockNum < myBlockSize) /* i_block[12] */
|
||||
{
|
||||
if (create && myInode->i_block[12] == 0)
|
||||
{
|
||||
myInode->i_block[12] = myFS->allocBlock();
|
||||
myInodeDirty = 1;
|
||||
}
|
||||
setCache(0, myInode->i_block[12]);
|
||||
/* blockNum indexes cache 0 */
|
||||
if (create && myCache[0][blockNum] == 0)
|
||||
{
|
||||
myCache[0][blockNum] = myFS->allocBlock();
|
||||
myCacheDirty[0] = 1;
|
||||
}
|
||||
return myCache[0][blockNum];
|
||||
}
|
||||
blockNum -= myBlockSize;
|
||||
if (blockNum < (myBlockSize * myBlockSize)) /* i_block[13] */
|
||||
{
|
||||
if (create && myInode->i_block[13] == 0)
|
||||
{
|
||||
myInode->i_block[13] = myFS->allocBlock();
|
||||
myInodeDirty = 1;
|
||||
}
|
||||
setCache(0, myInode->i_block[13]);
|
||||
/* blockNum / myBlockSize indexes cache 0 */
|
||||
if (create && myCache[0][blockNum / myBlockSize] == 0)
|
||||
{
|
||||
myCache[0][blockNum / myBlockSize] = myFS->allocBlock();
|
||||
myCacheDirty[0] = 1;
|
||||
}
|
||||
setCache(1, myCache[0][blockNum / myBlockSize]);
|
||||
/* blockNum % myBlockSize indexes cache 1 */
|
||||
if (create && myCache[1][blockNum % myBlockSize] == 0)
|
||||
{
|
||||
myCache[1][blockNum % myBlockSize] = myFS->allocBlock();
|
||||
myCacheDirty[1] = 1;
|
||||
}
|
||||
return myCache[1][blockNum % myBlockSize];
|
||||
}
|
||||
blockNum -= (myBlockSize * myBlockSize); /* i_block[14] */
|
||||
if (create && myInode->i_block[14] == 0)
|
||||
{
|
||||
myInode->i_block[14] = myFS->allocBlock();
|
||||
myInodeDirty = 1;
|
||||
}
|
||||
setCache(0, myInode->i_block[14]);
|
||||
/* blockNum / (myBlockSize^2) indexes cache 0 */
|
||||
if (create && myCache[0][blockNum / (myBlockSize * myBlockSize)] == 0)
|
||||
{
|
||||
myCache[0][blockNum / (myBlockSize * myBlockSize)] = myFS->allocBlock();
|
||||
myCacheDirty[0] = 1;
|
||||
}
|
||||
setCache(1, myCache[0][blockNum / (myBlockSize * myBlockSize)]);
|
||||
/* blockNum / myBlockSize indexes cache 1 */
|
||||
if (create && myCache[1][blockNum / myBlockSize] == 0)
|
||||
{
|
||||
myCache[1][blockNum / myBlockSize] = myFS->allocBlock();
|
||||
myCacheDirty[1] = 1;
|
||||
}
|
||||
setCache(2, myCache[1][blockNum / myBlockSize]);
|
||||
/* blockNum % myBlockSize indexes cache 2 */
|
||||
if (create && myCache[2][blockNum % myBlockSize] == 0)
|
||||
{
|
||||
myCache[2][blockNum % myBlockSize] = myFS->allocBlock();
|
||||
myCacheDirty[2] = 1;
|
||||
}
|
||||
return myCache[2][blockNum % myBlockSize];
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// Ext2BlockCache.h
|
||||
// Author: Josh Holtrop
|
||||
// Date: 12/29/05
|
||||
// Modified: 12/29/05
|
||||
|
||||
#ifndef __HOS_EXT2BLOCKCACHE_H__
|
||||
#define __HOS_EXT2BLOCKCACHE_H__ __HOS_EXT2BLOCKCACHE_H__
|
||||
|
||||
#include "fs/vfs.h"
|
||||
#include "ext2.h"
|
||||
|
||||
class Ext2BlockCache
|
||||
{
|
||||
protected:
|
||||
Ext2fs *myFS;
|
||||
u32_t myInum;
|
||||
ext2_inode_t *myInode;
|
||||
u32_t myBlockSize;
|
||||
u8_t *myCache[3];
|
||||
u8_t myCacheAddress[3];
|
||||
u8_t myCacheDirty[3];
|
||||
u32_t myInodeDirty;
|
||||
|
||||
void setCache(u32_t level, u32_t fsblock);
|
||||
u32_t getFSBlock(u32_t block, int create);
|
||||
|
||||
public:
|
||||
Ext2BlockCache(Ext2fs *fs, u32_t inum, ext2_inode_t *inode);
|
||||
~Ext2BlockCache();
|
||||
int readBlock(u32_t blockNum, void *buf);
|
||||
int writeBlock(u32_t blockNum, void *buf);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,238 @@
|
||||
// Ext2OpenDirectory.cpp
|
||||
// Author: Josh Holtrop
|
||||
// Date: 12/26/05
|
||||
// Modified: 12/26/05
|
||||
|
||||
extern "C" {
|
||||
#include "lang/lang.h"
|
||||
}
|
||||
|
||||
#include "fs/vfs.h"
|
||||
#include "Ext2OpenDirectory.h"
|
||||
#include "Ext2OpenFile.h"
|
||||
#include "ext2.h"
|
||||
|
||||
Ext2OpenDirectory::Ext2OpenDirectory(Ext2fs *fs, u32_t inum, int mode)
|
||||
{
|
||||
myPosition = 0;
|
||||
myFS = fs;
|
||||
myInum = inum;
|
||||
myMode = mode;
|
||||
myCache = new Ext2BlockCache(fs, inum, &myInode);
|
||||
fs->readInode(inum, &myInode);
|
||||
u32_t size = myInode.i_size;
|
||||
u32_t logBlockSize = fs->getSuper()->s_log_block_size;
|
||||
myBlockSize = 1024 << logBlockSize;
|
||||
if (size % myBlockSize)
|
||||
size += myBlockSize - (size % myBlockSize);
|
||||
myBlocks = size >> (10 + logBlockSize);
|
||||
myBuffer = new u8_t[size];
|
||||
if ((mode & VFS_MODE_RW_MASK) == VFS_MODE_READ)
|
||||
readDirectory();
|
||||
}
|
||||
|
||||
/* destroy an open ext2 directory object */
|
||||
Ext2OpenDirectory::~Ext2OpenDirectory()
|
||||
{
|
||||
delete myCache;
|
||||
delete[] myBuffer;
|
||||
}
|
||||
|
||||
void Ext2OpenDirectory::readDirectory()
|
||||
{
|
||||
/* read in the entire directory */
|
||||
for (u32_t i = 0; i < myBlocks; i++)
|
||||
myCache->readBlock(i, myBuffer + i * myBlockSize);
|
||||
}
|
||||
|
||||
/* seek absolute or relative, only positive direction */
|
||||
int Ext2OpenDirectory::seek(int pos, int mode)
|
||||
{
|
||||
if (mode == SEEK_ABSOLUTE)
|
||||
myPosition = 0;
|
||||
if (pos > 0)
|
||||
{
|
||||
while (myPosition < myInode.i_size)
|
||||
{
|
||||
ext2_dir_entry_t *de =
|
||||
(ext2_dir_entry_t *) (myBuffer + myPosition);
|
||||
myPosition += de->length;
|
||||
pos--;
|
||||
if (pos < 1)
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* read a directory entry from the directory */
|
||||
int Ext2OpenDirectory::read(vfs_dir_entry_t *ent)
|
||||
{
|
||||
if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_READ)
|
||||
return -1;
|
||||
if (myPosition >= myInode.i_size)
|
||||
return EOF;
|
||||
ext2_dir_entry_t *de = (ext2_dir_entry_t *) (myBuffer + myPosition);
|
||||
ent->inum = de->inode;
|
||||
memcpy(ent->name, de->name, de->name_length);
|
||||
ent->name[de->name_length] = 0;
|
||||
myPosition += de->length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Ext2OpenDirectory::create(char *name, int mode, u32_t permissions, u32_t dev)
|
||||
{
|
||||
if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_WRITE)
|
||||
return -1;
|
||||
readDirectory();
|
||||
myPosition = 0;
|
||||
u32_t name_length = strlen(name);
|
||||
while (myPosition < myInode.i_size)
|
||||
{
|
||||
ext2_dir_entry_t *de =
|
||||
(ext2_dir_entry_t *) (myBuffer + myPosition);
|
||||
if (name_length == de->name_length && !strncmp(name, de->name, name_length))
|
||||
return -2; /* entry already exists */
|
||||
myPosition += de->length;
|
||||
}
|
||||
u32_t newInode = myFS->allocInode();
|
||||
if (newInode == 0)
|
||||
return -3; /* no free inodes! */
|
||||
/* initialize the inode */
|
||||
ext2_inode_t in;
|
||||
memset(&in, 0, sizeof(ext2_inode_t));
|
||||
u32_t ext2_mode;
|
||||
switch(mode)
|
||||
{
|
||||
case VFS_FT_DIR: ext2_mode = EXT2_I_MODE_DIR; break;
|
||||
case VFS_FT_CHAR: ext2_mode = EXT2_I_MODE_CHAR;
|
||||
in.i_block[0] = dev; break;
|
||||
case VFS_FT_BLOCK: ext2_mode = EXT2_I_MODE_BLOCK;
|
||||
in.i_block[0] = dev; break;
|
||||
case VFS_FT_FIFO: ext2_mode = EXT2_I_MODE_FIFO; break;
|
||||
case VFS_FT_SOCK: ext2_mode = EXT2_I_MODE_SOCK; break;
|
||||
case VFS_FT_SYMLINK: ext2_mode = EXT2_I_MODE_SYM; break;
|
||||
case VFS_FT_FILE:
|
||||
default: ext2_mode = EXT2_I_MODE_FILE; break;
|
||||
}
|
||||
in.i_mode = ext2_mode | (permissions & EXT2_I_MODE_ATTR_MASK);
|
||||
in.i_links_count = 1;
|
||||
myFS->writeInode(newInode, &in);
|
||||
if (mode == VFS_FT_DIR)
|
||||
{
|
||||
if (myFS->getSuper()->s_free_blocks_count < 3)
|
||||
return -4; /* out of space on device */
|
||||
if (myFS->initializeDirectory(newInode, myInum))
|
||||
return -5; /* error initializing directory */
|
||||
myInode.i_links_count++;
|
||||
myFS->writeInode(myInum, &myInode);
|
||||
}
|
||||
u32_t entryLength = name_length + 8;
|
||||
if (entryLength & 0x3)
|
||||
entryLength = (entryLength + 4) & 0xFFFFFFFC; /* multiple of 4 bytes */
|
||||
myPosition = 0;
|
||||
for (;;)
|
||||
{
|
||||
ext2_dir_entry_t *de =
|
||||
(ext2_dir_entry_t *) (myBuffer + myPosition);
|
||||
u32_t thisEntryLength = de->name_length + 8;
|
||||
if (thisEntryLength & 0x3)
|
||||
thisEntryLength = (thisEntryLength + 4) & 0xFFFFFFFC;
|
||||
if (de->length - thisEntryLength >= entryLength)
|
||||
{
|
||||
/* There is room in this entry for the new one */
|
||||
u32_t newLength = de->length - thisEntryLength;
|
||||
de->length = thisEntryLength;
|
||||
u32_t firstPosition = myPosition;
|
||||
myPosition += de->length;
|
||||
de = (ext2_dir_entry_t *) (myBuffer + myPosition);
|
||||
de->length = newLength;
|
||||
de->name_length = name_length;
|
||||
de->inode = newInode;
|
||||
memcpy(de->name, name, name_length);
|
||||
writeInclusiveRange(firstPosition,
|
||||
myPosition + entryLength - 1);
|
||||
return 0;
|
||||
}
|
||||
if (myPosition + de->length >= myInode.i_size)
|
||||
{
|
||||
if (myFS->getSuper()->s_free_blocks_count < 2)
|
||||
{
|
||||
myFS->freeInode(newInode);
|
||||
return -4; /* out of space on device */
|
||||
}
|
||||
/* This is the last entry, we need to add a block */
|
||||
myBlocks++;
|
||||
u8_t *newBuffer = new u8_t[myBlockSize * myBlocks];
|
||||
memcpy(newBuffer, myBuffer, myBlockSize * (myBlocks - 1));
|
||||
delete[] myBuffer;
|
||||
myBuffer = newBuffer;
|
||||
de = (ext2_dir_entry_t *) (myBuffer + myPosition);
|
||||
u32_t thisEntryLength = de->name_length + 8;
|
||||
if (thisEntryLength & 0x3)
|
||||
thisEntryLength = (thisEntryLength + 4) & 0xFFFFFFFC;
|
||||
u32_t leftovers = de->length - thisEntryLength;
|
||||
de->length -= leftovers;
|
||||
u32_t firstPosition = myPosition;
|
||||
myPosition += thisEntryLength;
|
||||
de = (ext2_dir_entry_t *) (myBuffer + myPosition);
|
||||
de->length = myBlockSize + leftovers;
|
||||
de->name_length = name_length;
|
||||
de->inode = newInode;
|
||||
memcpy(de->name, name, name_length);
|
||||
writeInclusiveRange(firstPosition,
|
||||
myPosition + myBlockSize + leftovers - 1);
|
||||
myInode.i_size += myBlockSize;
|
||||
myFS->writeInode(myInum, &myInode);
|
||||
return 0;
|
||||
}
|
||||
myPosition += de->length;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Ext2OpenDirectory::writeInclusiveRange(u32_t first, u32_t last)
|
||||
{
|
||||
u32_t firstBlock = first / myBlockSize;
|
||||
u32_t lastBlock = last / myBlockSize;
|
||||
for (u32_t i = firstBlock; i <= lastBlock; i++)
|
||||
myCache->writeBlock(i, myBuffer + i * myBlockSize);
|
||||
}
|
||||
|
||||
int Ext2OpenDirectory::unlink(char *name)
|
||||
{
|
||||
if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_WRITE)
|
||||
return -1;
|
||||
readDirectory();
|
||||
myPosition = 0;
|
||||
u32_t lastPosition = 0;
|
||||
u32_t name_length = strlen(name);
|
||||
while (myPosition < myInode.i_size)
|
||||
{
|
||||
ext2_dir_entry_t *de =
|
||||
(ext2_dir_entry_t *) (myBuffer + myPosition);
|
||||
if (name_length == de->name_length && !strncmp(name, de->name, name_length))
|
||||
{
|
||||
ext2_inode_t inode;
|
||||
myFS->readInode(de->inode, &inode);
|
||||
if ((inode.i_mode & EXT2_I_MODE_TYPE_MASK) == EXT2_I_MODE_DIR)
|
||||
{
|
||||
if (myFS->attemptRemoveDir(de->inode))
|
||||
return -3; /* can't unlink non-empty directory */
|
||||
}
|
||||
/* found entry to unlink
|
||||
add the space to entry at lastPosition */
|
||||
myFS->unlink(de->inode);
|
||||
ext2_dir_entry_t *lde =
|
||||
(ext2_dir_entry_t *) (myBuffer + lastPosition);
|
||||
lde->length += de->length;
|
||||
writeInclusiveRange(lastPosition, lastPosition + 8);
|
||||
return 0;
|
||||
}
|
||||
lastPosition = myPosition;
|
||||
myPosition += de->length;
|
||||
}
|
||||
return -2; /* entry not found */
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
// Ext2OpenDirectory.h
|
||||
// Author: Josh Holtrop
|
||||
// Date: 12/26/05
|
||||
// Modified: 12/26/05
|
||||
|
||||
#ifndef __HOS_EXT2OPENDIRECTORY__
|
||||
#define __HOS_EXT2OPENDIRECTORY__ __HOS_EXT2OPENDIRECTORY__
|
||||
|
||||
#include "ext2.h"
|
||||
#include "Ext2BlockCache.h"
|
||||
|
||||
class Ext2OpenDirectory : public OpenDirectory
|
||||
{
|
||||
private:
|
||||
u32_t myPosition;
|
||||
Ext2fs *myFS;
|
||||
int myMode;
|
||||
u32_t myInum;
|
||||
u8_t *myBuffer;
|
||||
u32_t myBlocks;
|
||||
u32_t myBlockSize;
|
||||
Ext2BlockCache *myCache;
|
||||
ext2_inode_t myInode;
|
||||
|
||||
void readDirectory();
|
||||
void writeInclusiveRange(u32_t first, u32_t last);
|
||||
|
||||
public:
|
||||
Ext2OpenDirectory(Ext2fs *fs, u32_t inum, int mode);
|
||||
~Ext2OpenDirectory();
|
||||
int seek(int pos, int mode);
|
||||
int read(vfs_dir_entry_t *ent);
|
||||
int create(char *name, int mode, u32_t permissions, u32_t dev);
|
||||
int unlink(char *name);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,228 @@
|
||||
// Ext2OpenFile.cpp
|
||||
// Author: Josh Holtrop
|
||||
// Date: 12/26/05
|
||||
// Modified: 12/26/05
|
||||
|
||||
#include "Ext2OpenFile.h"
|
||||
|
||||
extern "C" {
|
||||
#include "lang/lang.h"
|
||||
#include "functions.h"
|
||||
}
|
||||
|
||||
lock_t Ext2OpenFileListLock;
|
||||
vector<Ext2OpenFileHandle> *Ext2OpenFileList = NULL;
|
||||
|
||||
/* make an Ext2OpenFile object
|
||||
* maintain vector of open files for notifying when one is truncated
|
||||
*/
|
||||
Ext2OpenFile::Ext2OpenFile(Ext2fs *fs, u32_t inum, int mode)
|
||||
{
|
||||
myMode = mode;
|
||||
myFS = fs;
|
||||
myInum = inum;
|
||||
myBeenTruncated = 0;
|
||||
myPosition = 0;
|
||||
myBlockSize = 1024 << fs->getSuper()->s_log_block_size;
|
||||
myBlockCache = new u8_t[myBlockSize];
|
||||
myBlockCacheBlock = 0;
|
||||
myBlockCacheStatus = 0; /* 0: invalid; 1: valid; 2: dirty */
|
||||
fs->readInode(inum, &myInode);
|
||||
myCache = new Ext2BlockCache(fs, inum, &myInode);
|
||||
lockit(&Ext2OpenFileListLock);
|
||||
if ((mode & VFS_MODE_RW_MASK) == VFS_MODE_WRITE)
|
||||
{
|
||||
if ((mode & VFS_MODE_WRITE_MASK) == VFS_MODE_TRUNCATE)
|
||||
{
|
||||
/* file opened for write/truncate
|
||||
* tell any open files that it's been truncated, then
|
||||
* tell ext2 filesystem to free its blocks
|
||||
*/
|
||||
u32_t size = Ext2OpenFileList->size();
|
||||
for (u32_t i = 0; i < size; i++)
|
||||
{
|
||||
if ((*Ext2OpenFileList)[i].inode == inum)
|
||||
(*Ext2OpenFileList)[i].ofile->notifyTruncated();
|
||||
}
|
||||
fs->truncateInode(inum);
|
||||
fs->readInode(inum, &myInode); /* re-read inode */
|
||||
}
|
||||
else
|
||||
myPosition = myInode.i_size;
|
||||
}
|
||||
if (Ext2OpenFileList == NULL)
|
||||
Ext2OpenFileList = new vector<Ext2OpenFileHandle>();
|
||||
/* add ourselves to the list */
|
||||
Ext2OpenFileHandle thisHandle = {inum, this};
|
||||
Ext2OpenFileList->add(thisHandle);
|
||||
unlock(&Ext2OpenFileListLock);
|
||||
}
|
||||
|
||||
/* destroy an Ext2OpenFile object */
|
||||
Ext2OpenFile::~Ext2OpenFile()
|
||||
{
|
||||
/* remove ourselves from the open file list */
|
||||
lockit(&Ext2OpenFileListLock);
|
||||
u32_t size = Ext2OpenFileList->size();
|
||||
for (u32_t i = 0; i < size; i++)
|
||||
{
|
||||
if ((*Ext2OpenFileList)[i].ofile == this)
|
||||
{
|
||||
Ext2OpenFileList->remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
unlock(&Ext2OpenFileListLock);
|
||||
|
||||
/* write back any open caches if in write mode */
|
||||
if ( !myBeenTruncated && ((myMode & VFS_MODE_RW_MASK) == VFS_MODE_WRITE) )
|
||||
{
|
||||
if (myBlockCacheStatus == 2)
|
||||
myCache->writeBlock(myBlockCacheBlock, myBlockCache);
|
||||
myFS->writeInode(myInum, &myInode);
|
||||
}
|
||||
/* free the memory we used */
|
||||
delete myCache;
|
||||
delete[] myBlockCache;
|
||||
}
|
||||
|
||||
/* seek to a certain position in the file (only for reading) */
|
||||
int Ext2OpenFile::seek(int pos, int mode)
|
||||
{
|
||||
if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_READ)
|
||||
return -1;
|
||||
if (mode == SEEK_ABSOLUTE)
|
||||
{
|
||||
if (pos < 0)
|
||||
return -2;
|
||||
if ((u32_t)pos >= myInode.i_size)
|
||||
return -3;
|
||||
myPosition = pos;
|
||||
return 0;
|
||||
}
|
||||
else if (mode == SEEK_RELATIVE)
|
||||
{
|
||||
if (myPosition + pos < 0)
|
||||
return -2;
|
||||
if (myPosition + pos >= myInode.i_size)
|
||||
return -3;
|
||||
myPosition += pos;
|
||||
return 0;
|
||||
}
|
||||
else if (mode == SEEK_END)
|
||||
{
|
||||
if (myInode.i_size + pos < 0)
|
||||
return -2;
|
||||
if (myInode.i_size + pos >= myInode.i_size)
|
||||
return -3;
|
||||
myPosition = myInode.i_size + pos;
|
||||
return 0;
|
||||
}
|
||||
return -4;
|
||||
}
|
||||
|
||||
/* read a byte from the current file position, return error code/EOF */
|
||||
int Ext2OpenFile::read()
|
||||
{
|
||||
if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_READ)
|
||||
return -1;
|
||||
if (myBeenTruncated || myPosition >= myInode.i_size)
|
||||
return EOF;
|
||||
u32_t theBlock = myPosition / myBlockSize;
|
||||
updateCache(theBlock);
|
||||
return myBlockCache[myPosition++ % myBlockSize];
|
||||
}
|
||||
|
||||
/* read num bytes from the current file position, put in buf
|
||||
* return: number of bytes read (>=0) or error code (<0)
|
||||
*/
|
||||
int Ext2OpenFile::read(void *buf, u32_t num)
|
||||
{
|
||||
if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_READ)
|
||||
return -1;
|
||||
if (myBeenTruncated || myPosition >= myInode.i_size)
|
||||
return EOF;
|
||||
if (myPosition + num > myInode.i_size)
|
||||
num = myInode.i_size - myPosition;
|
||||
u32_t bytesRead = 0;
|
||||
u32_t bytesIntoFirstBlock = myPosition % myBlockSize;
|
||||
if (bytesIntoFirstBlock)
|
||||
{
|
||||
updateCache(myPosition / myBlockSize);
|
||||
bytesRead = min(myBlockSize - bytesIntoFirstBlock, num);
|
||||
memcpy(buf, myBlockCache + bytesIntoFirstBlock, bytesRead);
|
||||
myPosition += bytesRead;
|
||||
}
|
||||
while (bytesRead < num)
|
||||
{
|
||||
updateCache(myPosition / myBlockSize);
|
||||
u32_t bytesToRead = min(num - bytesRead, myBlockSize);
|
||||
memcpy((u8_t *)buf + bytesRead, myBlockCache, bytesToRead);
|
||||
bytesRead += bytesToRead;
|
||||
myPosition += bytesToRead;
|
||||
}
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
/* write a byte to the current file position */
|
||||
int Ext2OpenFile::write(int chr)
|
||||
{
|
||||
if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_WRITE)
|
||||
return -1;
|
||||
if (myBeenTruncated)
|
||||
return EOF;
|
||||
u32_t theBlock = myPosition / myBlockSize;
|
||||
updateCache(theBlock);
|
||||
myBlockCache[myPosition++ % myBlockSize] = chr;
|
||||
myBlockCacheStatus = 2;
|
||||
myInode.i_size++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* write num bytes from buf to the current file position
|
||||
* return: number of bytes written (>=0) or error code (<0)
|
||||
*/
|
||||
int Ext2OpenFile::write(void *buf, u32_t num)
|
||||
{
|
||||
if (myBeenTruncated)
|
||||
return -1;
|
||||
if ((myMode & VFS_MODE_RW_MASK) != VFS_MODE_WRITE)
|
||||
return -2;
|
||||
u32_t bytesIntoFirstBlock = myPosition % myBlockSize;
|
||||
u32_t bytesWritten = 0;
|
||||
if (bytesIntoFirstBlock)
|
||||
{
|
||||
updateCache(myPosition / myBlockSize);
|
||||
bytesWritten = min(myBlockSize - bytesIntoFirstBlock, num);
|
||||
memcpy(myBlockCache + bytesIntoFirstBlock, buf, bytesWritten);
|
||||
myBlockCacheStatus = 2;
|
||||
myPosition += bytesWritten;
|
||||
}
|
||||
while (bytesWritten < num)
|
||||
{
|
||||
updateCache(myPosition / myBlockSize);
|
||||
u32_t bytesToWrite = min(num - bytesWritten, myBlockSize);
|
||||
memcpy(myBlockCache, (u8_t *)buf + bytesWritten, bytesToWrite);
|
||||
myBlockCacheStatus = 2;
|
||||
bytesWritten += bytesToWrite;
|
||||
myPosition += bytesToWrite;
|
||||
}
|
||||
myInode.i_size += bytesWritten;
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
void Ext2OpenFile::updateCache(u32_t blockNum)
|
||||
{
|
||||
if (myBlockCacheStatus && myBlockCacheBlock == blockNum)
|
||||
return;
|
||||
if (myBlockCacheStatus == 2)
|
||||
myCache->writeBlock(myBlockCacheBlock, myBlockCache);
|
||||
myCache->readBlock(blockNum, myBlockCache);
|
||||
myBlockCacheStatus = 1;
|
||||
myBlockCacheBlock = blockNum;
|
||||
}
|
||||
|
||||
void Ext2OpenFile::notifyTruncated()
|
||||
{
|
||||
myBeenTruncated = 1;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// Ext2OpenFile.h
|
||||
// Author: Josh Holtrop
|
||||
// Date: 12/26/05
|
||||
// Modified: 12/26/05
|
||||
|
||||
#ifndef __HOS_EXT2OPENFILE__
|
||||
#define __HOS_EXT2OPENFILE__ __HOS_EXT2OPENFILE__
|
||||
|
||||
#include "ext2.h"
|
||||
#include "fs/OpenFile.h"
|
||||
#include "Ext2BlockCache.h"
|
||||
|
||||
class Ext2OpenFile : public OpenFile
|
||||
{
|
||||
protected:
|
||||
Ext2fs *myFS;
|
||||
u32_t myInum;
|
||||
int myMode;
|
||||
int myBeenTruncated; /* set true when the file truncated */
|
||||
u32_t myPosition;
|
||||
u32_t myBlockSize;
|
||||
Ext2BlockCache *myCache;
|
||||
ext2_inode_t myInode;
|
||||
u8_t *myBlockCache;
|
||||
u32_t myBlockCacheBlock;
|
||||
int myBlockCacheStatus; /* 0: invalid; 1: valid; 2: dirty */
|
||||
|
||||
void updateCache(u32_t blockNum);
|
||||
|
||||
public:
|
||||
Ext2OpenFile(Ext2fs *fs, u32_t inum, int mode);
|
||||
~Ext2OpenFile();
|
||||
int seek(int pos, int mode);
|
||||
int read();
|
||||
int read(void *buf, u32_t num);
|
||||
int write(int chr);
|
||||
int write(void *buf, u32_t num);
|
||||
void notifyTruncated();
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32_t inode;
|
||||
Ext2OpenFile *ofile;
|
||||
} Ext2OpenFileHandle;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,599 @@
|
||||
// ext2.cpp
|
||||
// ext2 filesystem driver for HOS
|
||||
// Author: Josh Holtrop
|
||||
// Date: 05/10/05
|
||||
// Modified: 05/10/05
|
||||
|
||||
/* example ext2 filesystem block group structure containing superblock and group descriptors:
|
||||
* block offset description #blocks
|
||||
* ------------ ----------- -------
|
||||
* 0 superblock 1
|
||||
* 1 group descriptors gd_blocks = ceil(ceil[s_blocks_count / s_blocks_per_group] / (1024 >> [5 - s_log_block_size]))
|
||||
* gd_blocks+1 block bitmap block 1
|
||||
* gd_blocks+2 inode bitmap block 1
|
||||
* gd_blocks+3 inode table itblocks = ceil[s_inodes_per_group / (1024 >> [7 - s_log_block_size])]
|
||||
* gd_blocks+3+itblocks data blocks s_blocks_per_group - gd_blocks - itblocks - 3
|
||||
*/
|
||||
|
||||
|
||||
extern "C" {
|
||||
#include "display/kout.h"
|
||||
#include "mm/vmm.h"
|
||||
#include "lang/lang.h"
|
||||
}
|
||||
|
||||
#include "ext2.h"
|
||||
#include "Ext2OpenDirectory.h"
|
||||
#include "Ext2OpenFile.h"
|
||||
|
||||
/* initialize the ext2 filesystem driver */
|
||||
int ext2_init()
|
||||
{
|
||||
vfs_register("ext2", ext2__mount_func);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* a function to mount an ext2 filesystem and return a pointer to it */
|
||||
FileSystem *ext2__mount_func(device_t dev)
|
||||
{
|
||||
ext2_super_block_t *super =
|
||||
(ext2_super_block_t *) New(ext2_super_block_t);
|
||||
if ( (block_read(DEV_MAJOR(dev), DEV_MINOR(dev), 2, 2, super) < 1024)
|
||||
|| (super->s_magic != EXT2_MAGIC) )
|
||||
{
|
||||
kfree(super);
|
||||
return NULL;
|
||||
}
|
||||
Ext2fs *fs = new Ext2fs(super, dev);
|
||||
kfree(super);
|
||||
return fs;
|
||||
}
|
||||
|
||||
/* constructor for an actual ext2 filesystem object */
|
||||
Ext2fs::Ext2fs(ext2_super_block_t *super, device_t dev)
|
||||
{
|
||||
myDevice = dev;
|
||||
memcpy(&mySuper, super, sizeof(ext2_super_block_t));
|
||||
mySuperDirty = 0;
|
||||
myNumGroups = /* ceil[blocks_count / blocks_per_group] */
|
||||
(mySuper.s_blocks_count + mySuper.s_blocks_per_group - 1)
|
||||
/ mySuper.s_blocks_per_group;
|
||||
myGroupDescriptorsPerBlock = 1024 >> (5 - mySuper.s_log_block_size);
|
||||
myGroupDescriptorBlocks = /* ceil[num_groups / groupDescriptorsPerBlock] */
|
||||
(myNumGroups + myGroupDescriptorsPerBlock - 1)
|
||||
/ myGroupDescriptorsPerBlock;
|
||||
myInodesPerBlock = 1024 >> (7 - mySuper.s_log_block_size);
|
||||
myInodeTableBlocks = /* ceil[inodes_per_group / inodePerBlock] */
|
||||
(mySuper.s_inodes_per_group + myInodesPerBlock - 1)
|
||||
/ myInodesPerBlock;
|
||||
|
||||
/* test/debug code */
|
||||
/* kprintf("free blocks: %u\n", mySuper.s_free_blocks_count);
|
||||
OpenDirectory *od = openDirectory(2, VFS_MODE_WRITE);
|
||||
kprintf("TEST: %d\n", od->unlink("link"));
|
||||
kprintf("TEST: %d\n", od->create("test", VFS_FT_FILE, 0640, 0));
|
||||
kprintf("TEST: %d\n", od->create("Block File baby", VFS_FT_BLOCK, 0666, 5 << 8 | 3));
|
||||
kprintf("TEST: %d\n", od->unlink("bin"));
|
||||
kprintf("TEST: %d\n", od->create("Character-File", VFS_FT_CHAR, 0644, 130 << 8 | 42));
|
||||
kprintf("free blocks: %u\n", mySuper.s_free_blocks_count);
|
||||
kprintf("TEST: %d\n", od->create("a directory", VFS_FT_DIR, 0755, 0));
|
||||
kprintf("free blocks: %u\n", mySuper.s_free_blocks_count);
|
||||
delete od;
|
||||
*/
|
||||
}
|
||||
|
||||
/* this destructor destroys an ext2 filesystem that was mounted */
|
||||
Ext2fs::~Ext2fs()
|
||||
{
|
||||
if (mySuperDirty)
|
||||
block_write(DEV_MAJOR(myDevice), DEV_MINOR(myDevice), 2, 2, &mySuper);
|
||||
}
|
||||
|
||||
/* return the total number of 512-blocks on the filesystem */
|
||||
u32_t Ext2fs::totalBlocks()
|
||||
{
|
||||
return mySuper.s_blocks_count << (mySuper.s_log_block_size + 1);
|
||||
}
|
||||
|
||||
/* return the number of free 512-blocks on the filesystem */
|
||||
u32_t Ext2fs::freeBlocks()
|
||||
{
|
||||
return mySuper.s_free_blocks_count << (mySuper.s_log_block_size + 1);
|
||||
}
|
||||
|
||||
/* return the total number of inodes on the filesystem */
|
||||
u32_t Ext2fs::totalInodes()
|
||||
{
|
||||
return mySuper.s_inodes_count;
|
||||
}
|
||||
|
||||
/* return the free number of inodes on the filesystem */
|
||||
u32_t Ext2fs::freeInodes()
|
||||
{
|
||||
return mySuper.s_free_inodes_count;
|
||||
}
|
||||
|
||||
/* ext2 filesystems always have a root-directory inode number of 2 */
|
||||
u32_t Ext2fs::getRootInodeNumber()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* open a directory */
|
||||
OpenDirectory *Ext2fs::openDirectory(u32_t inum, int mode)
|
||||
{
|
||||
ext2_inode_t inode;
|
||||
readInode(inum, &inode);
|
||||
if ((inode.i_mode & EXT2_I_MODE_TYPE_MASK) == EXT2_I_MODE_DIR)
|
||||
return new Ext2OpenDirectory(this, inum, mode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* open a file */
|
||||
OpenFile *Ext2fs::openFile(u32_t inum, int mode)
|
||||
{
|
||||
ext2_inode_t inode;
|
||||
readInode(inum, &inode);
|
||||
if ((inode.i_mode & EXT2_I_MODE_TYPE_MASK) == EXT2_I_MODE_FILE)
|
||||
return new Ext2OpenFile(this, inum, mode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* stat an inode */
|
||||
int Ext2fs::stat(u32_t inum, vfs_stat_t *buf)
|
||||
{
|
||||
ext2_inode_t inode;
|
||||
if (readInode(inum, &inode))
|
||||
return -1;
|
||||
buf->dev = 0;
|
||||
switch(inode.i_mode & EXT2_I_MODE_TYPE_MASK)
|
||||
{
|
||||
case EXT2_I_MODE_FIFO: buf->type = VFS_FT_FIFO; break;
|
||||
case EXT2_I_MODE_CHAR: buf->type = VFS_FT_CHAR;
|
||||
buf->dev = inode.i_block[0]; break;
|
||||
case EXT2_I_MODE_DIR: buf->type = VFS_FT_DIR; break;
|
||||
case EXT2_I_MODE_BLOCK: buf->type = VFS_FT_BLOCK;
|
||||
buf->dev = inode.i_block[0]; break;
|
||||
case EXT2_I_MODE_FILE: buf->type = VFS_FT_FILE; break;
|
||||
case EXT2_I_MODE_SYM: buf->type = VFS_FT_SYMLINK; break;
|
||||
case EXT2_I_MODE_SOCK: buf->type = VFS_FT_SOCK; break;
|
||||
default: buf->type = VFS_FT_UNKNOWN;
|
||||
}
|
||||
buf->size = inode.i_size;
|
||||
buf->inode = inum;
|
||||
buf->permissions = inode.i_mode & EXT2_I_MODE_ATTR_MASK;
|
||||
buf->uid = inode.i_uid;
|
||||
buf->gid = inode.i_gid;
|
||||
buf->atime = inode.i_atime;
|
||||
buf->mtime = inode.i_mtime;
|
||||
buf->ctime = inode.i_ctime;
|
||||
buf->links = inode.i_links_count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* dereference a symbolink link */
|
||||
int Ext2fs::link_deref(u32_t inum, char *buf)
|
||||
{
|
||||
ext2_inode_t inode;
|
||||
if (readInode(inum, &inode))
|
||||
return -1; /* Couldn't read inode */
|
||||
if ((inode.i_mode & EXT2_I_MODE_TYPE_MASK) != EXT2_I_MODE_SYM)
|
||||
return -2;
|
||||
if (inode.i_size > VFS_MAX_PATH_LENGTH)
|
||||
return -3;
|
||||
if (inode.i_size < 61)
|
||||
{
|
||||
memcpy(buf, inode.i_block, inode.i_size);
|
||||
buf[inode.i_size] = 0;
|
||||
return 0;
|
||||
}
|
||||
char *block = new char[1024 << mySuper.s_log_block_size];
|
||||
readBlock(inode.i_block[0], block);
|
||||
memcpy(buf, block, inode.i_size);
|
||||
buf[inode.i_size] = 0;
|
||||
delete[] block;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*************************** internal functions ***************************/
|
||||
|
||||
/* read an inode from the disk into memory */
|
||||
int Ext2fs::readInode(u32_t inum, ext2_inode_t *buf)
|
||||
{
|
||||
if (inodeStatus(inum) != 1)
|
||||
return -1;
|
||||
inum--; /* turn inode number into a 0-based index */
|
||||
u32_t group = inum / mySuper.s_inodes_per_group;
|
||||
u32_t index = inum % mySuper.s_inodes_per_group;
|
||||
ext2_group_desc_t group_desc;
|
||||
readGroupDescriptor(group, &group_desc);
|
||||
ext2_inode_t *inode_block = new ext2_inode_t[8 << mySuper.s_log_block_size];
|
||||
readBlock(group_desc.bg_inode_table +
|
||||
(index >> (3 + mySuper.s_log_block_size)), inode_block);
|
||||
u32_t inode_block_index = index % (8 << mySuper.s_log_block_size);
|
||||
memcpy(buf, inode_block + inode_block_index, sizeof(ext2_inode_t));
|
||||
delete[] inode_block;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* write an inode from memory onto the disk */
|
||||
int Ext2fs::writeInode(u32_t inum, ext2_inode_t *buf)
|
||||
{
|
||||
if (inodeStatus(inum) != 1)
|
||||
return -1;
|
||||
inum--; /* turn inode number into a 0-based index */
|
||||
u32_t group = inum / mySuper.s_inodes_per_group;
|
||||
u32_t index = inum % mySuper.s_inodes_per_group;
|
||||
ext2_group_desc_t group_desc;
|
||||
readGroupDescriptor(group, &group_desc);
|
||||
ext2_inode_t *inode_block = new ext2_inode_t[8 << mySuper.s_log_block_size];
|
||||
u32_t block_num = group_desc.bg_inode_table +
|
||||
(index >> (3 + mySuper.s_log_block_size));
|
||||
readBlock(block_num, inode_block);
|
||||
u32_t inode_block_index = index % (8 << mySuper.s_log_block_size);
|
||||
memcpy(inode_block + inode_block_index, buf, sizeof(ext2_inode_t));
|
||||
writeBlock(block_num, inode_block);
|
||||
delete[] inode_block;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* read the group descriptor for a given group number */
|
||||
int Ext2fs::readGroupDescriptor(u32_t group, ext2_group_desc_t *buf)
|
||||
{
|
||||
if (group >= myNumGroups)
|
||||
return -1;
|
||||
ext2_group_desc_t *gd_block =
|
||||
new ext2_group_desc_t[myGroupDescriptorsPerBlock];
|
||||
readBlock(mySuper.s_first_data_block + 1 +
|
||||
(group / myGroupDescriptorsPerBlock), gd_block);
|
||||
memcpy(buf, gd_block + (group % myGroupDescriptorsPerBlock),
|
||||
sizeof(ext2_group_desc_t));
|
||||
delete[] gd_block;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* write the group descriptor for a given group number */
|
||||
int Ext2fs::writeGroupDescriptor(u32_t group, ext2_group_desc_t *buf)
|
||||
{
|
||||
if (group >= myNumGroups)
|
||||
return -1;
|
||||
ext2_group_desc_t *gd_block =
|
||||
new ext2_group_desc_t[myGroupDescriptorsPerBlock];
|
||||
u32_t block_num = mySuper.s_first_data_block + 1 +
|
||||
(group / myGroupDescriptorsPerBlock);
|
||||
readBlock(block_num, gd_block);
|
||||
memcpy(gd_block + (group % myGroupDescriptorsPerBlock), buf,
|
||||
sizeof(ext2_group_desc_t));
|
||||
writeBlock(block_num, gd_block);
|
||||
delete[] gd_block;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* read a data block from the block device */
|
||||
int Ext2fs::readBlock(u32_t blockNum, void *buf)
|
||||
{
|
||||
return block_read(DEV_MAJOR(myDevice), DEV_MINOR(myDevice),
|
||||
blockNum << (mySuper.s_log_block_size + 1),
|
||||
2 << mySuper.s_log_block_size,
|
||||
buf);
|
||||
}
|
||||
|
||||
/* write a data block to the block device */
|
||||
int Ext2fs::writeBlock(u32_t blockNum, void *buf)
|
||||
{
|
||||
return block_write(DEV_MAJOR(myDevice), DEV_MINOR(myDevice),
|
||||
blockNum << (mySuper.s_log_block_size + 1),
|
||||
2 << mySuper.s_log_block_size,
|
||||
buf);
|
||||
}
|
||||
|
||||
/* check the status of an inode (1-based inode number)
|
||||
* -1: invalid inode number
|
||||
* 0: free inode
|
||||
* 1: allocated (used) inode
|
||||
*/
|
||||
int Ext2fs::inodeStatus(u32_t inum)
|
||||
{
|
||||
if (inum < 1 || inum > mySuper.s_inodes_count)
|
||||
return -1; /* invalid inode number */
|
||||
inum--; /* turn inode number into a 0-based index */
|
||||
u32_t group = inum / mySuper.s_inodes_per_group;
|
||||
u32_t index = inum % mySuper.s_inodes_per_group;
|
||||
ext2_group_desc_t group_desc;
|
||||
readGroupDescriptor(group, &group_desc);
|
||||
u8_t *bitmap_block = new u8_t[1024 << mySuper.s_log_block_size];
|
||||
readBlock(group_desc.bg_inode_bitmap +
|
||||
(index >> (13 + mySuper.s_log_block_size)), bitmap_block);
|
||||
u32_t bitmap_index = index % (8192 << mySuper.s_log_block_size);
|
||||
int inode_status = (bitmap_block[bitmap_index >> 3] >> (bitmap_index & 0x7)) & 1;
|
||||
delete[] bitmap_block;
|
||||
return inode_status;
|
||||
}
|
||||
|
||||
/* check the status of a block
|
||||
* -1: invalid block number
|
||||
* 0: free block
|
||||
* 1: allocated (used) block
|
||||
*/
|
||||
int Ext2fs::blockStatus(u32_t bnum)
|
||||
{
|
||||
if (bnum < mySuper.s_first_data_block)
|
||||
return 1;
|
||||
if (bnum >= mySuper.s_blocks_count)
|
||||
return -1; /* invalid inode number */
|
||||
bnum -= mySuper.s_first_data_block;
|
||||
u32_t group = bnum / mySuper.s_blocks_per_group;
|
||||
u32_t index = bnum % mySuper.s_blocks_per_group;
|
||||
ext2_group_desc_t group_desc;
|
||||
readGroupDescriptor(group, &group_desc);
|
||||
u8_t *bitmap_block = new u8_t[1024 << mySuper.s_log_block_size];
|
||||
readBlock(group_desc.bg_block_bitmap +
|
||||
(index >> (13 + mySuper.s_log_block_size)), bitmap_block);
|
||||
u32_t bitmap_index = index % (8192 << mySuper.s_log_block_size);
|
||||
int block_status = (bitmap_block[bitmap_index >> 3] >> (bitmap_index & 0x7)) & 1;
|
||||
delete[] bitmap_block;
|
||||
return block_status;
|
||||
}
|
||||
|
||||
/* allocate an inode, return number (0 on failure) */
|
||||
u32_t Ext2fs::allocInode()
|
||||
{
|
||||
ext2_group_desc_t gd;
|
||||
for (unsigned int bg = 0; bg < myNumGroups; bg++)
|
||||
{
|
||||
readGroupDescriptor(bg, &gd);
|
||||
if (gd.bg_free_inodes_count)
|
||||
{
|
||||
u32_t index = allocFromBitmap(gd.bg_inode_bitmap,
|
||||
mySuper.s_inodes_per_group);
|
||||
if (index == 0xFFFFFFFF)
|
||||
return 0;
|
||||
gd.bg_free_inodes_count--;
|
||||
writeGroupDescriptor(bg, &gd);
|
||||
mySuper.s_free_inodes_count--;
|
||||
mySuperDirty = 1;
|
||||
return (bg * mySuper.s_inodes_per_group) + index + 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* allocate a block, return number (0 on failure) */
|
||||
u32_t Ext2fs::allocBlock()
|
||||
{
|
||||
ext2_group_desc_t gd;
|
||||
for (unsigned int bg = 0; bg < myNumGroups; bg++)
|
||||
{
|
||||
readGroupDescriptor(bg, &gd);
|
||||
if (gd.bg_free_blocks_count)
|
||||
{
|
||||
u32_t index = allocFromBitmap(gd.bg_block_bitmap,
|
||||
mySuper.s_blocks_per_group);
|
||||
if (index == 0xFFFFFFFF)
|
||||
return 0;
|
||||
gd.bg_free_blocks_count--;
|
||||
writeGroupDescriptor(bg, &gd);
|
||||
mySuper.s_free_blocks_count--;
|
||||
mySuperDirty = 1;
|
||||
return (bg * mySuper.s_blocks_per_group) + index +
|
||||
mySuper.s_first_data_block;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* free an inode, return error code */
|
||||
int Ext2fs::freeInode(u32_t inum)
|
||||
{
|
||||
if (inum < 11 || inum > mySuper.s_inodes_count)
|
||||
return -1;
|
||||
if (inodeStatus(inum) != 1)
|
||||
return -2;
|
||||
inum--; /* now 0-based */
|
||||
ext2_group_desc_t gd;
|
||||
u32_t group_num = inum / mySuper.s_inodes_per_group;
|
||||
readGroupDescriptor(group_num, &gd);
|
||||
freeFromBitmap(gd.bg_inode_bitmap, inum % mySuper.s_inodes_per_group);
|
||||
gd.bg_free_inodes_count++;
|
||||
mySuper.s_free_inodes_count++;
|
||||
mySuperDirty = 1;
|
||||
writeGroupDescriptor(group_num, &gd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* free a block, return error code */
|
||||
int Ext2fs::freeBlock(u32_t bnum)
|
||||
{
|
||||
if (bnum < mySuper.s_first_data_block || bnum >= mySuper.s_blocks_count)
|
||||
return -1;
|
||||
if (blockStatus(bnum) != 1)
|
||||
return -2;
|
||||
bnum -= mySuper.s_first_data_block; /* now 0-based */
|
||||
ext2_group_desc_t gd;
|
||||
u32_t group_num = bnum / mySuper.s_blocks_per_group;
|
||||
readGroupDescriptor(group_num, &gd);
|
||||
freeFromBitmap(gd.bg_block_bitmap, bnum % mySuper.s_blocks_per_group);
|
||||
gd.bg_free_blocks_count++;
|
||||
mySuper.s_free_blocks_count++;
|
||||
mySuperDirty = 1;
|
||||
writeGroupDescriptor(group_num, &gd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* allocate a node from a bitmap, return the index, 0xFFFFFFFF on failure */
|
||||
u32_t Ext2fs::allocFromBitmap(u32_t blockNum, u32_t maxBits)
|
||||
{
|
||||
u8_t *block = new u8_t[1024 << mySuper.s_log_block_size];
|
||||
u8_t *blockPtr = block;
|
||||
u32_t maxBytes = (maxBits + 7) >> 3;
|
||||
readBlock(blockNum, block);
|
||||
for (u32_t idx = 0; idx < maxBytes; idx++)
|
||||
{
|
||||
if (*blockPtr != 0xFF)
|
||||
{
|
||||
for (u32_t bit = 0; bit < 8; bit++)
|
||||
{
|
||||
if ( !((*blockPtr) & (1 << bit)) )
|
||||
{
|
||||
u32_t nodeIndex = (idx << 3) + bit;
|
||||
if (nodeIndex < maxBits)
|
||||
{
|
||||
*blockPtr |= (1 << bit);
|
||||
writeBlock(blockNum, block);
|
||||
return nodeIndex;
|
||||
}
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
blockPtr++;
|
||||
}
|
||||
delete[] block;
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
/* free a node from a bitmap */
|
||||
void Ext2fs::freeFromBitmap(u32_t blockNum, u32_t node)
|
||||
{
|
||||
u8_t *block = new u8_t[1024 << mySuper.s_log_block_size];
|
||||
readBlock(blockNum, block);
|
||||
u8_t *blockPtr = block + (node >> 3);
|
||||
*blockPtr &= ((1 << (node & 0x7)) ^ 0xFF);
|
||||
writeBlock(blockNum, block);
|
||||
delete[] block;
|
||||
}
|
||||
|
||||
/* unlink an inode:
|
||||
* decrement i_links_count
|
||||
* if it is zero, free the inode
|
||||
* if not, write the inode back
|
||||
*/
|
||||
void Ext2fs::unlink(u32_t inum)
|
||||
{
|
||||
ext2_inode_t inode;
|
||||
readInode(inum, &inode);
|
||||
inode.i_links_count--;
|
||||
if (inode.i_links_count)
|
||||
{
|
||||
writeInode(inum, &inode);
|
||||
return;
|
||||
}
|
||||
truncateInode(inum);
|
||||
freeInode(inum);
|
||||
}
|
||||
|
||||
int Ext2fs::attemptRemoveDir(u32_t inum)
|
||||
{
|
||||
vfs_dir_entry_t dentry, dentry2;
|
||||
OpenDirectory *od = openDirectory(inum, VFS_MODE_READ);
|
||||
if (od->read(&dentry))
|
||||
{
|
||||
delete od;
|
||||
return -1;
|
||||
}
|
||||
if (od->read(&dentry2))
|
||||
{
|
||||
delete od;
|
||||
return -1;
|
||||
}
|
||||
if (!od->read(&dentry))
|
||||
{
|
||||
delete od;
|
||||
return -1;
|
||||
}
|
||||
delete od;
|
||||
unlink(dentry.inum);
|
||||
unlink(dentry2.inum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Ext2fs::truncateInode(u32_t inum)
|
||||
{
|
||||
ext2_inode_t inode;
|
||||
readInode(inum, &inode);
|
||||
if ( ((inode.i_mode & EXT2_I_MODE_TYPE_MASK) != EXT2_I_MODE_DIR) &&
|
||||
((inode.i_mode & EXT2_I_MODE_TYPE_MASK) != EXT2_I_MODE_FILE) )
|
||||
return;
|
||||
for (int i = 0; i < 12; i++)
|
||||
if (inode.i_block[i])
|
||||
freeBlock(inode.i_block[i]);
|
||||
u32_t entriesPerBlock = 256 << mySuper.s_log_block_size;
|
||||
u32_t *block = new u32_t[entriesPerBlock];
|
||||
if (inode.i_block[12])
|
||||
{
|
||||
readBlock(inode.i_block[12], block);
|
||||
for (u32_t i = 0; i < entriesPerBlock; i++)
|
||||
if (block[i])
|
||||
freeBlock(block[i]);
|
||||
freeBlock(inode.i_block[12]);
|
||||
}
|
||||
if (inode.i_block[13])
|
||||
{
|
||||
readBlock(inode.i_block[13], block);
|
||||
u32_t *block2 = new u32_t[entriesPerBlock];
|
||||
for (u32_t i = 0; i < entriesPerBlock; i++)
|
||||
if (block[i])
|
||||
{
|
||||
readBlock(block[i], block2);
|
||||
for (u32_t j = 0; j < entriesPerBlock; j++)
|
||||
if (block2[j])
|
||||
freeBlock(block2[j]);
|
||||
freeBlock(block[i]);
|
||||
}
|
||||
delete[] block2;
|
||||
freeBlock(inode.i_block[13]);
|
||||
}
|
||||
if (inode.i_block[14])
|
||||
{
|
||||
readBlock(inode.i_block[14], block);
|
||||
u32_t *block2 = new u32_t[entriesPerBlock];
|
||||
u32_t *block3 = new u32_t[entriesPerBlock];
|
||||
for (u32_t i = 0; i < entriesPerBlock; i++)
|
||||
if (block[i])
|
||||
{
|
||||
readBlock(block[i], block2);
|
||||
for (u32_t j = 0; j < entriesPerBlock; j++)
|
||||
if (block2[j])
|
||||
{
|
||||
readBlock(block2[j], block3);
|
||||
for (u32_t k = 0; k < entriesPerBlock; k++)
|
||||
if (block3[k])
|
||||
freeBlock(block3[k]);
|
||||
freeBlock(block2[j]);
|
||||
}
|
||||
freeBlock(block[i]);
|
||||
}
|
||||
delete[] block2;
|
||||
delete[] block3;
|
||||
freeBlock(inode.i_block[14]);
|
||||
}
|
||||
delete[] block;
|
||||
for (int i = 0; i < 15; i++)
|
||||
inode.i_block[i] = 0;
|
||||
inode.i_size = 0;
|
||||
inode.i_blocks = 0;
|
||||
writeInode(inum, &inode);
|
||||
}
|
||||
|
||||
int Ext2fs::initializeDirectory(u32_t inum, u32_t parent)
|
||||
{
|
||||
ext2_inode_t inode;
|
||||
readInode(inum, &inode);
|
||||
if ( !(inode.i_block[0] = allocBlock()) )
|
||||
return -1;
|
||||
u8_t *buffer = new u8_t[1024 << mySuper.s_log_block_size];
|
||||
ext2_dir_entry_t *de = (ext2_dir_entry_t *) buffer;
|
||||
de->name_length = 1;
|
||||
de->length = 12;
|
||||
de->inode = inum;
|
||||
memcpy(de->name, ".", 1);
|
||||
de = (ext2_dir_entry_t *) (buffer + 12);
|
||||
de->name_length = 2;
|
||||
de->length = (1024 << mySuper.s_log_block_size) - 12;
|
||||
de->inode = parent;
|
||||
memcpy(de->name, "..", 2);
|
||||
delete[] buffer;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
// ext2.h
|
||||
// ext2 filesystem driver for HOS
|
||||
// Author: Josh Holtrop
|
||||
// Date: 05/10/05
|
||||
// Modified: 05/23/05
|
||||
|
||||
#ifndef __HOS_EXT2_H__
|
||||
#define __HOS_EXT2_H__ __HOS_EXT2_H__
|
||||
|
||||
#define EXT2_MAGIC 0xEF53
|
||||
#define EXT2_NAME_LEN 255
|
||||
|
||||
#define EXT2_I_MODE_ATTR_MASK 0x0FFF
|
||||
#define EXT2_I_MODE_OX 0x0001
|
||||
#define EXT2_I_MODE_OW 0x0002
|
||||
#define EXT2_I_MODE_OR 0x0004
|
||||
#define EXT2_I_MODE_GX 0x0008
|
||||
#define EXT2_I_MODE_GW 0x0010
|
||||
#define EXT2_I_MODE_GR 0x0020
|
||||
#define EXT2_I_MODE_UX 0x0040
|
||||
#define EXT2_I_MODE_UW 0x0080
|
||||
#define EXT2_I_MODE_UR 0x0100
|
||||
#define EXT2_I_MODE_STICKY 0x0200
|
||||
#define EXT2_I_MODE_SGID 0x0400
|
||||
#define EXT2_I_MODE_SUID 0x0800
|
||||
|
||||
#define EXT2_I_MODE_TYPE_MASK 0xF000
|
||||
#define EXT2_I_MODE_FIFO 0x1000
|
||||
#define EXT2_I_MODE_CHAR 0x2000
|
||||
#define EXT2_I_MODE_DIR 0x4000
|
||||
#define EXT2_I_MODE_BLOCK 0x6000
|
||||
#define EXT2_I_MODE_FILE 0x8000
|
||||
#define EXT2_I_MODE_SYM 0xA000
|
||||
#define EXT2_I_MODE_SOCK 0xC000
|
||||
|
||||
#define EXT2_I_FLAGS_SEC_DEL 0x01
|
||||
#define EXT2_I_FLAGS_UNDELETE 0x02
|
||||
#define EXT2_I_FLAGS_COMPRESS 0x04
|
||||
#define EXT2_I_FLAGS_SYNC 0x08
|
||||
#define EXT2_I_FLAGS_IMMUTABLE 0x10
|
||||
#define EXT2_I_FLAGS_APPEND 0x20
|
||||
#define EXT2_I_FLAGS_NODUMP 0x40
|
||||
|
||||
/* ext2 standard inode numbers */
|
||||
#define EXT2_INODE_BAD_BLOCKS 1
|
||||
#define EXT2_INODE_ROOT 2
|
||||
#define EXT2_INODE_ACL_INDEX 3
|
||||
#define EXT2_INODE_ACL_DATA 4
|
||||
#define EXT2_INODE_BOOT_LOADER 5
|
||||
#define EXT2_INODE_UNDELETE_DIR 6
|
||||
#define EXT2_INODE_AVAIL 11
|
||||
|
||||
/* The directory entry file type field values */
|
||||
#define EXT2_FT_UNKNOWN 0
|
||||
#define EXT2_FT_FILE 1
|
||||
#define EXT2_FT_DIR 2
|
||||
#define EXT2_FT_CHAR 3
|
||||
#define EXT2_FT_BLOCK 4
|
||||
#define EXT2_FT_FIFO 5
|
||||
#define EXT2_FT_SOCK 6
|
||||
#define EXT2_FT_SYMLINK 7
|
||||
#define EXT2_FT_MAX 8
|
||||
|
||||
#include "fs/vfs.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32_t s_inodes_count; /* Inodes count */
|
||||
u32_t s_blocks_count; /* Blocks count */
|
||||
u32_t s_r_blocks_count; /* Reserved blocks count */
|
||||
u32_t s_free_blocks_count; /* Free blocks count */
|
||||
u32_t s_free_inodes_count; /* Free inodes count */
|
||||
u32_t s_first_data_block; /* First Data Block */
|
||||
u32_t s_log_block_size; /* Block size: 0->1024, 1->2048, 2->4096 */
|
||||
int s_log_frag_size; /* Fragment size */
|
||||
u32_t s_blocks_per_group; /* # Blocks per group */
|
||||
u32_t s_frags_per_group; /* # Fragments per group */
|
||||
u32_t s_inodes_per_group; /* # Inodes per group */
|
||||
u32_t s_mtime; /* Mount time */
|
||||
u32_t s_wtime; /* Write time */
|
||||
u16_t s_mnt_count; /* Mount count */
|
||||
short s_max_mnt_count; /* Maximal mount count */
|
||||
u16_t s_magic; /* Magic signature */
|
||||
u16_t s_state; /* File system state */
|
||||
u16_t s_errors; /* Behaviour when detecting errors */
|
||||
u16_t s_minor_rev_level; /* minor revision level */
|
||||
u32_t s_lastcheck; /* time of last check */
|
||||
u32_t s_checkinterval; /* max. time between checks */
|
||||
u32_t s_creator_os; /* OS */
|
||||
u32_t s_rev_level; /* Revision level */
|
||||
u16_t s_def_resuid; /* Default uid for reserved blocks */
|
||||
u16_t s_def_resgid; /* Default gid for reserved blocks */
|
||||
|
||||
u32_t s_reserved[235];
|
||||
} ext2_super_block_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32_t bg_block_bitmap; // Blocks bitmap block
|
||||
u32_t bg_inode_bitmap; // Inode bitmap block
|
||||
u32_t bg_inode_table; // Inode table block
|
||||
u16_t bg_free_blocks_count; // Free blocks count
|
||||
u16_t bg_free_inodes_count; // Free Inodes count
|
||||
u16_t bg_used_dirs_count; // Directories count
|
||||
u16_t bg_pad1;
|
||||
u32_t bg_reserved[3];
|
||||
} ext2_group_desc_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u16_t i_mode; // File mode
|
||||
u16_t i_uid; // Owner UID
|
||||
u32_t i_size; // Size in bytes
|
||||
u32_t i_atime; // Access time
|
||||
u32_t i_ctime; // Creation time
|
||||
u32_t i_mtime; // Modification time
|
||||
u32_t i_dtime; // Deletion time
|
||||
u16_t i_gid; // Group ID
|
||||
u16_t i_links_count; // Links count
|
||||
u32_t i_blocks; // Disk Blocks count (512)
|
||||
u32_t i_flags; // File flags
|
||||
u32_t i_reserved1;
|
||||
u32_t i_block[15]; // Pointers to blocks (12 direct, single, double, triple indirect)
|
||||
u32_t i_version; // File version (for NFS)
|
||||
u32_t i_file_acl; // File ACL
|
||||
u32_t i_dir_acl; // Directory ACL
|
||||
u32_t i_faddr; // Fragment address
|
||||
u8_t i_frag; // Fragment number
|
||||
u8_t i_fsize; // Fragment size
|
||||
u16_t i_pad1;
|
||||
u32_t i_reserved2[2];
|
||||
} ext2_inode_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32_t inode; // inode number
|
||||
u16_t length; // directory entry length
|
||||
u8_t name_length; // name length
|
||||
u8_t file_type; // File type (used???)
|
||||
char name[EXT2_NAME_LEN];
|
||||
} ext2_dir_entry_t;
|
||||
|
||||
#ifdef _HOS_CPP_
|
||||
|
||||
int ext2_init();
|
||||
FileSystem *ext2__mount_func(device_t dev);
|
||||
|
||||
class Ext2fs : public FileSystem
|
||||
{
|
||||
protected:
|
||||
/* my data members */
|
||||
device_t myDevice;
|
||||
int mySuperDirty;
|
||||
ext2_super_block_t mySuper;
|
||||
u32_t myNumGroups;
|
||||
u32_t myGroupDescriptorBlocks;
|
||||
u32_t myInodeTableBlocks;
|
||||
u32_t myGroupDescriptorsPerBlock;
|
||||
u32_t myInodesPerBlock;
|
||||
|
||||
/* my functions */
|
||||
int readGroupDescriptor(u32_t group, ext2_group_desc_t *buf);
|
||||
int writeGroupDescriptor(u32_t group, ext2_group_desc_t *buf);
|
||||
int inodeStatus(u32_t inum);
|
||||
int blockStatus(u32_t bnum);
|
||||
u32_t allocFromBitmap(u32_t blockNum, u32_t max);
|
||||
void freeFromBitmap(u32_t blockNum, u32_t node);
|
||||
|
||||
public:
|
||||
Ext2fs(ext2_super_block_t *super, device_t dev);
|
||||
~Ext2fs();
|
||||
u32_t totalBlocks();
|
||||
u32_t freeBlocks();
|
||||
u32_t totalInodes();
|
||||
u32_t freeInodes();
|
||||
u32_t getRootInodeNumber();
|
||||
OpenDirectory *openDirectory(u32_t inum, int mode);
|
||||
OpenFile *openFile(u32_t inum, int mode);
|
||||
int stat(u32_t inum, vfs_stat_t *buf);
|
||||
int readBlock(u32_t blockNum, void *buf);
|
||||
int writeBlock(u32_t blockNum, void *buf);
|
||||
int link_deref(u32_t inum, char *buf);
|
||||
int readInode(u32_t inum, ext2_inode_t *buf);
|
||||
int writeInode(u32_t inum, ext2_inode_t *buf);
|
||||
u32_t allocInode();
|
||||
u32_t allocBlock();
|
||||
int freeInode(u32_t inum);
|
||||
int freeBlock(u32_t bnum);
|
||||
void unlink(u32_t inum);
|
||||
int attemptRemoveDir(u32_t inum);
|
||||
void truncateInode(u32_t inum);
|
||||
int initializeDirectory(u32_t inum, u32_t parent);
|
||||
|
||||
/* inlined functions */
|
||||
inline u32_t numGroups() { return myNumGroups; }
|
||||
inline u32_t groupDescriptorBlocks() { return myGroupDescriptorBlocks; }
|
||||
inline u32_t inodeTableBlocks() { return myInodeTableBlocks; }
|
||||
inline ext2_super_block_t *getSuper() { return &mySuper; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,762 @@
|
||||
// ext2.c
|
||||
// Author: Josh Holtrop
|
||||
// Date: 08/22/04
|
||||
// Modified: 12/24/04
|
||||
|
||||
#include "hos_defines.h"
|
||||
#include "fs/devices.h"
|
||||
#include "display/kout.h"
|
||||
#include "ext2.h"
|
||||
#include "mm/vmm.h"
|
||||
#include "fs/vfs.h"
|
||||
#include "lang/lang.h"
|
||||
#include "functions.h"
|
||||
|
||||
/* Turning an inode number into a (group, inode_index) pair:
|
||||
* group = (inode - 1) / s_inodes_per_group
|
||||
* index = (inode - 1) % s_inodes_per_group
|
||||
*/
|
||||
|
||||
vfs_fs_t ext2_driver = {ext2_mount_super, ext2_umount_super, ext2_stat,
|
||||
ext2__get_root_dir_inode, ext2__link_deref,
|
||||
ext2__free_inodes, ext2__total_inodes,
|
||||
ext2__free_blocks, ext2__total_blocks,
|
||||
ext2_alloc_inode, ext2_free_inode, ext2_alloc_block, ext2_free_block,
|
||||
ext2__open_dir, ext2__read_dir, ext2__close_dir,
|
||||
ext2__open_file, ext2__read_file, ext2__close_file,
|
||||
ext2__open_block_file, ext2__read_block_file, ext2__block_file_seek, ext2__close_block_file};
|
||||
|
||||
// initialize the filesystem driver
|
||||
int ext2_init(int fsID)
|
||||
{
|
||||
vfs_fs_t *fs;
|
||||
if (( fs = New(vfs_fs_t) )) // give the VFS our FS structure
|
||||
{
|
||||
*fs = ext2_driver;
|
||||
vfs_register_fs(fsID, fs);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// lookup a file name in a directory and store the directory entry for it
|
||||
int ext2_dir_lookup(vfs_mount_t *mount, u32_t dir_inode, char *fileName, ext2_dir_entry_t *direntry)
|
||||
{
|
||||
ext2_open_dir_t *dir = ext2_open_dir(mount, dir_inode);
|
||||
if (!dir)
|
||||
return -1; // bad directory inode number
|
||||
ext2_dir_entry_t dentry;
|
||||
while (!ext2_dir_read_entry(mount, dir, &dentry))
|
||||
{
|
||||
char *dentryName = kcalloc(1, dentry.name_length + 1);
|
||||
memcpy(dentryName, dentry.name, dentry.name_length);
|
||||
int res = strcmp(fileName, dentryName);
|
||||
kfree(dentryName);
|
||||
if (!res)
|
||||
{
|
||||
*direntry = dentry;
|
||||
ext2_close_dir(mount, dir);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
ext2_close_dir(mount, dir);
|
||||
return -2;
|
||||
}
|
||||
|
||||
// open a directory by inode number for reading
|
||||
ext2_open_dir_t *ext2_open_dir(vfs_mount_t *mount, u32_t inode_number)
|
||||
{
|
||||
ext2_open_dir_t *open_dir = New(ext2_open_dir_t);
|
||||
ext2_open_inode_t *open_inode = ext2_open_inode(mount, inode_number);
|
||||
if (!open_inode)
|
||||
{
|
||||
kfree(open_dir);
|
||||
return NULL;
|
||||
}
|
||||
if ((open_inode->inode.i_mode & EXT2_I_MODE_TYPE_MASK) != EXT2_I_MODE_DIR)
|
||||
{
|
||||
ext2_close_inode(mount, open_inode);
|
||||
kfree(open_dir);
|
||||
return NULL;
|
||||
}
|
||||
open_dir->open_inode = open_inode;
|
||||
open_dir->position = 0;
|
||||
return open_dir;
|
||||
}
|
||||
|
||||
int ext2_dir_read_entry(vfs_mount_t *mount, ext2_open_dir_t *open_dir, ext2_dir_entry_t *dentry)
|
||||
{
|
||||
ext2_super_block_t *super = mount->super;
|
||||
if (open_dir->position >= open_dir->open_inode->inode.i_size)
|
||||
return -1; // EOF
|
||||
u32_t dir_block = open_dir->position >> (10 + super->s_log_block_size);
|
||||
char *block = kmalloc(2048 << super->s_log_block_size);
|
||||
ext2_inode_seek(mount, open_dir->open_inode, dir_block);
|
||||
if (ext2_read_inode_block(mount, open_dir->open_inode, block))
|
||||
ext2_read_inode_block(mount, open_dir->open_inode, block + (1024 << super->s_log_block_size));
|
||||
ext2_dir_entry_t *dir_entry = (ext2_dir_entry_t *)(block + open_dir->position % (1024 << super->s_log_block_size));
|
||||
if (!dir_entry->inode)
|
||||
{
|
||||
kfree(block);
|
||||
return -2; // EOF
|
||||
}
|
||||
memcpy(dentry, dir_entry, min(dir_entry->length, sizeof(ext2_dir_entry_t)));
|
||||
open_dir->position += dir_entry->length;
|
||||
kfree(block);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext2_close_dir(vfs_mount_t *mount, ext2_open_dir_t *open_dir)
|
||||
{
|
||||
ext2_close_inode(mount, open_dir->open_inode);
|
||||
kfree(open_dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// open an inode for reading
|
||||
ext2_open_inode_t *ext2_open_inode(vfs_mount_t *mount, u32_t inode_number)
|
||||
{
|
||||
ext2_open_inode_t *open_inode = New(ext2_open_inode_t);
|
||||
if ( ext2_read_inode(mount, inode_number, &(open_inode->inode)) )
|
||||
{
|
||||
kfree(open_inode);
|
||||
return NULL;
|
||||
}
|
||||
open_inode->block = 0;
|
||||
open_inode->block_pointers = NULL;
|
||||
open_inode->block_pointers_start = 0;
|
||||
mount->refs++;
|
||||
return open_inode;
|
||||
}
|
||||
|
||||
|
||||
// seek to a certain block of an open inode
|
||||
int ext2_inode_seek(vfs_mount_t *mount, ext2_open_inode_t *open_inode, u32_t block_number)
|
||||
{
|
||||
ext2_super_block_t *super = mount->super;
|
||||
if (open_inode->inode.i_size <= (block_number << (10 + super->s_log_block_size)))
|
||||
return -1; // at or past EOF
|
||||
open_inode->block = block_number;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// returns number of bytes read
|
||||
int ext2_read_inode_block(vfs_mount_t *mount, ext2_open_inode_t *open_inode, void *block)
|
||||
{
|
||||
ext2_super_block_t *super = mount->super;
|
||||
if (open_inode->inode.i_size <= (open_inode->block << (10 + super->s_log_block_size)))
|
||||
return 0; // at or past EOF
|
||||
u32_t leftover_bytes = open_inode->inode.i_size - (open_inode->block << (10 + super->s_log_block_size));
|
||||
u32_t block_number = ext2_block_number(mount, open_inode);
|
||||
block_read(mount->major, mount->minor, ext2_FSToDiskBlock(block_number, super),
|
||||
2 << super->s_log_block_size, block);
|
||||
open_inode->block++;
|
||||
return min(leftover_bytes, 1024 << super->s_log_block_size);
|
||||
}
|
||||
|
||||
|
||||
// close an open inode
|
||||
int ext2_close_inode(vfs_mount_t *mount, ext2_open_inode_t *open_inode)
|
||||
{
|
||||
mount->refs--;
|
||||
if (open_inode->block_pointers)
|
||||
kfree(open_inode->block_pointers); // free the block pointers cache
|
||||
kfree(open_inode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// check the status of an inode (1-based inode number)
|
||||
// -1: invalid inode number
|
||||
// 0: free inode
|
||||
// 1: allocated inode
|
||||
int ext2_inode_status(vfs_mount_t *mount, u32_t inode_number)
|
||||
{
|
||||
ext2_super_block_t *super = mount->super;
|
||||
if (inode_number < 1 || inode_number > super->s_inodes_count) // inode number invalid
|
||||
return -1;
|
||||
inode_number--; // turn inode_number into a 0-based index
|
||||
u32_t group = inode_number / super->s_inodes_per_group;
|
||||
u32_t index = inode_number % super->s_inodes_per_group;
|
||||
u32_t inode_bitmap_block = ext2_get_group_desc(mount, group).bg_inode_bitmap + (index >> (13 + super->s_log_block_size));
|
||||
u32_t bitmap_index = index % (8192 << super->s_log_block_size);
|
||||
u8_t *inode_bitmap = kmalloc(1024 << super->s_log_block_size);
|
||||
block_read(mount->major, mount->minor,
|
||||
ext2_FSToDiskBlock(inode_bitmap_block, super), 2 << super->s_log_block_size, inode_bitmap);
|
||||
int inode_status = (inode_bitmap[bitmap_index >> 3] >> (bitmap_index & 0x7)) & 1;
|
||||
kfree(inode_bitmap);
|
||||
return inode_status;
|
||||
}
|
||||
|
||||
|
||||
// check the status of a block
|
||||
// -1: invalid block number
|
||||
// 0: free block
|
||||
// 1: allocated block
|
||||
int ext2_block_status(vfs_mount_t *mount, u32_t block_number)
|
||||
{
|
||||
ext2_super_block_t *super = mount->super;
|
||||
if (block_number < super->s_first_data_block || block_number > super->s_blocks_count) // block number invalid
|
||||
return -1;
|
||||
block_number -= super->s_first_data_block;
|
||||
u32_t group = block_number / super->s_blocks_per_group;
|
||||
u32_t index = block_number % super->s_blocks_per_group;
|
||||
u32_t block_bitmap_block = ext2_get_group_desc(mount, group).bg_block_bitmap + (index >> (13 + super->s_log_block_size));
|
||||
u32_t bitmap_index = index % (8192 << super->s_log_block_size);
|
||||
u8_t *block_bitmap = kmalloc(1024 << super->s_log_block_size);
|
||||
block_read(mount->major, mount->minor,
|
||||
ext2_FSToDiskBlock(block_bitmap_block, super), 2 << super->s_log_block_size, block_bitmap);
|
||||
int block_status = (block_bitmap[bitmap_index >> 3] >> (bitmap_index & 0x7)) & 1;
|
||||
kfree(block_bitmap);
|
||||
return block_status;
|
||||
}
|
||||
|
||||
|
||||
// transform open_inode->block (a relative block number) to an absolute block number for the filesystem
|
||||
u32_t ext2_block_number(vfs_mount_t *mount, ext2_open_inode_t *open_inode)
|
||||
{
|
||||
if (open_inode->block < 12)
|
||||
return open_inode->inode.i_block[open_inode->block];
|
||||
ext2_super_block_t *super = mount->super;
|
||||
int pointersPerBlock = 256 << super->s_log_block_size;
|
||||
if (open_inode->block_pointers && // there is a block pointers cache block allocated
|
||||
(open_inode->block >= open_inode->block_pointers_start) && // and the block number is in it
|
||||
(open_inode->block < (open_inode->block_pointers_start + pointersPerBlock)))
|
||||
return open_inode->block_pointers[open_inode->block - open_inode->block_pointers_start];
|
||||
u32_t rel_block = open_inode->block - 12;
|
||||
if (!open_inode->block_pointers)
|
||||
open_inode->block_pointers = kmalloc(pointersPerBlock << 2);
|
||||
if (rel_block < pointersPerBlock) // indirect block in i_block[12]
|
||||
{
|
||||
block_read(mount->major, mount->minor, ext2_FSToDiskBlock(open_inode->inode.i_block[12], super),
|
||||
2 << super->s_log_block_size, open_inode->block_pointers);
|
||||
open_inode->block_pointers_start = 12;
|
||||
return open_inode->block_pointers[rel_block];
|
||||
}
|
||||
rel_block -= pointersPerBlock;
|
||||
if (rel_block < (pointersPerBlock * pointersPerBlock)) // double-indirect block in i_block[13]
|
||||
{
|
||||
block_read(mount->major, mount->minor, ext2_FSToDiskBlock(open_inode->inode.i_block[13], super),
|
||||
2 << super->s_log_block_size, open_inode->block_pointers);
|
||||
u32_t real_block = open_inode->block_pointers[rel_block / pointersPerBlock];
|
||||
block_read(mount->major, mount->minor, ext2_FSToDiskBlock(real_block, super),
|
||||
2 << super->s_log_block_size, open_inode->block_pointers);
|
||||
open_inode->block_pointers_start = 12 + pointersPerBlock + rel_block - (rel_block % pointersPerBlock);
|
||||
return open_inode->block_pointers[rel_block % pointersPerBlock];
|
||||
}
|
||||
// this code shouldn't run unless we are dealing with a 65+mb file ...
|
||||
rel_block -= pointersPerBlock * pointersPerBlock;
|
||||
block_read(mount->major, mount->minor, ext2_FSToDiskBlock(open_inode->inode.i_block[14], super),
|
||||
2 << super->s_log_block_size, open_inode->block_pointers);
|
||||
u32_t index_1 = rel_block / (pointersPerBlock * pointersPerBlock);
|
||||
u32_t leftover_1 = rel_block % (pointersPerBlock * pointersPerBlock);
|
||||
u32_t block_1 = open_inode->block_pointers[index_1];
|
||||
block_read(mount->major, mount->minor, ext2_FSToDiskBlock(block_1, super),
|
||||
2 << super->s_log_block_size, open_inode->block_pointers);
|
||||
u32_t index_2 = leftover_1 / pointersPerBlock;
|
||||
u32_t leftover_2 = leftover_1 % pointersPerBlock;
|
||||
u32_t block_2 = open_inode->block_pointers[index_2];
|
||||
block_read(mount->major, mount->minor, ext2_FSToDiskBlock(block_2, super),
|
||||
2 << super->s_log_block_size, open_inode->block_pointers);
|
||||
open_inode->block_pointers_start = 12 + (pointersPerBlock + 1) * pointersPerBlock + rel_block - (rel_block % pointersPerBlock);
|
||||
return open_inode->block_pointers[leftover_2];
|
||||
}
|
||||
|
||||
|
||||
// read the inode structure from the device
|
||||
int ext2_read_inode(vfs_mount_t *mount, u32_t inode, ext2_inode_t *dat)
|
||||
{
|
||||
if (ext2_inode_status(mount, inode) != 1)
|
||||
return -1; // free or invalid inode number
|
||||
ext2_super_block_t *super = mount->super;
|
||||
inode--; // turn inode into a 0-based index
|
||||
u32_t group = inode / super->s_inodes_per_group;
|
||||
u32_t index = inode % super->s_inodes_per_group;
|
||||
u32_t inodeAddr = (ext2_get_group_desc(mount, group).bg_inode_table <<
|
||||
(10 + super->s_log_block_size)) + (index << 7);
|
||||
void *block = kmalloc(512);
|
||||
block_read(mount->major, mount->minor, inodeAddr >> 9, 1, block);
|
||||
memcpy(dat, (block + (inodeAddr & 0x1FF)), sizeof(ext2_inode_t));
|
||||
kfree(block);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// write an inode structure to the device
|
||||
int ext2_write_inode(vfs_mount_t *mount, u32_t inode, ext2_inode_t *dat)
|
||||
{
|
||||
if (ext2_inode_status(mount, inode) != 1)
|
||||
return -1; // free or invalid inode number
|
||||
ext2_super_block_t *super = mount->super;
|
||||
inode--; // turn inode into a 0-based index
|
||||
u32_t group = inode / super->s_inodes_per_group;
|
||||
u32_t index = inode % super->s_inodes_per_group;
|
||||
u32_t inodeAddr = (ext2_get_group_desc(mount, group).bg_inode_table <<
|
||||
(10 + super->s_log_block_size)) + (index << 7);
|
||||
void *block = kmalloc(512);
|
||||
block_read(mount->major, mount->minor, inodeAddr >> 9, 1, block);
|
||||
memcpy( (block + (inodeAddr & 0x1FF)), dat, sizeof(ext2_inode_t));
|
||||
block_write(mount->major, mount->minor, inodeAddr >> 9, 1, block);
|
||||
kfree(block);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// read the group descriptor structure from the device and return it
|
||||
ext2_group_desc_t ext2_get_group_desc(vfs_mount_t *mount, u32_t group)
|
||||
{
|
||||
ext2_super_block_t *super = mount->super;
|
||||
u32_t groupDescAddr = ((1 + super->s_first_data_block) << (10 + super->s_log_block_size)) + (group << 5);
|
||||
void *block = kmalloc(512);
|
||||
block_read(mount->major, mount->minor, groupDescAddr >> 9, 1, block);
|
||||
ext2_group_desc_t gd = *(ext2_group_desc_t *)(block + (groupDescAddr & 0x1FF));
|
||||
kfree(block);
|
||||
return gd;
|
||||
}
|
||||
|
||||
// write the group descriptor structure to the device
|
||||
void ext2_write_group_desc(vfs_mount_t *mount, u32_t group_num, ext2_group_desc_t *gd)
|
||||
{
|
||||
ext2_super_block_t *super = mount->super;
|
||||
u32_t groupDescAddr = ((1 + super->s_first_data_block) << (10 + super->s_log_block_size)) + (group_num << 5);
|
||||
void *block = kmalloc(512);
|
||||
block_read(mount->major, mount->minor, groupDescAddr >> 9, 1, block);
|
||||
memcpy( (block + (groupDescAddr & 0x1FF)), gd, sizeof(ext2_group_desc_t) );
|
||||
block_write(mount->major, mount->minor, groupDescAddr >> 9, 1, block);
|
||||
kfree(block);
|
||||
}
|
||||
|
||||
// allocate an inode and return its number
|
||||
u32_t ext2_alloc_inode(vfs_mount_t *mount)
|
||||
{
|
||||
ext2_super_block_t *super = mount->super;
|
||||
if (!super->s_free_inodes_count)
|
||||
return 0; // no free inodes
|
||||
int bg, bg_max = ext2_num_block_groups(super);
|
||||
for (bg = 0; bg < bg_max; bg++)
|
||||
{
|
||||
ext2_group_desc_t group_desc = ext2_get_group_desc(mount, bg);
|
||||
if (group_desc.bg_free_inodes_count)
|
||||
{
|
||||
u32_t node = ext2_reserve_node(mount, group_desc.bg_inode_bitmap, super->s_inodes_per_group);
|
||||
group_desc.bg_free_inodes_count--;
|
||||
ext2_write_group_desc(mount, bg, &group_desc);
|
||||
super->s_free_inodes_count--;
|
||||
return bg * super->s_inodes_per_group + node + 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext2_free_inode(vfs_mount_t *mount, u32_t inode_number)
|
||||
{
|
||||
ext2_super_block_t *super = mount->super;
|
||||
if (inode_number < 11 || inode_number > super->s_inodes_count)
|
||||
return -1; // invalid inode number
|
||||
if (ext2_inode_status(mount, inode_number) != 1)
|
||||
return -2; // inode not allocated
|
||||
inode_number--; // now a 0-based inode number
|
||||
int bg = inode_number / super->s_inodes_per_group;
|
||||
ext2_group_desc_t group_desc = ext2_get_group_desc(mount, bg);
|
||||
ext2_free_node(mount, group_desc.bg_inode_bitmap, inode_number % super->s_inodes_per_group);
|
||||
group_desc.bg_free_inodes_count++;
|
||||
ext2_write_group_desc(mount, bg, &group_desc);
|
||||
super->s_free_inodes_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// allocate a block and return its number
|
||||
u32_t ext2_alloc_block(vfs_mount_t *mount)
|
||||
{
|
||||
ext2_super_block_t *super = mount->super;
|
||||
if (!super->s_free_blocks_count)
|
||||
return 0; // no free blocks
|
||||
int bg, bg_max = ext2_num_block_groups(super);
|
||||
for (bg = 0; bg < bg_max; bg++)
|
||||
{
|
||||
ext2_group_desc_t group_desc = ext2_get_group_desc(mount, bg);
|
||||
if (group_desc.bg_free_blocks_count)
|
||||
{
|
||||
u32_t node = ext2_reserve_node(mount, group_desc.bg_block_bitmap, super->s_blocks_per_group);
|
||||
group_desc.bg_free_blocks_count--;
|
||||
ext2_write_group_desc(mount, bg, &group_desc);
|
||||
super->s_free_blocks_count--;
|
||||
return bg * super->s_blocks_per_group + node + super->s_first_data_block;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext2_free_block(vfs_mount_t *mount, u32_t block_number)
|
||||
{
|
||||
ext2_super_block_t *super = mount->super;
|
||||
if (block_number < super->s_first_data_block || block_number > (super->s_blocks_count + super->s_first_data_block - 1))
|
||||
return -1; // invalid block number
|
||||
if (ext2_block_status(mount, block_number) != 1)
|
||||
return -2; // block not allocated
|
||||
block_number -= super->s_first_data_block; // now a 0-based block number
|
||||
int bg = block_number / super->s_blocks_per_group;
|
||||
ext2_group_desc_t group_desc = ext2_get_group_desc(mount, bg);
|
||||
ext2_free_node(mount, group_desc.bg_block_bitmap, block_number % super->s_blocks_per_group);
|
||||
group_desc.bg_free_blocks_count++;
|
||||
ext2_write_group_desc(mount, bg, &group_desc);
|
||||
super->s_free_blocks_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext2_resize_inode(vfs_mount_t *mount, u32_t inode_number, u32_t new_size)
|
||||
{
|
||||
ext2_inode_t inode;
|
||||
if ( ext2_read_inode(mount, inode_number, &inode) )
|
||||
return -1;
|
||||
ext2_super_block_t *super = mount->super;
|
||||
int current_blocks = (inode.i_size + (1024 << super->s_log_block_size) - 1) >> (10 + super->s_log_block_size);
|
||||
int new_blocks = (new_size + (1024 << super->s_log_block_size) - 1) >> (10 + super->s_log_block_size);
|
||||
if ( new_blocks == current_blocks )
|
||||
return 0;
|
||||
|
||||
// TODO: resize
|
||||
u32_t block_size = 1024 << super->s_log_block_size;
|
||||
u32_t pointers_per_block = block_size >> 2;
|
||||
u32_t *pointer_cache1 = kmalloc(3 * block_size);
|
||||
u32_t *pointer_cache2 = pointer_cache1 + pointers_per_block;
|
||||
u32_t *pointer_cache3 = pointer_cache2 + pointers_per_block;
|
||||
u32_t c1_start, c2_start, c3_start;
|
||||
c1_start = c2_start = c3_start = 0;
|
||||
while (new_blocks < current_blocks) // delete, decrease current_blocks
|
||||
{
|
||||
current_blocks--;
|
||||
// now delete block number current_blocks
|
||||
|
||||
}
|
||||
|
||||
while (current_blocks < new_blocks) // add, increase current_blocks
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
// reserve a node of a inode or block bitmap and mark its entry allocated
|
||||
u32_t ext2_reserve_node(vfs_mount_t *mount, u32_t bitmap_block_num, u32_t bitmap_size)
|
||||
{
|
||||
ext2_super_block_t *super = mount->super;
|
||||
u32_t *bitmap = kmalloc(1024 << super->s_log_block_size);
|
||||
int block, max_block = (bitmap_size - 1) / (8192 << super->s_log_block_size) + 1;
|
||||
for (block = 0; block < max_block; block++)
|
||||
{
|
||||
block_read(mount->major, mount->minor, ext2_FSToDiskBlock(bitmap_block_num + block, super),
|
||||
2 << super->s_log_block_size, bitmap);
|
||||
int num, num_max = 256 << super->s_log_block_size;
|
||||
u32_t *block_pointer = bitmap;
|
||||
int done = 0;
|
||||
for (num = 0; num < num_max && !done; num++)
|
||||
{
|
||||
if (*block_pointer != 0xFFFFFFFF)
|
||||
{
|
||||
done = 1;
|
||||
int bit;
|
||||
for (bit = 0; bit < 32; bit++)
|
||||
{
|
||||
if (!(*block_pointer & (1 << bit)))
|
||||
{
|
||||
u32_t node_number = (block * 8192 << super->s_log_block_size) + (num << 5) + bit;
|
||||
if (node_number < bitmap_size)
|
||||
{
|
||||
// found a node, mark it allocated, write the bitmap, return
|
||||
*block_pointer |= (1 << bit);
|
||||
block_write(mount->major, mount->minor,
|
||||
ext2_FSToDiskBlock(bitmap_block_num + block, super),
|
||||
2 << super->s_log_block_size, bitmap);
|
||||
kfree(bitmap);
|
||||
return node_number;
|
||||
}
|
||||
kfree(bitmap);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
block_pointer++;
|
||||
}
|
||||
}
|
||||
kfree(bitmap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext2_free_node(vfs_mount_t *mount, u32_t bitmap_block_num, u32_t node_number)
|
||||
{
|
||||
ext2_super_block_t *super = mount->super;
|
||||
u32_t block_num = node_number >> (13 + super->s_log_block_size);
|
||||
byte *block = kmalloc(1024 << super->s_log_block_size);
|
||||
block_read(mount->major, mount->minor, ext2_FSToDiskBlock(bitmap_block_num + block_num, super),
|
||||
2 << super->s_log_block_size, block);
|
||||
u32_t node_bit_offset = node_number % (8192 << super->s_log_block_size);
|
||||
u32_t node_byte_offset = node_bit_offset >> 3;
|
||||
block[node_byte_offset] &= (0xFF ^ (1 << (node_bit_offset & 0x7)));
|
||||
block_write(mount->major, mount->minor, ext2_FSToDiskBlock(bitmap_block_num + block_num, super),
|
||||
2 << super->s_log_block_size, block);
|
||||
kfree(block);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return how many block groups are on the filesystem
|
||||
int ext2_num_block_groups(ext2_super_block_t *super)
|
||||
{
|
||||
return (super->s_inodes_count / super->s_inodes_per_group) + 1;
|
||||
}
|
||||
|
||||
void ext2_write_super(vfs_mount_t *mount)
|
||||
{
|
||||
block_write(mount->major, mount->minor, 2, 2, mount->super);
|
||||
}
|
||||
|
||||
|
||||
/***************** VFS INTERFACE FUNCTIONS *******************/
|
||||
|
||||
|
||||
// mount the superblock of the filesystem and return a pointer to it, if valid
|
||||
void *ext2_mount_super(major_t major, minor_t minor)
|
||||
{
|
||||
ext2_super_block_t *super = kmalloc(1024);
|
||||
block_read(major, minor, 2, 2, super);
|
||||
if (super->s_magic != EXT2_MAGIC) // not an ext2 filesystem
|
||||
{
|
||||
kfree(super);
|
||||
return NULL;
|
||||
}
|
||||
return super;
|
||||
}
|
||||
|
||||
|
||||
// called when we are unmounting this filesystem mount
|
||||
int ext2_umount_super(vfs_mount_t *mount)
|
||||
{
|
||||
ext2_write_super(mount);
|
||||
return kfree(mount->super); // free memory that the superblock was taking
|
||||
}
|
||||
|
||||
|
||||
// stat a file, return a structure of info about it
|
||||
int ext2_stat(vfs_mount_t *mount, u32_t inode_number, vfs_stat_t *stat)
|
||||
{
|
||||
if (ext2_inode_status(mount, inode_number) != 1)
|
||||
return -1;
|
||||
ext2_inode_t *inode = New(ext2_inode_t);
|
||||
if ( ext2_read_inode(mount, inode_number, inode) )
|
||||
{
|
||||
kfree(inode);
|
||||
return -2;
|
||||
}
|
||||
|
||||
stat->dev = 0;
|
||||
switch(inode->i_mode & EXT2_I_MODE_TYPE_MASK)
|
||||
{
|
||||
case EXT2_I_MODE_FIFO: stat->type = VFS_FT_FIFO; break;
|
||||
case EXT2_I_MODE_CHAR: stat->type = VFS_FT_CHAR; stat->dev = inode->i_block[0]; break;
|
||||
case EXT2_I_MODE_DIR: stat->type = VFS_FT_DIR; break;
|
||||
case EXT2_I_MODE_BLOCK: stat->type = VFS_FT_BLOCK; stat->dev = inode->i_block[0]; break;
|
||||
case EXT2_I_MODE_FILE: stat->type = VFS_FT_FILE; break;
|
||||
case EXT2_I_MODE_SYM: stat->type = VFS_FT_SYMLINK; break;
|
||||
case EXT2_I_MODE_SOCK: stat->type = VFS_FT_SOCK; break;
|
||||
default: stat->type = VFS_FT_UNKNOWN; break;
|
||||
}
|
||||
stat->size = inode->i_size;
|
||||
stat->inode = inode_number;
|
||||
stat->permissions = inode->i_mode & EXT2_I_MODE_ATTR_MASK;
|
||||
stat->uid = inode->i_uid;
|
||||
stat->gid = inode->i_gid;
|
||||
stat->atime = inode->i_atime;
|
||||
stat->mtime = inode->i_mtime;
|
||||
stat->ctime = inode->i_ctime;
|
||||
stat->links = inode->i_links_count;
|
||||
kfree(inode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// what is the inode of the root directory?
|
||||
u32_t ext2__get_root_dir_inode(vfs_mount_t *mount)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
// VFS interface function to dereference a symbolic link
|
||||
int ext2__link_deref(vfs_mount_t *mount, u32_t link_inode, char *link)
|
||||
{
|
||||
ext2_inode_t inode;
|
||||
if (ext2_read_inode(mount, link_inode, &inode))
|
||||
return -1;
|
||||
if ( (inode.i_mode & EXT2_I_MODE_TYPE_MASK) != EXT2_I_MODE_SYM )
|
||||
return -2;
|
||||
if (!inode.i_size)
|
||||
return -4;
|
||||
if (inode.i_size < 61)
|
||||
{
|
||||
memcpy(link, inode.i_block, inode.i_size);
|
||||
link[inode.i_size] = 0;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ext2_open_inode_t *open_inode;
|
||||
if (!(open_inode = ext2_open_inode(mount, link_inode)))
|
||||
return -3;
|
||||
ext2_super_block_t *super = mount->super;
|
||||
void *buffer = kmalloc(1024 << super->s_log_block_size);
|
||||
memset(link, 0, 4096);
|
||||
int copied = 0;
|
||||
while (copied < 4096)
|
||||
{
|
||||
int bytes_read = ext2_read_inode_block(mount, open_inode, buffer);
|
||||
if (bytes_read == 0)
|
||||
break;
|
||||
memcpy(link + copied, buffer, bytes_read);
|
||||
copied += bytes_read;
|
||||
}
|
||||
ext2_close_inode(mount, open_inode);
|
||||
kfree(buffer);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// VFS interface function to return the number of free inodes
|
||||
int ext2__free_inodes(vfs_mount_t *mount)
|
||||
{
|
||||
ext2_super_block_t *super = mount->super;
|
||||
return super->s_free_inodes_count;
|
||||
}
|
||||
|
||||
// VFS interface function to return the total number of inodes
|
||||
int ext2__total_inodes(vfs_mount_t *mount)
|
||||
{
|
||||
ext2_super_block_t *super = mount->super;
|
||||
return super->s_inodes_count;
|
||||
}
|
||||
|
||||
// VFS interface function to return the number of free 512-byte blocks
|
||||
int ext2__free_blocks(vfs_mount_t *mount)
|
||||
{
|
||||
ext2_super_block_t *super = mount->super;
|
||||
return super->s_free_blocks_count << (1 + super->s_log_block_size);
|
||||
}
|
||||
|
||||
// VFS interface function to return the total number of 512-byte blocks
|
||||
int ext2__total_blocks(vfs_mount_t *mount)
|
||||
{
|
||||
ext2_super_block_t *super = mount->super;
|
||||
return super->s_blocks_count << (1 + super->s_log_block_size);
|
||||
}
|
||||
|
||||
// VFS interface function to open a directory
|
||||
int ext2__open_dir(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *dir)
|
||||
{
|
||||
if (ext2_inode_status(mount, inode_number) != 1)
|
||||
return -1;
|
||||
ext2_open_dir_t *open_dir = ext2_open_dir(mount, inode_number);
|
||||
if (!open_dir)
|
||||
return -2;
|
||||
dir->fs_data = open_dir;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// VFS interface function to read a directory entry from an open directory
|
||||
int ext2__read_dir(vfs_mount_t *mount, vfs_open_file_t *dir, vfs_dir_entry_t *dentry)
|
||||
{
|
||||
ext2_dir_entry_t t_dentry;
|
||||
int status = ext2_dir_read_entry(mount, dir->fs_data, &t_dentry);
|
||||
if (status)
|
||||
return status;
|
||||
memcpy(dentry->name, t_dentry.name, t_dentry.name_length);
|
||||
dentry->name[t_dentry.name_length] = 0;
|
||||
dentry->inode_number = t_dentry.inode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// VFS interface function to close an open directory
|
||||
int ext2__close_dir(vfs_mount_t *mount, vfs_open_file_t *dir)
|
||||
{
|
||||
return ext2_close_dir(mount, dir->fs_data);
|
||||
}
|
||||
|
||||
|
||||
// VFS interface function to open a file for reading a byte at a time
|
||||
int ext2__open_file(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *open_file)
|
||||
{
|
||||
if (ext2_inode_status(mount, inode_number) != 1)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// VFS interface function to read a byte from an open file
|
||||
int ext2__read_file(vfs_mount_t *mount, vfs_open_file_t *open_file)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// VFS interface function to close a byte-file
|
||||
int ext2__close_file(vfs_mount_t *mount, vfs_open_file_t *open_file)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// VFS interface function to open a file for reading 512-byte blocks at a time
|
||||
int ext2__open_block_file(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *open_file)
|
||||
{
|
||||
if (ext2_inode_status(mount, inode_number) != 1)
|
||||
return -1;
|
||||
ext2_open_inode_t *open_inode = ext2_open_inode(mount, inode_number);
|
||||
if (!open_inode)
|
||||
return -2;
|
||||
if ((open_inode->inode.i_mode & EXT2_I_MODE_TYPE_MASK) != EXT2_I_MODE_FILE)
|
||||
{
|
||||
ext2_close_inode(mount, open_inode);
|
||||
return -3;
|
||||
}
|
||||
ext2__open_block_file_t *open_block_file = New(ext2__open_block_file_t);
|
||||
open_block_file->open_inode = open_inode;
|
||||
open_block_file->block = 0;
|
||||
open_file->fs_data = open_block_file;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// VFS interface function to read a block from an open block file
|
||||
// returns the number of bytes read
|
||||
int ext2__read_block_file(vfs_mount_t *mount, vfs_open_file_t *open_file, void *buffer)
|
||||
{
|
||||
ext2_super_block_t *super = mount->super;
|
||||
ext2__open_block_file_t *open_block_file = open_file->fs_data;
|
||||
if (ext2_inode_seek(mount, open_block_file->open_inode, ext2_diskToFSBlock(open_block_file->block, super)))
|
||||
return 0; // EOF
|
||||
u8_t *block = kmalloc(1024 << super->s_log_block_size);
|
||||
u32_t file_position_read = (1024 << super->s_log_block_size) * open_block_file->open_inode->block;
|
||||
u32_t file_position_want = open_block_file->block << 9;
|
||||
u32_t data_offset = file_position_want - file_position_read;
|
||||
int bytes_read = ext2_read_inode_block(mount, open_block_file->open_inode, block);
|
||||
if (bytes_read <= data_offset)
|
||||
{
|
||||
kfree(block);
|
||||
return 0; // EOF
|
||||
}
|
||||
memcpy(buffer, block + data_offset, min(512, bytes_read - data_offset));
|
||||
kfree(block);
|
||||
open_block_file->block++;
|
||||
return min(512, bytes_read - data_offset);
|
||||
}
|
||||
|
||||
// VFS interface function to seek to a certain block number of an open block file
|
||||
int ext2__block_file_seek(vfs_mount_t *mount, vfs_open_file_t *open_file, u32_t block_number)
|
||||
{
|
||||
ext2__open_block_file_t *open_block_file = open_file->fs_data;
|
||||
return ext2_inode_seek(mount, open_block_file->open_inode, ext2_FSToDiskBlock(block_number, mount->super));
|
||||
}
|
||||
|
||||
// VFS interface function to close an open block file
|
||||
int ext2__close_block_file(vfs_mount_t *mount, vfs_open_file_t *open_file)
|
||||
{
|
||||
ext2__open_block_file_t *open_block_file = open_file->fs_data;
|
||||
ext2_close_inode(mount, open_block_file->open_inode);
|
||||
kfree(open_block_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
// ext2.h
|
||||
// Author: Josh Holtrop
|
||||
// Date: 08/22/04
|
||||
// Modified: 12/24/04
|
||||
|
||||
#ifndef __HOS_EXT2_H__
|
||||
#define __HOS_EXT2_H__ __HOS_EXT2_H__
|
||||
|
||||
#include "hos_defines.h"
|
||||
#include "fs/devices.h"
|
||||
#include "fs/vfs.h"
|
||||
|
||||
#define EXT2_MAGIC 0xEF53
|
||||
#define EXT2_NAME_LEN 255
|
||||
|
||||
#define EXT2_I_MODE_ATTR_MASK 0x0FFF
|
||||
#define EXT2_I_MODE_OX 0x0001
|
||||
#define EXT2_I_MODE_OW 0x0002
|
||||
#define EXT2_I_MODE_OR 0x0004
|
||||
#define EXT2_I_MODE_GX 0x0008
|
||||
#define EXT2_I_MODE_GW 0x0010
|
||||
#define EXT2_I_MODE_GR 0x0020
|
||||
#define EXT2_I_MODE_UX 0x0040
|
||||
#define EXT2_I_MODE_UW 0x0080
|
||||
#define EXT2_I_MODE_UR 0x0100
|
||||
#define EXT2_I_MODE_STICKY 0x0200
|
||||
#define EXT2_I_MODE_SGID 0x0400
|
||||
#define EXT2_I_MODE_SUID 0x0800
|
||||
|
||||
#define EXT2_I_MODE_TYPE_MASK 0xF000
|
||||
#define EXT2_I_MODE_FIFO 0x1000
|
||||
#define EXT2_I_MODE_CHAR 0x2000
|
||||
#define EXT2_I_MODE_DIR 0x4000
|
||||
#define EXT2_I_MODE_BLOCK 0x6000
|
||||
#define EXT2_I_MODE_FILE 0x8000
|
||||
#define EXT2_I_MODE_SYM 0xA000
|
||||
#define EXT2_I_MODE_SOCK 0xC000
|
||||
|
||||
#define EXT2_I_FLAGS_SEC_DEL 0x01
|
||||
#define EXT2_I_FLAGS_UNDELETE 0x02
|
||||
#define EXT2_I_FLAGS_COMPRESS 0x04
|
||||
#define EXT2_I_FLAGS_SYNC 0x08
|
||||
#define EXT2_I_FLAGS_IMMUTABLE 0x10
|
||||
#define EXT2_I_FLAGS_APPEND 0x20
|
||||
#define EXT2_I_FLAGS_NODUMP 0x40
|
||||
|
||||
#define EXT2_INODE_BAD_BLOCKS 1
|
||||
#define EXT2_INODE_ROOT 2
|
||||
#define EXT2_INODE_ACL_INDEX 3
|
||||
#define EXT2_INODE_ACL_DATA 4
|
||||
#define EXT2_INODE_BOOT_LOADER 5
|
||||
#define EXT2_INODE_UNDELETE_DIR 6
|
||||
#define EXT2_INODE_AVAIL 11
|
||||
|
||||
#define EXT2_FT_UNKNOWN 0
|
||||
#define EXT2_FT_FILE 1
|
||||
#define EXT2_FT_DIR 2
|
||||
#define EXT2_FT_CHAR 3
|
||||
#define EXT2_FT_BLOCK 4
|
||||
#define EXT2_FT_FIFO 5
|
||||
#define EXT2_FT_SOCK 6
|
||||
#define EXT2_FT_SYMLINK 7
|
||||
#define EXT2_FT_MAX 8
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32_t s_inodes_count; /* Inodes count */
|
||||
u32_t s_blocks_count; /* Blocks count */
|
||||
u32_t s_r_blocks_count; /* Reserved blocks count */
|
||||
u32_t s_free_blocks_count; /* Free blocks count */
|
||||
u32_t s_free_inodes_count; /* Free inodes count */
|
||||
u32_t s_first_data_block; /* First Data Block */
|
||||
u32_t s_log_block_size; /* Block size: 0->1024, 1->2048, 2->4096 */
|
||||
int s_log_frag_size; /* Fragment size */
|
||||
u32_t s_blocks_per_group; /* # Blocks per group */
|
||||
u32_t s_frags_per_group; /* # Fragments per group */
|
||||
u32_t s_inodes_per_group; /* # Inodes per group */
|
||||
u32_t s_mtime; /* Mount time */
|
||||
u32_t s_wtime; /* Write time */
|
||||
u16_t s_mnt_count; /* Mount count */
|
||||
short s_max_mnt_count; /* Maximal mount count */
|
||||
u16_t s_magic; /* Magic signature */
|
||||
u16_t s_state; /* File system state */
|
||||
u16_t s_errors; /* Behaviour when detecting errors */
|
||||
u16_t s_minor_rev_level; /* minor revision level */
|
||||
u32_t s_lastcheck; /* time of last check */
|
||||
u32_t s_checkinterval; /* max. time between checks */
|
||||
u32_t s_creator_os; /* OS */
|
||||
u32_t s_rev_level; /* Revision level */
|
||||
u16_t s_def_resuid; /* Default uid for reserved blocks */
|
||||
u16_t s_def_resgid; /* Default gid for reserved blocks */
|
||||
|
||||
u32_t s_reserved[235];
|
||||
} ext2_super_block_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32_t bg_block_bitmap; // Blocks bitmap block
|
||||
u32_t bg_inode_bitmap; // Inode bitmap block
|
||||
u32_t bg_inode_table; // Inode table block
|
||||
u16_t bg_free_blocks_count; // Free blocks count
|
||||
u16_t bg_free_inodes_count; // Free Inodes count
|
||||
u16_t bg_used_dirs_count; // Directories count
|
||||
u16_t bg_pad1;
|
||||
u32_t bg_reserved[3];
|
||||
} ext2_group_desc_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u16_t i_mode; // File mode
|
||||
u16_t i_uid; // Owner UID
|
||||
u32_t i_size; // Size in bytes
|
||||
u32_t i_atime; // Access time
|
||||
u32_t i_ctime; // Creation time
|
||||
u32_t i_mtime; // Modification time
|
||||
u32_t i_dtime; // Deletion time
|
||||
u16_t i_gid; // Group ID
|
||||
u16_t i_links_count; // Links count
|
||||
u32_t i_blocks; // Blocks count
|
||||
u32_t i_flags; // File flags
|
||||
u32_t i_reserved1;
|
||||
u32_t i_block[15]; // Pointers to blocks (12 direct, single, double, triple indirect)
|
||||
u32_t i_version; // File version (for NFS)
|
||||
u32_t i_file_acl; // File ACL
|
||||
u32_t i_dir_acl; // Directory ACL
|
||||
u32_t i_faddr; // Fragment address
|
||||
u8_t i_frag; // Fragment number
|
||||
u8_t i_fsize; // Fragment size
|
||||
u16_t i_pad1;
|
||||
u32_t i_reserved2[2];
|
||||
} ext2_inode_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32_t inode; // inode number
|
||||
u16_t length; // directory entry length
|
||||
u8_t name_length; // name length
|
||||
u8_t file_type; // File type
|
||||
char name[EXT2_NAME_LEN];
|
||||
} ext2_dir_entry_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ext2_inode_t inode;
|
||||
u32_t block;
|
||||
u32_t *block_pointers;
|
||||
u32_t block_pointers_start;
|
||||
} ext2_open_inode_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ext2_open_inode_t *open_inode;
|
||||
u32_t position;
|
||||
} ext2_open_dir_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ext2_open_inode_t *open_inode;
|
||||
u32_t position;
|
||||
u32_t buffer_start;
|
||||
u32_t buffer_bytes;
|
||||
u8_t *buffer;
|
||||
} ext2__open_file_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ext2_open_inode_t *open_inode;
|
||||
u32_t block;
|
||||
} ext2__open_block_file_t;
|
||||
|
||||
static inline u32_t ext2_diskToFSBlock(u32_t block, ext2_super_block_t *super)
|
||||
{
|
||||
// convert # of disk blocks to # of filesystem blocks
|
||||
return block >> (super->s_log_block_size + 1);
|
||||
}
|
||||
|
||||
static inline u32_t ext2_FSToDiskBlock(u32_t block, ext2_super_block_t *super)
|
||||
{
|
||||
// convert # of filesystem blocks to # of disk blocks
|
||||
return block << (super->s_log_block_size + 1);
|
||||
}
|
||||
|
||||
|
||||
int ext2_init(int fsID);
|
||||
int ext2_read_inode(vfs_mount_t *mount, u32_t inode, ext2_inode_t *dat);
|
||||
int ext2_write_inode(vfs_mount_t *mount, u32_t inode, ext2_inode_t *dat);
|
||||
ext2_group_desc_t ext2_get_group_desc(vfs_mount_t *mount, u32_t group);
|
||||
void ext2_write_group_desc(vfs_mount_t *mount, u32_t group_num, ext2_group_desc_t *gd);
|
||||
ext2_open_inode_t *ext2_open_inode(vfs_mount_t *mount, u32_t inode_number);
|
||||
int ext2_close_inode(vfs_mount_t *mount, ext2_open_inode_t *open_inode);
|
||||
int ext2_read_inode_block(vfs_mount_t *mount, ext2_open_inode_t *open_inode, void *block);
|
||||
u32_t ext2_block_number(vfs_mount_t *mount, ext2_open_inode_t *open_inode);
|
||||
int ext2_inode_seek(vfs_mount_t *mount, ext2_open_inode_t *open_inode, u32_t block_number);
|
||||
|
||||
int ext2_inode_status(vfs_mount_t *mount, u32_t inode_number);
|
||||
int ext2_block_status(vfs_mount_t *mount, u32_t block_number);
|
||||
|
||||
u32_t ext2_alloc_inode(vfs_mount_t *mount);
|
||||
int ext2_free_inode(vfs_mount_t *mount, u32_t inode_number);
|
||||
u32_t ext2_alloc_block(vfs_mount_t *mount);
|
||||
int ext2_free_block(vfs_mount_t *mount, u32_t block_number);
|
||||
|
||||
u32_t ext2_reserve_node(vfs_mount_t *mount, u32_t bitmap_block_num, u32_t bitmap_size);
|
||||
int ext2_free_node(vfs_mount_t *mount, u32_t bitmap_block_num, u32_t node_number);
|
||||
int ext2_num_block_groups(ext2_super_block_t *super);
|
||||
void ext2_write_super(vfs_mount_t *mount);
|
||||
|
||||
int ext2_resize_inode(vfs_mount_t *mount, u32_t inode_number, u32_t new_size);
|
||||
|
||||
ext2_open_dir_t *ext2_open_dir(vfs_mount_t *mount, u32_t inode_number);
|
||||
int ext2_dir_read_entry(vfs_mount_t *mount, ext2_open_dir_t *open_dir, ext2_dir_entry_t *dentry);
|
||||
int ext2_close_dir(vfs_mount_t *mount, ext2_open_dir_t *open_dir);
|
||||
int ext2_dir_lookup(vfs_mount_t *mount, u32_t dir_inode, char *fileName, ext2_dir_entry_t *direntry);
|
||||
|
||||
|
||||
void *ext2_mount_super(major_t major, minor_t minor);
|
||||
int ext2_umount_super(vfs_mount_t *mount);
|
||||
int ext2_stat(vfs_mount_t *mount, u32_t inode_number, vfs_stat_t *stat);
|
||||
u32_t ext2__get_root_dir_inode(vfs_mount_t *mount);
|
||||
int ext2__link_deref(vfs_mount_t *mount, u32_t link_inode, char *link);
|
||||
int ext2__free_inodes(vfs_mount_t *mount);
|
||||
int ext2__total_inodes(vfs_mount_t *mount);
|
||||
int ext2__free_blocks(vfs_mount_t *mount);
|
||||
int ext2__total_blocks(vfs_mount_t *mount);
|
||||
|
||||
|
||||
int ext2__open_dir(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *dir);
|
||||
int ext2__read_dir(vfs_mount_t *mount, vfs_open_file_t *dir, vfs_dir_entry_t *dentry);
|
||||
int ext2__close_dir(vfs_mount_t *mount, vfs_open_file_t *dir);
|
||||
|
||||
int ext2__open_file(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *open_file);
|
||||
int ext2__read_file(vfs_mount_t *mount, vfs_open_file_t *open_file);
|
||||
int ext2__close_file(vfs_mount_t *mount, vfs_open_file_t *open_file);
|
||||
|
||||
int ext2__open_block_file(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *open_file);
|
||||
int ext2__read_block_file(vfs_mount_t *mount, vfs_open_file_t *open_file, void *buffer);
|
||||
int ext2__block_file_seek(vfs_mount_t *mount, vfs_open_file_t *open_file, u32_t block_number);
|
||||
int ext2__close_block_file(vfs_mount_t *mount, vfs_open_file_t *open_file);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,332 @@
|
||||
|
||||
|
||||
// lookup a file name in a directory and store the directory entry for it
|
||||
int ext2_dir_lookup(vfs_mount_t *mount, u32_t dir_inode, char *fileName, ext2_dir_entry_t *direntry)
|
||||
{
|
||||
ext2_open_dir_t *dir = ext2_open_dir(mount, dir_inode);
|
||||
if (!dir)
|
||||
return -1; // bad directory inode number
|
||||
ext2_dir_entry_t dentry;
|
||||
while (!ext2_dir_read_entry(mount, dir, &dentry))
|
||||
{
|
||||
char *dentryName = kcalloc(1, dentry.name_length + 1);
|
||||
memcpy(dentryName, dentry.name, dentry.name_length);
|
||||
int res = strcmp(fileName, dentryName);
|
||||
kfree(dentryName);
|
||||
if (!res)
|
||||
{
|
||||
*direntry = dentry;
|
||||
ext2_close_dir(mount, dir);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
ext2_close_dir(mount, dir);
|
||||
return -2;
|
||||
}
|
||||
|
||||
// open a directory by inode number for reading
|
||||
ext2_open_dir_t *ext2_open_dir(vfs_mount_t *mount, u32_t inode_number)
|
||||
{
|
||||
ext2_open_dir_t *open_dir = New(ext2_open_dir_t);
|
||||
ext2_open_inode_t *open_inode = ext2_open_inode(mount, inode_number);
|
||||
if (!open_inode)
|
||||
{
|
||||
kfree(open_dir);
|
||||
return NULL;
|
||||
}
|
||||
if ((open_inode->inode.i_mode & EXT2_I_MODE_TYPE_MASK) != EXT2_I_MODE_DIR)
|
||||
{
|
||||
ext2_close_inode(mount, open_inode);
|
||||
kfree(open_dir);
|
||||
return NULL;
|
||||
}
|
||||
open_dir->open_inode = open_inode;
|
||||
open_dir->position = 0;
|
||||
return open_dir;
|
||||
}
|
||||
|
||||
int ext2_dir_read_entry(vfs_mount_t *mount, ext2_open_dir_t *open_dir, ext2_dir_entry_t *dentry)
|
||||
{
|
||||
ext2_super_block_t *super = mount->super;
|
||||
if (open_dir->position >= open_dir->open_inode->inode.i_size)
|
||||
return -1; // EOF
|
||||
u32_t dir_block = open_dir->position >> (10 + super->s_log_block_size);
|
||||
char *block = kmalloc(2048 << super->s_log_block_size);
|
||||
ext2_inode_seek(mount, open_dir->open_inode, dir_block);
|
||||
if (ext2_read_inode_block(mount, open_dir->open_inode, block))
|
||||
ext2_read_inode_block(mount, open_dir->open_inode, block + (1024 << super->s_log_block_size));
|
||||
ext2_dir_entry_t *dir_entry = (ext2_dir_entry_t *)(block + open_dir->position % (1024 << super->s_log_block_size));
|
||||
if (!dir_entry->inode)
|
||||
{
|
||||
kfree(block);
|
||||
return -2; // EOF
|
||||
}
|
||||
memcpy(dentry, dir_entry, min(dir_entry->length, sizeof(ext2_dir_entry_t)));
|
||||
open_dir->position += dir_entry->length;
|
||||
kfree(block);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext2_close_dir(vfs_mount_t *mount, ext2_open_dir_t *open_dir)
|
||||
{
|
||||
ext2_close_inode(mount, open_dir->open_inode);
|
||||
kfree(open_dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// open an inode for reading
|
||||
ext2_open_inode_t *ext2_open_inode(vfs_mount_t *mount, u32_t inode_number)
|
||||
{
|
||||
ext2_open_inode_t *open_inode = New(ext2_open_inode_t);
|
||||
if ( ext2_read_inode(mount, inode_number, &(open_inode->inode)) )
|
||||
{
|
||||
kfree(open_inode);
|
||||
return NULL;
|
||||
}
|
||||
open_inode->block = 0;
|
||||
open_inode->block_pointers = NULL;
|
||||
open_inode->block_pointers_start = 0;
|
||||
mount->refs++;
|
||||
return open_inode;
|
||||
}
|
||||
|
||||
|
||||
// seek to a certain block of an open inode
|
||||
int ext2_inode_seek(vfs_mount_t *mount, ext2_open_inode_t *open_inode, u32_t block_number)
|
||||
{
|
||||
ext2_super_block_t *super = mount->super;
|
||||
if (open_inode->inode.i_size <= (block_number << (10 + super->s_log_block_size)))
|
||||
return -1; // at or past EOF
|
||||
open_inode->block = block_number;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// returns number of bytes read
|
||||
int ext2_read_inode_block(vfs_mount_t *mount, ext2_open_inode_t *open_inode, void *block)
|
||||
{
|
||||
ext2_super_block_t *super = mount->super;
|
||||
if (open_inode->inode.i_size <= (open_inode->block << (10 + super->s_log_block_size)))
|
||||
return 0; // at or past EOF
|
||||
u32_t leftover_bytes = open_inode->inode.i_size - (open_inode->block << (10 + super->s_log_block_size));
|
||||
u32_t block_number = ext2_block_number(mount, open_inode);
|
||||
block_read(mount->major, mount->minor, ext2_FSToDiskBlock(block_number, super),
|
||||
2 << super->s_log_block_size, block);
|
||||
open_inode->block++;
|
||||
return min(leftover_bytes, 1024 << super->s_log_block_size);
|
||||
}
|
||||
|
||||
|
||||
// close an open inode
|
||||
int ext2_close_inode(vfs_mount_t *mount, ext2_open_inode_t *open_inode)
|
||||
{
|
||||
mount->refs--;
|
||||
if (open_inode->block_pointers)
|
||||
kfree(open_inode->block_pointers); // free the block pointers cache
|
||||
kfree(open_inode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// transform open_inode->block (a relative block number) to an absolute block number for the filesystem
|
||||
u32_t ext2_block_number(vfs_mount_t *mount, ext2_open_inode_t *open_inode)
|
||||
{
|
||||
if (open_inode->block < 12)
|
||||
return open_inode->inode.i_block[open_inode->block];
|
||||
ext2_super_block_t *super = mount->super;
|
||||
int pointersPerBlock = 256 << super->s_log_block_size;
|
||||
if (open_inode->block_pointers && // there is a block pointers cache block allocated
|
||||
(open_inode->block >= open_inode->block_pointers_start) && // and the block number is in it
|
||||
(open_inode->block < (open_inode->block_pointers_start + pointersPerBlock)))
|
||||
return open_inode->block_pointers[open_inode->block - open_inode->block_pointers_start];
|
||||
u32_t rel_block = open_inode->block - 12;
|
||||
if (!open_inode->block_pointers)
|
||||
open_inode->block_pointers = kmalloc(pointersPerBlock << 2);
|
||||
if (rel_block < pointersPerBlock) // indirect block in i_block[12]
|
||||
{
|
||||
block_read(mount->major, mount->minor, ext2_FSToDiskBlock(open_inode->inode.i_block[12], super),
|
||||
2 << super->s_log_block_size, open_inode->block_pointers);
|
||||
open_inode->block_pointers_start = 12;
|
||||
return open_inode->block_pointers[rel_block];
|
||||
}
|
||||
rel_block -= pointersPerBlock;
|
||||
if (rel_block < (pointersPerBlock * pointersPerBlock)) // double-indirect block in i_block[13]
|
||||
{
|
||||
block_read(mount->major, mount->minor, ext2_FSToDiskBlock(open_inode->inode.i_block[13], super),
|
||||
2 << super->s_log_block_size, open_inode->block_pointers);
|
||||
u32_t real_block = open_inode->block_pointers[rel_block / pointersPerBlock];
|
||||
block_read(mount->major, mount->minor, ext2_FSToDiskBlock(real_block, super),
|
||||
2 << super->s_log_block_size, open_inode->block_pointers);
|
||||
open_inode->block_pointers_start = 12 + pointersPerBlock + rel_block - (rel_block % pointersPerBlock);
|
||||
return open_inode->block_pointers[rel_block % pointersPerBlock];
|
||||
}
|
||||
// this code shouldn't run unless we are dealing with a 65+mb file ...
|
||||
rel_block -= pointersPerBlock * pointersPerBlock;
|
||||
block_read(mount->major, mount->minor, ext2_FSToDiskBlock(open_inode->inode.i_block[14], super),
|
||||
2 << super->s_log_block_size, open_inode->block_pointers);
|
||||
u32_t index_1 = rel_block / (pointersPerBlock * pointersPerBlock);
|
||||
u32_t leftover_1 = rel_block % (pointersPerBlock * pointersPerBlock);
|
||||
u32_t block_1 = open_inode->block_pointers[index_1];
|
||||
block_read(mount->major, mount->minor, ext2_FSToDiskBlock(block_1, super),
|
||||
2 << super->s_log_block_size, open_inode->block_pointers);
|
||||
u32_t index_2 = leftover_1 / pointersPerBlock;
|
||||
u32_t leftover_2 = leftover_1 % pointersPerBlock;
|
||||
u32_t block_2 = open_inode->block_pointers[index_2];
|
||||
block_read(mount->major, mount->minor, ext2_FSToDiskBlock(block_2, super),
|
||||
2 << super->s_log_block_size, open_inode->block_pointers);
|
||||
open_inode->block_pointers_start = 12 + (pointersPerBlock + 1) * pointersPerBlock + rel_block - (rel_block % pointersPerBlock);
|
||||
return open_inode->block_pointers[leftover_2];
|
||||
}
|
||||
|
||||
|
||||
int ext2_resize_inode(vfs_mount_t *mount, u32_t inode_number, u32_t new_size)
|
||||
{
|
||||
ext2_inode_t inode;
|
||||
if ( ext2_read_inode(mount, inode_number, &inode) )
|
||||
return -1;
|
||||
ext2_super_block_t *super = mount->super;
|
||||
int current_blocks = (inode.i_size + (1024 << super->s_log_block_size) - 1) >> (10 + super->s_log_block_size);
|
||||
int new_blocks = (new_size + (1024 << super->s_log_block_size) - 1) >> (10 + super->s_log_block_size);
|
||||
if ( new_blocks == current_blocks )
|
||||
return 0;
|
||||
|
||||
// TODO: resize
|
||||
u32_t block_size = 1024 << super->s_log_block_size;
|
||||
u32_t pointers_per_block = block_size >> 2;
|
||||
u32_t *pointer_cache1 = kmalloc(3 * block_size);
|
||||
u32_t *pointer_cache2 = pointer_cache1 + pointers_per_block;
|
||||
u32_t *pointer_cache3 = pointer_cache2 + pointers_per_block;
|
||||
u32_t c1_start, c2_start, c3_start;
|
||||
c1_start = c2_start = c3_start = 0;
|
||||
while (new_blocks < current_blocks) // delete, decrease current_blocks
|
||||
{
|
||||
current_blocks--;
|
||||
// now delete block number current_blocks
|
||||
|
||||
}
|
||||
|
||||
while (current_blocks < new_blocks) // add, increase current_blocks
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***************** VFS INTERFACE FUNCTIONS *******************/
|
||||
|
||||
|
||||
|
||||
// VFS interface function to open a directory
|
||||
int ext2__open_dir(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *dir)
|
||||
{
|
||||
if (ext2_inode_status(mount, inode_number) != 1)
|
||||
return -1;
|
||||
ext2_open_dir_t *open_dir = ext2_open_dir(mount, inode_number);
|
||||
if (!open_dir)
|
||||
return -2;
|
||||
dir->fs_data = open_dir;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// VFS interface function to read a directory entry from an open directory
|
||||
int ext2__read_dir(vfs_mount_t *mount, vfs_open_file_t *dir, vfs_dir_entry_t *dentry)
|
||||
{
|
||||
ext2_dir_entry_t t_dentry;
|
||||
int status = ext2_dir_read_entry(mount, dir->fs_data, &t_dentry);
|
||||
if (status)
|
||||
return status;
|
||||
memcpy(dentry->name, t_dentry.name, t_dentry.name_length);
|
||||
dentry->name[t_dentry.name_length] = 0;
|
||||
dentry->inode_number = t_dentry.inode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// VFS interface function to close an open directory
|
||||
int ext2__close_dir(vfs_mount_t *mount, vfs_open_file_t *dir)
|
||||
{
|
||||
return ext2_close_dir(mount, dir->fs_data);
|
||||
}
|
||||
|
||||
|
||||
// VFS interface function to open a file for reading a byte at a time
|
||||
int ext2__open_file(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *open_file)
|
||||
{
|
||||
if (ext2_inode_status(mount, inode_number) != 1)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// VFS interface function to read a byte from an open file
|
||||
int ext2__read_file(vfs_mount_t *mount, vfs_open_file_t *open_file)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// VFS interface function to close a byte-file
|
||||
int ext2__close_file(vfs_mount_t *mount, vfs_open_file_t *open_file)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// VFS interface function to open a file for reading 512-byte blocks at a time
|
||||
int ext2__open_block_file(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *open_file)
|
||||
{
|
||||
if (ext2_inode_status(mount, inode_number) != 1)
|
||||
return -1;
|
||||
ext2_open_inode_t *open_inode = ext2_open_inode(mount, inode_number);
|
||||
if (!open_inode)
|
||||
return -2;
|
||||
if ((open_inode->inode.i_mode & EXT2_I_MODE_TYPE_MASK) != EXT2_I_MODE_FILE)
|
||||
{
|
||||
ext2_close_inode(mount, open_inode);
|
||||
return -3;
|
||||
}
|
||||
ext2__open_block_file_t *open_block_file = New(ext2__open_block_file_t);
|
||||
open_block_file->open_inode = open_inode;
|
||||
open_block_file->block = 0;
|
||||
open_file->fs_data = open_block_file;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// VFS interface function to read a block from an open block file
|
||||
// returns the number of bytes read
|
||||
int ext2__read_block_file(vfs_mount_t *mount, vfs_open_file_t *open_file, void *buffer)
|
||||
{
|
||||
ext2_super_block_t *super = mount->super;
|
||||
ext2__open_block_file_t *open_block_file = open_file->fs_data;
|
||||
if (ext2_inode_seek(mount, open_block_file->open_inode, ext2_diskToFSBlock(open_block_file->block, super)))
|
||||
return 0; // EOF
|
||||
u8_t *block = kmalloc(1024 << super->s_log_block_size);
|
||||
u32_t file_position_read = (1024 << super->s_log_block_size) * open_block_file->open_inode->block;
|
||||
u32_t file_position_want = open_block_file->block << 9;
|
||||
u32_t data_offset = file_position_want - file_position_read;
|
||||
int bytes_read = ext2_read_inode_block(mount, open_block_file->open_inode, block);
|
||||
if (bytes_read <= data_offset)
|
||||
{
|
||||
kfree(block);
|
||||
return 0; // EOF
|
||||
}
|
||||
memcpy(buffer, block + data_offset, min(512, bytes_read - data_offset));
|
||||
kfree(block);
|
||||
open_block_file->block++;
|
||||
return min(512, bytes_read - data_offset);
|
||||
}
|
||||
|
||||
// VFS interface function to seek to a certain block number of an open block file
|
||||
int ext2__block_file_seek(vfs_mount_t *mount, vfs_open_file_t *open_file, u32_t block_number)
|
||||
{
|
||||
ext2__open_block_file_t *open_block_file = open_file->fs_data;
|
||||
return ext2_inode_seek(mount, open_block_file->open_inode, ext2_FSToDiskBlock(block_number, mount->super));
|
||||
}
|
||||
|
||||
// VFS interface function to close an open block file
|
||||
int ext2__close_block_file(vfs_mount_t *mount, vfs_open_file_t *open_file)
|
||||
{
|
||||
ext2__open_block_file_t *open_block_file = open_file->fs_data;
|
||||
ext2_close_inode(mount, open_block_file->open_inode);
|
||||
kfree(open_block_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
// ext2.h
|
||||
// Author: Josh Holtrop
|
||||
// Date: 08/22/04
|
||||
// Modified: 12/24/04
|
||||
|
||||
#ifndef __HOS_EXT2_H__
|
||||
#define __HOS_EXT2_H__ __HOS_EXT2_H__
|
||||
|
||||
#include "hos_defines.h"
|
||||
#include "fs/devices.h"
|
||||
#include "fs/vfs.h"
|
||||
|
||||
#define EXT2_MAGIC 0xEF53
|
||||
#define EXT2_NAME_LEN 255
|
||||
|
||||
#define EXT2_I_MODE_ATTR_MASK 0x0FFF
|
||||
#define EXT2_I_MODE_OX 0x0001
|
||||
#define EXT2_I_MODE_OW 0x0002
|
||||
#define EXT2_I_MODE_OR 0x0004
|
||||
#define EXT2_I_MODE_GX 0x0008
|
||||
#define EXT2_I_MODE_GW 0x0010
|
||||
#define EXT2_I_MODE_GR 0x0020
|
||||
#define EXT2_I_MODE_UX 0x0040
|
||||
#define EXT2_I_MODE_UW 0x0080
|
||||
#define EXT2_I_MODE_UR 0x0100
|
||||
#define EXT2_I_MODE_STICKY 0x0200
|
||||
#define EXT2_I_MODE_SGID 0x0400
|
||||
#define EXT2_I_MODE_SUID 0x0800
|
||||
|
||||
#define EXT2_I_MODE_TYPE_MASK 0xF000
|
||||
#define EXT2_I_MODE_FIFO 0x1000
|
||||
#define EXT2_I_MODE_CHAR 0x2000
|
||||
#define EXT2_I_MODE_DIR 0x4000
|
||||
#define EXT2_I_MODE_BLOCK 0x6000
|
||||
#define EXT2_I_MODE_FILE 0x8000
|
||||
#define EXT2_I_MODE_SYM 0xA000
|
||||
#define EXT2_I_MODE_SOCK 0xC000
|
||||
|
||||
#define EXT2_I_FLAGS_SEC_DEL 0x01
|
||||
#define EXT2_I_FLAGS_UNDELETE 0x02
|
||||
#define EXT2_I_FLAGS_COMPRESS 0x04
|
||||
#define EXT2_I_FLAGS_SYNC 0x08
|
||||
#define EXT2_I_FLAGS_IMMUTABLE 0x10
|
||||
#define EXT2_I_FLAGS_APPEND 0x20
|
||||
#define EXT2_I_FLAGS_NODUMP 0x40
|
||||
|
||||
#define EXT2_INODE_BAD_BLOCKS 1
|
||||
#define EXT2_INODE_ROOT 2
|
||||
#define EXT2_INODE_ACL_INDEX 3
|
||||
#define EXT2_INODE_ACL_DATA 4
|
||||
#define EXT2_INODE_BOOT_LOADER 5
|
||||
#define EXT2_INODE_UNDELETE_DIR 6
|
||||
#define EXT2_INODE_AVAIL 11
|
||||
|
||||
#define EXT2_FT_UNKNOWN 0
|
||||
#define EXT2_FT_FILE 1
|
||||
#define EXT2_FT_DIR 2
|
||||
#define EXT2_FT_CHAR 3
|
||||
#define EXT2_FT_BLOCK 4
|
||||
#define EXT2_FT_FIFO 5
|
||||
#define EXT2_FT_SOCK 6
|
||||
#define EXT2_FT_SYMLINK 7
|
||||
#define EXT2_FT_MAX 8
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32_t s_inodes_count; /* Inodes count */
|
||||
u32_t s_blocks_count; /* Blocks count */
|
||||
u32_t s_r_blocks_count; /* Reserved blocks count */
|
||||
u32_t s_free_blocks_count; /* Free blocks count */
|
||||
u32_t s_free_inodes_count; /* Free inodes count */
|
||||
u32_t s_first_data_block; /* First Data Block */
|
||||
u32_t s_log_block_size; /* Block size: 0->1024, 1->2048, 2->4096 */
|
||||
int s_log_frag_size; /* Fragment size */
|
||||
u32_t s_blocks_per_group; /* # Blocks per group */
|
||||
u32_t s_frags_per_group; /* # Fragments per group */
|
||||
u32_t s_inodes_per_group; /* # Inodes per group */
|
||||
u32_t s_mtime; /* Mount time */
|
||||
u32_t s_wtime; /* Write time */
|
||||
u16_t s_mnt_count; /* Mount count */
|
||||
short s_max_mnt_count; /* Maximal mount count */
|
||||
u16_t s_magic; /* Magic signature */
|
||||
u16_t s_state; /* File system state */
|
||||
u16_t s_errors; /* Behaviour when detecting errors */
|
||||
u16_t s_minor_rev_level; /* minor revision level */
|
||||
u32_t s_lastcheck; /* time of last check */
|
||||
u32_t s_checkinterval; /* max. time between checks */
|
||||
u32_t s_creator_os; /* OS */
|
||||
u32_t s_rev_level; /* Revision level */
|
||||
u16_t s_def_resuid; /* Default uid for reserved blocks */
|
||||
u16_t s_def_resgid; /* Default gid for reserved blocks */
|
||||
|
||||
u32_t s_reserved[235];
|
||||
} ext2_super_block_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32_t bg_block_bitmap; // Blocks bitmap block
|
||||
u32_t bg_inode_bitmap; // Inode bitmap block
|
||||
u32_t bg_inode_table; // Inode table block
|
||||
u16_t bg_free_blocks_count; // Free blocks count
|
||||
u16_t bg_free_inodes_count; // Free Inodes count
|
||||
u16_t bg_used_dirs_count; // Directories count
|
||||
u16_t bg_pad1;
|
||||
u32_t bg_reserved[3];
|
||||
} ext2_group_desc_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u16_t i_mode; // File mode
|
||||
u16_t i_uid; // Owner UID
|
||||
u32_t i_size; // Size in bytes
|
||||
u32_t i_atime; // Access time
|
||||
u32_t i_ctime; // Creation time
|
||||
u32_t i_mtime; // Modification time
|
||||
u32_t i_dtime; // Deletion time
|
||||
u16_t i_gid; // Group ID
|
||||
u16_t i_links_count; // Links count
|
||||
u32_t i_blocks; // Blocks count
|
||||
u32_t i_flags; // File flags
|
||||
u32_t i_reserved1;
|
||||
u32_t i_block[15]; // Pointers to blocks (12 direct, single, double, triple indirect)
|
||||
u32_t i_version; // File version (for NFS)
|
||||
u32_t i_file_acl; // File ACL
|
||||
u32_t i_dir_acl; // Directory ACL
|
||||
u32_t i_faddr; // Fragment address
|
||||
u8_t i_frag; // Fragment number
|
||||
u8_t i_fsize; // Fragment size
|
||||
u16_t i_pad1;
|
||||
u32_t i_reserved2[2];
|
||||
} ext2_inode_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32_t inode; // inode number
|
||||
u16_t length; // directory entry length
|
||||
u8_t name_length; // name length
|
||||
u8_t file_type; // File type
|
||||
char name[EXT2_NAME_LEN];
|
||||
} ext2_dir_entry_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ext2_inode_t inode;
|
||||
u32_t block;
|
||||
u32_t *block_pointers;
|
||||
u32_t block_pointers_start;
|
||||
} ext2_open_inode_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ext2_open_inode_t *open_inode;
|
||||
u32_t position;
|
||||
} ext2_open_dir_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ext2_open_inode_t *open_inode;
|
||||
u32_t position;
|
||||
u32_t buffer_start;
|
||||
u32_t buffer_bytes;
|
||||
u8_t *buffer;
|
||||
} ext2__open_file_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ext2_open_inode_t *open_inode;
|
||||
u32_t block;
|
||||
} ext2__open_block_file_t;
|
||||
|
||||
static inline u32_t ext2_diskToFSBlock(u32_t block, ext2_super_block_t *super)
|
||||
{
|
||||
// convert # of disk blocks to # of filesystem blocks
|
||||
return block >> (super->s_log_block_size + 1);
|
||||
}
|
||||
|
||||
static inline u32_t ext2_FSToDiskBlock(u32_t block, ext2_super_block_t *super)
|
||||
{
|
||||
// convert # of filesystem blocks to # of disk blocks
|
||||
return block << (super->s_log_block_size + 1);
|
||||
}
|
||||
|
||||
|
||||
int ext2_init(int fsID);
|
||||
int ext2_read_inode(vfs_mount_t *mount, u32_t inode, ext2_inode_t *dat);
|
||||
int ext2_write_inode(vfs_mount_t *mount, u32_t inode, ext2_inode_t *dat);
|
||||
ext2_group_desc_t ext2_get_group_desc(vfs_mount_t *mount, u32_t group);
|
||||
void ext2_write_group_desc(vfs_mount_t *mount, u32_t group_num, ext2_group_desc_t *gd);
|
||||
ext2_open_inode_t *ext2_open_inode(vfs_mount_t *mount, u32_t inode_number);
|
||||
int ext2_close_inode(vfs_mount_t *mount, ext2_open_inode_t *open_inode);
|
||||
int ext2_read_inode_block(vfs_mount_t *mount, ext2_open_inode_t *open_inode, void *block);
|
||||
u32_t ext2_block_number(vfs_mount_t *mount, ext2_open_inode_t *open_inode);
|
||||
int ext2_inode_seek(vfs_mount_t *mount, ext2_open_inode_t *open_inode, u32_t block_number);
|
||||
|
||||
int ext2_inode_status(vfs_mount_t *mount, u32_t inode_number);
|
||||
int ext2_block_status(vfs_mount_t *mount, u32_t block_number);
|
||||
|
||||
u32_t ext2_alloc_inode(vfs_mount_t *mount);
|
||||
int ext2_free_inode(vfs_mount_t *mount, u32_t inode_number);
|
||||
u32_t ext2_alloc_block(vfs_mount_t *mount);
|
||||
int ext2_free_block(vfs_mount_t *mount, u32_t block_number);
|
||||
|
||||
u32_t ext2_reserve_node(vfs_mount_t *mount, u32_t bitmap_block_num, u32_t bitmap_size);
|
||||
int ext2_free_node(vfs_mount_t *mount, u32_t bitmap_block_num, u32_t node_number);
|
||||
int ext2_num_block_groups(ext2_super_block_t *super);
|
||||
void ext2_write_super(vfs_mount_t *mount);
|
||||
|
||||
int ext2_resize_inode(vfs_mount_t *mount, u32_t inode_number, u32_t new_size);
|
||||
|
||||
ext2_open_dir_t *ext2_open_dir(vfs_mount_t *mount, u32_t inode_number);
|
||||
int ext2_dir_read_entry(vfs_mount_t *mount, ext2_open_dir_t *open_dir, ext2_dir_entry_t *dentry);
|
||||
int ext2_close_dir(vfs_mount_t *mount, ext2_open_dir_t *open_dir);
|
||||
int ext2_dir_lookup(vfs_mount_t *mount, u32_t dir_inode, char *fileName, ext2_dir_entry_t *direntry);
|
||||
|
||||
|
||||
void *ext2_mount_super(major_t major, minor_t minor);
|
||||
int ext2_umount_super(vfs_mount_t *mount);
|
||||
int ext2_stat(vfs_mount_t *mount, u32_t inode_number, vfs_stat_t *stat);
|
||||
u32_t ext2__get_root_dir_inode(vfs_mount_t *mount);
|
||||
int ext2__link_deref(vfs_mount_t *mount, u32_t link_inode, char *link);
|
||||
int ext2__free_inodes(vfs_mount_t *mount);
|
||||
int ext2__total_inodes(vfs_mount_t *mount);
|
||||
int ext2__free_blocks(vfs_mount_t *mount);
|
||||
int ext2__total_blocks(vfs_mount_t *mount);
|
||||
|
||||
|
||||
int ext2__open_dir(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *dir);
|
||||
int ext2__read_dir(vfs_mount_t *mount, vfs_open_file_t *dir, vfs_dir_entry_t *dentry);
|
||||
int ext2__close_dir(vfs_mount_t *mount, vfs_open_file_t *dir);
|
||||
|
||||
int ext2__open_file(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *open_file);
|
||||
int ext2__read_file(vfs_mount_t *mount, vfs_open_file_t *open_file);
|
||||
int ext2__close_file(vfs_mount_t *mount, vfs_open_file_t *open_file);
|
||||
|
||||
int ext2__open_block_file(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *open_file);
|
||||
int ext2__read_block_file(vfs_mount_t *mount, vfs_open_file_t *open_file, void *buffer);
|
||||
int ext2__block_file_seek(vfs_mount_t *mount, vfs_open_file_t *open_file, u32_t block_number);
|
||||
int ext2__close_block_file(vfs_mount_t *mount, vfs_open_file_t *open_file);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// sysfs.cpp
|
||||
// sysfs filesystem driver for HOS
|
||||
// Author: Josh Holtrop
|
||||
// Date: 06/27/05
|
||||
// Modified: 06/27/05
|
||||
|
||||
extern "C" {
|
||||
#include "display/kout.h"
|
||||
}
|
||||
|
||||
#include "fs/vfs.h"
|
||||
#include "sysfs.h"
|
||||
#include "sysfs_entry.h"
|
||||
|
||||
int sysfs_init()
|
||||
{
|
||||
vfs_register("sysfs", sysfs__mount_func);
|
||||
return 0;
|
||||
}
|
||||
|
||||
FileSystem *sysfs__mount_func(device_t dev)
|
||||
{
|
||||
if (dev)
|
||||
kprintf("sysfs: warning: device parameter ignored\n");
|
||||
return new Sysfs();
|
||||
}
|
||||
|
||||
Sysfs::Sysfs()
|
||||
{
|
||||
myEntries.add(Sysfs_Entry(SYSFS_FILE, "timer", SYSFS_TIMER));
|
||||
|
||||
}
|
||||
|
||||
Sysfs::~Sysfs()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
u32_t Sysfs::getRootInodeNumber()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// sysfs.h
|
||||
// sysfs filesystem driver for HOS
|
||||
// Author: Josh Holtrop
|
||||
// Date: 06/27/05
|
||||
// Modified: 06/27/05
|
||||
|
||||
#ifndef __HOS_SYSFS_H__
|
||||
#define __HOS_SYSFS_H__ __HOS_SYSFS_H__
|
||||
|
||||
#define SYSFS_TIMER 1
|
||||
|
||||
#ifdef _HOS_CPP_
|
||||
|
||||
#include "fs/FileSystem.h"
|
||||
#include "fs/vfs.h"
|
||||
#include "lang/vector.h"
|
||||
#include "lang/string.h"
|
||||
#include "sysfs_entry.h"
|
||||
|
||||
int sysfs_init();
|
||||
FileSystem *sysfs__mount_func(device_t dev);
|
||||
|
||||
class Sysfs : public FileSystem
|
||||
{
|
||||
protected:
|
||||
vector<Sysfs_Entry> myEntries;
|
||||
|
||||
public:
|
||||
Sysfs();
|
||||
~Sysfs();
|
||||
u32_t getRootInodeNumber();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// sysfs_entry.cpp
|
||||
// sysfs filesystem driver for HOS
|
||||
// Author: Josh Holtrop
|
||||
// Date: 06/27/05
|
||||
// Modified: 06/27/05
|
||||
|
||||
#include "sysfs_entry.h"
|
||||
#include "lang/string.h"
|
||||
|
||||
Sysfs_Entry::Sysfs_Entry(int type, string name, int id)
|
||||
{
|
||||
myType = type;
|
||||
myName = name;
|
||||
myID = id;
|
||||
}
|
||||
|
||||
Sysfs_Entry::~Sysfs_Entry()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
// sysfs_entry.h
|
||||
// sysfs filesystem driver for HOS
|
||||
// Author: Josh Holtrop
|
||||
// Date: 06/27/05
|
||||
// Modified: 06/27/05
|
||||
|
||||
#ifndef __HOS_SYSFS_ENTRY_H__
|
||||
#define __HOS_SYSFS_ENTRY_H__ __HOS_SYSFS_ENTRY_H__
|
||||
|
||||
#include "lang/vector.h"
|
||||
#include "lang/string.h"
|
||||
|
||||
#define SYSFS_DIR 1
|
||||
#define SYSFS_FILE 2
|
||||
|
||||
class Sysfs_Entry
|
||||
{
|
||||
protected:
|
||||
int myType;
|
||||
string myName;
|
||||
int myID;
|
||||
vector<Sysfs_Entry> myChildren;
|
||||
|
||||
public:
|
||||
Sysfs_Entry(int type, string name, int id);
|
||||
~Sysfs_Entry();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
// vfat.c
|
||||
// Author: Josh Holtrop
|
||||
// Date: 03/11/04
|
||||
// Modified: 03/22/04
|
||||
|
||||
#include "vfat.h"
|
||||
#include "hos_defines.h"
|
||||
#include "fs/vfs.h"
|
||||
#include "mm/vmm.h"
|
||||
#include "lang/cstring.h"
|
||||
|
||||
//From Microsoft's FAT32 File System Specification
|
||||
DSKSZTOSECPERCLUS DskTableFAT16 [] =
|
||||
{
|
||||
{ 8400, 0}, /* disks up to 4.1 MB, the 0 value for SecPerClusVal trips an error */
|
||||
{ 32680, 2}, /* disks up to 16 MB, 1k cluster */
|
||||
{ 262144, 4}, /* disks up to 128 MB, 2k cluster */
|
||||
{ 524288, 8}, /* disks up to 256 MB, 4k cluster */
|
||||
{ 1048576, 16}, /* disks up to 512 MB, 8k cluster */
|
||||
/* The entries after this point are not used unless FAT16 is forced */
|
||||
// { 2097152, 32}, /* disks up to 1 GB, 16k cluster */
|
||||
// { 4194304, 64}, /* disks up to 2 GB, 32k cluster */
|
||||
{ 0xFFFFFFFF, 0} /* any disk greater than 2GB, 0 value for SecPerClusVal trips an error */
|
||||
};
|
||||
|
||||
//From Microsoft's FAT32 File System Specification
|
||||
DSKSZTOSECPERCLUS DskTableFAT32 [] =
|
||||
{
|
||||
{ 66600, 0}, /* disks up to 32.5 MB, the 0 value for SecPerClusVal trips an error */
|
||||
{ 532480, 1}, /* disks up to 260 MB, .5k cluster */
|
||||
{ 16777216, 8}, /* disks up to 8 GB, 4k cluster */
|
||||
{ 33554432, 16}, /* disks up to 16 GB, 8k cluster */
|
||||
{ 67108864, 32}, /* disks up to 32 GB, 16k cluster */
|
||||
{ 0xFFFFFFFF, 64}/* disks greater than 32GB, 32k cluster */
|
||||
};
|
||||
|
||||
int vfat_identify(vfat_bpb *bpb)
|
||||
{
|
||||
int rootDirSectors = ((bpb->rootEntries * 32) + (bpb->bytesPerSector - 1)) / bpb->bytesPerSector;
|
||||
int totalSectors = bpb->totalSectors16 ? bpb->totalSectors16 : bpb->totalSectors32;
|
||||
int fatSectors = bpb->sectorsPerFAT16 ? bpb->sectorsPerFAT16 : bpb->sectorsPerFAT32;
|
||||
int dataSectors = totalSectors - (bpb->reservedSectors + bpb->numFATs * fatSectors + rootDirSectors);
|
||||
int clusters = dataSectors / bpb->sectorsPerCluster;
|
||||
if (clusters < 4085)
|
||||
return 12;
|
||||
if (clusters < 65525)
|
||||
return 16;
|
||||
return 32;
|
||||
}
|
||||
|
||||
|
||||
int vfat_format(Volume *vol)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
FILE *vfat_open(char *fileName, dword attributes, Volume *vol)
|
||||
{
|
||||
while (*fileName == '/')
|
||||
++fileName;
|
||||
if (strlen(fileName) < 1)
|
||||
return 0;
|
||||
vfat_bpb *bpb = vfat_getBootSector(vol);
|
||||
if (!bpb) return 0;
|
||||
byte *fat = vfat_loadFAT(vol, bpb);
|
||||
if (!fat)
|
||||
{
|
||||
free(bpb);
|
||||
return 0;
|
||||
}
|
||||
int segs = string_split(fileName); //number of sections of path (1=file is in root directory)
|
||||
int me = vfat_identify(bpb);
|
||||
if (me != 32)
|
||||
{
|
||||
if (segs == 1) //we are looking for the file in the root directory
|
||||
{
|
||||
vfat_getEntryInRoot(vol, bpb, fileName, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
byte *vfat_loadFAT(Volume *vol, vfat_bpb *bpb)
|
||||
{
|
||||
int fatSize = bpb->sectorsPerFAT16 ? bpb->sectorsPerFAT16 : bpb->sectorsPerFAT32;
|
||||
byte *fat = malloc(fatSize << 9); //512 bytes per sector
|
||||
if (!fat) return 0;
|
||||
if (vfs_readSectorn(vol, bpb->reservedSectors, fat, fatSize))
|
||||
{
|
||||
free(fat);
|
||||
return 0;
|
||||
}
|
||||
return fat;
|
||||
}
|
||||
|
||||
vfat_bpb *vfat_getBootSector(Volume *vol)
|
||||
{
|
||||
vfat_bpb *bs;
|
||||
if (!(bs = malloc(512)))
|
||||
return 0;
|
||||
vfs_readSector(vol, 0, bs);
|
||||
return bs;
|
||||
}
|
||||
|
||||
int vfat_close(FILE *fp)
|
||||
{
|
||||
return free(fp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
// vfat.h
|
||||
// Author: Josh Holtrop
|
||||
// Date: 03/11/04
|
||||
// Modified: 03/22/04
|
||||
|
||||
#ifndef __HOS_VFAT__
|
||||
#define __HOS_VFAT__ __HOS_VFAT__
|
||||
|
||||
#include "hos_defines.h"
|
||||
#include "fs/vfs.h"
|
||||
|
||||
#define VFAT_FAT12_EOCL 0x0FF8 // end-of-cluster chain reached if FatValue >= EOCL
|
||||
#define VFAT_FAT16_EOCL 0xFFF8
|
||||
#define VFAT_FAT32_EOCL 0x0FFFFFF8
|
||||
|
||||
#define VFAT_FAT12_EOC 0x0FFF // end-of-cluster chain value
|
||||
#define VFAT_FAT16_EOC 0xFFFF
|
||||
#define VFAT_FAT32_EOC 0x0FFFFFFF
|
||||
|
||||
#define VFAT_FAT12_BAD 0x0FF7 // bad cluster mark
|
||||
#define VFAT_FAT16_BAD 0xFFF7
|
||||
#define VFAT_FAT32_BAD 0x0FFFFFF7
|
||||
|
||||
#define VFAT_DIRENTRY_FREE 0xE5
|
||||
#define VFAT_DIRENTRY_FREE_LAST 0x00
|
||||
|
||||
typedef struct
|
||||
{
|
||||
byte jmpBoot[3]; // {0xEB, 0x??, 0x90} or {0xE9, 0x??, 0x??}
|
||||
char OEMName[8]; // any 8-char string (def. "MSWIN4.1")
|
||||
word bytesPerSector; // 512 (default), 1024, 2048, 4096
|
||||
byte sectorsPerCluster; // 1 (default), 2, 4, 8, 16, 32, 64, 128
|
||||
word reservedSectors; // 1 (fat12/16), 32 (fat32)
|
||||
byte numFATs; // 2
|
||||
word rootEntries; // number of 32-byte root directory entries (224 for 1440k floppy) - 0 for fat32
|
||||
word totalSectors16; // total number of sectors in volume (2880 for floppy) - 0 for fat32
|
||||
byte media; // >= 0xF0 valid, 0xF8 (default non-removable), 0xF0 (default removable), must match lsb of FAT[0]
|
||||
word sectorsPerFAT16; // number of sectors in FAT (9 for floppy)
|
||||
word sectorsPerTrack; // (18 for floppy)
|
||||
word numHeads; // number of heads (2 for floppy)
|
||||
dword hiddenSectors; // 0
|
||||
dword totalSectors32; // 0, non-zero for fat32 volumes
|
||||
|
||||
/* FAT32 specific members */
|
||||
dword sectorsPerFAT32; // number of sectors in a fat for fat32 volumes
|
||||
word extFlags; // bits 0-3 active fat, bit 7 {0 = mirror all FATs, 1 = only use 1 FAT}
|
||||
word fsVersion; // fat32 version (0:0)
|
||||
dword rootCluster; // first cluster of root directory (default 2)
|
||||
word fsInfo; // sector number of FSINFO block (default 1)
|
||||
word bootCopy; // sector of backup boot record (default 6)
|
||||
} __attribute__ ((packed)) vfat_bpb;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
dword leadSignature; // 0x41615252
|
||||
byte reserved1[480];
|
||||
dword structSignature; // 0x61417272
|
||||
dword lastFree; // last known free cluster (0xFFFFFFFF == unknown)
|
||||
dword nextFree; // start looking for free clusters here (0xFFFFFFFF == unknown)
|
||||
byte reserved2[12];
|
||||
dword trailSignature; // 0xAA550000
|
||||
} __attribute__ ((packed)) vfat_fsinfo;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char fileName[8]; // file name, 8 char. max, pad w/ spaces
|
||||
char fileExt[3]; // file extension, 3 char. max, pad w/ spaces
|
||||
byte attributes; // file attributes, read-only, etc.
|
||||
byte reserved; // 0
|
||||
byte timeTenths; // 0-199
|
||||
word time; // time of creation
|
||||
word date; // date of creation
|
||||
word adate; // last accessed date
|
||||
word clusterHigh; // 0 for fat12/16
|
||||
word wtime; // last write time
|
||||
word wdate; // last write date
|
||||
word clusterLow; // LSW of first cluster of file data
|
||||
dword fileSize;
|
||||
} __attribute__ ((packed)) vfat_dirEntry;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
byte order;
|
||||
word name0_4[5]; // filename - first 5 characters (unicode)
|
||||
byte attributes; // must be VFAT_LONG_NAME
|
||||
byte type; // 0 = part of long name
|
||||
byte checksum; // checksum of short entry at end of long entry set
|
||||
word name5_10[6]; // filename - next 6 characters (unicode)
|
||||
word clusterLow; // 0
|
||||
word name11_12[2]; // filename - next 2 characters
|
||||
} __attribute__ ((packed)) vfat_lfnEntry;
|
||||
|
||||
#define VFAT_READ_ONLY 0x01
|
||||
#define VFAT_HIDDEN 0x02
|
||||
#define VFAT_SYSTEM 0x04
|
||||
#define VFAT_VOLUME 0x08
|
||||
#define VFAT_DIRECTORY 0x10
|
||||
#define VFAT_ARCHIVE 0x20
|
||||
|
||||
#define VFAT_LONG_NAME 0x0F // VFAT_READ_ONLY | VFAT_HIDDEN | VFAT_SYSTEM | VFAT_VOLUME
|
||||
#define VFAT_ATTR_MASK 0x3F // VFAT_READ_ONLY | VFAT_HIDDEN | VFAT_SYSTEM | VFAT_VOLUME | VFAT_DIRECTORY | VFAT_ARCHIVE
|
||||
|
||||
#define VFAT_ORDER_MASK 0x40
|
||||
|
||||
/*
|
||||
* Illegal file name characters:
|
||||
* Values less than 0x20 except for 0x05. 0x05 signifies that the actual filename character is 0xE5
|
||||
* 0x22 ("), 0x2A (*)
|
||||
* 0x2E (.), 0x2F (/), 0x3A (:)
|
||||
* 0x3C (<), 0x3E (>), 0x3F (?), 0x5C (\), 0x7C (|)
|
||||
* The following are illegal in 8.3 but legal in LFN:
|
||||
* 0x2B (+), 0x2C (,), 0x3B (;), 0x3D (=), 0x5B ([), 0x5D (])
|
||||
*/
|
||||
|
||||
//From Microsoft's FAT32 File System Specification
|
||||
typedef struct
|
||||
{
|
||||
dword diskSize;
|
||||
byte sectorsPerCluster;
|
||||
} DSKSZTOSECPERCLUS;
|
||||
|
||||
// sector[510] == 0x55
|
||||
// sector[511] == 0xAA
|
||||
|
||||
int vfat_identify(vfat_bpb *bpb);
|
||||
int vfat_format(Volume *vol);
|
||||
FILE *vfat_open(char *fileName, dword attributes, Volume *vol);
|
||||
vfat_bpb *vfat_getBootSector(Volume *vol);
|
||||
int vfat_close(FILE *fp);
|
||||
byte *vfat_loadFAT(Volume *vol, vfat_bpb *bpb)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+400
-42
@@ -1,55 +1,413 @@
|
||||
|
||||
// vfs.cpp
|
||||
// Virtual file system subsystem for HOS
|
||||
// Author: Josh Holtrop
|
||||
// Date: 03/11/04
|
||||
// Modified: 04/16/04
|
||||
// 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/vfat.h"
|
||||
//#include "block/rd.h"
|
||||
//#include "block/loop.h"
|
||||
#include "lang/LinkedList.h"
|
||||
#include "fs/FileSystem.h"
|
||||
#include "fs/VFSMount.h"
|
||||
#include "fs/ext2/ext2.h"
|
||||
#include "lang/vector.h"
|
||||
#include "lang/string.h"
|
||||
#include "devfs.h"
|
||||
#include "kio.h"
|
||||
#include "Mount.h"
|
||||
#include "devices.h"
|
||||
|
||||
LinkedList<Mount> *mounts;
|
||||
|
||||
void vfs_init()
|
||||
/* 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()
|
||||
{
|
||||
|
||||
mounts = new LinkedList<Mount>;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void list()
|
||||
{
|
||||
LinkedList<Mount>::iterator it = mounts->begin();
|
||||
while (it != mounts->end())
|
||||
{
|
||||
printf("%s\t%s\n", (*it).device.data(), (*it).mountPoint.data());
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int vfs_mount(string device, string mountPoint)
|
||||
{
|
||||
Mount mount(device, mountPoint);
|
||||
LinkedList<Mount>::iterator it = mounts->begin();
|
||||
int i = 0;
|
||||
while (it != mounts->end() && (*it).mountPoint <= mount.mountPoint)
|
||||
{
|
||||
if (*it == mount)
|
||||
return 1; //device already mounted or mount point already taken
|
||||
i++;
|
||||
++it;
|
||||
}
|
||||
mounts->insert(i, mount);
|
||||
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
-19
@@ -1,19 +1,129 @@
|
||||
|
||||
// vfs.h
|
||||
// Author: Josh Holtrop
|
||||
// Date: 03/11/04
|
||||
// Modified: 06/16/04
|
||||
|
||||
#ifndef __HOS_VFS__
|
||||
#define __HOS_VFS__ __HOS_VFS__
|
||||
|
||||
#include "hos_defines.h"
|
||||
#include "lang/string.h"
|
||||
|
||||
void vfs_init();
|
||||
int vfs_mount(string device, string mountPoint);
|
||||
void list();
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// vfs.h
|
||||
// Virtual file system subsystem for HOS
|
||||
// Author: Josh Holtrop
|
||||
// Date: 05/10/05
|
||||
// Modified: 12/26/05
|
||||
|
||||
#ifndef __HOS_VFS_H__
|
||||
#define __HOS_VFS_H__ __HOS_VFS_H__
|
||||
|
||||
#define VFS_FT_UNKNOWN 0
|
||||
#define VFS_FT_FILE 1
|
||||
#define VFS_FT_DIR 2
|
||||
#define VFS_FT_CHAR 3
|
||||
#define VFS_FT_BLOCK 4
|
||||
#define VFS_FT_FIFO 5
|
||||
#define VFS_FT_SOCK 6
|
||||
#define VFS_FT_SYMLINK 7
|
||||
|
||||
#define VFS_PERMS_OX 0x0001
|
||||
#define VFS_PERMS_OW 0x0002
|
||||
#define VFS_PERMS_OR 0x0004
|
||||
#define VFS_PERMS_GX 0x0008
|
||||
#define VFS_PERMS_GW 0x0010
|
||||
#define VFS_PERMS_GR 0x0020
|
||||
#define VFS_PERMS_UX 0x0040
|
||||
#define VFS_PERMS_UW 0x0080
|
||||
#define VFS_PERMS_UR 0x0100
|
||||
#define VFS_PERMS_STICKY 0x0200
|
||||
#define VFS_PERMS_SGID 0x0400
|
||||
#define VFS_PERMS_SUID 0x0800
|
||||
|
||||
#define EOF -256
|
||||
|
||||
#define VFS_MAX_FILENAME 255
|
||||
#define VFS_MAX_PATH_LENGTH 1024
|
||||
|
||||
#define SEEK_ABSOLUTE 0
|
||||
#define SEEK_RELATIVE 1
|
||||
#define SEEK_END 2
|
||||
|
||||
#define VFS_MODE_RW_MASK 0x1
|
||||
#define VFS_MODE_READ 0x0
|
||||
#define VFS_MODE_WRITE 0x1
|
||||
#define VFS_MODE_WRITE_MASK 0x2
|
||||
#define VFS_MODE_TRUNCATE 0x0
|
||||
#define VFS_MODE_APPEND 0x2
|
||||
|
||||
#include "hos_defines.h"
|
||||
#include "devices.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u16_t type; // file type, of VFS_FT_*
|
||||
u32_t size;
|
||||
u32_t inode;
|
||||
u16_t permissions;
|
||||
u16_t uid;
|
||||
u16_t gid;
|
||||
u32_t atime;
|
||||
u32_t mtime;
|
||||
u32_t ctime;
|
||||
u16_t links;
|
||||
u32_t dev;
|
||||
} vfs_stat_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[VFS_MAX_FILENAME + 1];
|
||||
u32_t inum;
|
||||
} vfs_dir_entry_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char fs[16];
|
||||
char mountPoint[256];
|
||||
u32_t totalBlocks;
|
||||
u32_t freeBlocks;
|
||||
u32_t totalInodes;
|
||||
u32_t freeInodes;
|
||||
} vfs_mount_info_t;
|
||||
|
||||
typedef u64_t inode_num_t;
|
||||
|
||||
#ifdef _HOS_CPP_
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int vfs_init();
|
||||
int vfs_mount(device_t device, char *fsType, char *mountPoint);
|
||||
int vfs_umount(device_t dev);
|
||||
int vfs_stat(char *name, vfs_stat_t *buff);
|
||||
int vfs_link_deref(char *name, char *buff);
|
||||
int vfs_get_mount_info(unsigned int mountNum, vfs_mount_info_t *infoptr);
|
||||
void *vfs_open_dir(char *name);
|
||||
void *vfs_open_file(char *name, int mode);
|
||||
void vfs_close_dir(void *o);
|
||||
void vfs_close_file(void *o);
|
||||
int vfs_read_dir(void *o, vfs_dir_entry_t *dirent);
|
||||
int vfs_seek_dir(void *o, int pos, int mode);
|
||||
int vfs_read_file(void *o);
|
||||
int vfs_read_file_block(void *o, void *buf, u32_t num);
|
||||
int vfs_write_file(void *o, int chr);
|
||||
int vfs_write_file_block(void *o, void *buf, u32_t num);
|
||||
int vfs_seek_file(void *o, int pos, int mode);
|
||||
|
||||
|
||||
#ifdef _HOS_CPP_
|
||||
}
|
||||
|
||||
#include "lang/string.h"
|
||||
#include "lang/vector.h"
|
||||
#include "fs/FileSystem.h"
|
||||
#include "fs/VFSMount.h"
|
||||
|
||||
typedef FileSystem *(*mount_func_t)(device_t);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
string name;
|
||||
mount_func_t mount_func;
|
||||
} FSHandle;
|
||||
|
||||
int vfs_register(char *fs, mount_func_t mount_func);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,432 @@
|
||||
// vfs.cpp
|
||||
// Author: Josh Holtrop
|
||||
// Date: 08/22/04
|
||||
// Modified: 12/21/04
|
||||
|
||||
#define _HOS_CPP_ _HOS_CPP_
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "hos_defines.h"
|
||||
#include "display/kout.h"
|
||||
#include "fs/vfs.h"
|
||||
#include "fs/ext2.h"
|
||||
#include "kernel.h"
|
||||
#include "mm/vmm.h"
|
||||
#include "lang/lang.h"
|
||||
}
|
||||
|
||||
|
||||
vfs_fs_t *fses[VFS_MAX_FS]; // a vfs_fs structure for every filesystem we support
|
||||
vfs_mount_t *mounts;
|
||||
|
||||
// basic initialization routine, init all filesystem drivers
|
||||
int vfs_init()
|
||||
{
|
||||
k_check(ext2_init(FS_EXT2), "ext2_init() failed!");
|
||||
FileSystem fs;
|
||||
FileSystem *ext2 = new Ext2();
|
||||
FileSystem *jfs = new JoshsFS();
|
||||
fs.out();
|
||||
ext2->out();
|
||||
jfs->out();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// called by a filesystem driver to let us know that it is ready to handle fs requests
|
||||
int vfs_register_fs(int fsn, vfs_fs_t *fs)
|
||||
{
|
||||
if (fsn < 0 || fsn >= VFS_MAX_FS || fses[fsn])
|
||||
{
|
||||
kprintf("Invalid filesystem register: %d\n", fsn);
|
||||
return -1;
|
||||
}
|
||||
fses[fsn] = fs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// called to mount a block device with a certain filesystem to a part of our VFS Mount Tree
|
||||
int vfs_mount(major_t maj, minor_t min, int fsType, char *mountPoint)
|
||||
{
|
||||
if (fsType < 0 || fsType >= VFS_MAX_FS || !fses[fsType])
|
||||
return -1; // invalid filesystem type
|
||||
if (!strcmp("/", mountPoint))
|
||||
{
|
||||
if (mounts)
|
||||
return -2; // root already mounted
|
||||
void *super = fses[fsType]->mount_super(maj, min);
|
||||
if (!super)
|
||||
return -3; // didn't mount superblock
|
||||
vfs_mount_t *mnt = (vfs_mount_t *) New(vfs_mount_t);
|
||||
mnt->refs = 0;
|
||||
mnt->fs = fsType;
|
||||
mnt->major = maj;
|
||||
mnt->minor = min;
|
||||
mnt->super = super;
|
||||
mnt->next = NULL;
|
||||
mnt->prev = NULL;
|
||||
mnt->mountPoint = (char *) kmalloc(2);
|
||||
strcpy(mnt->mountPoint, mountPoint);
|
||||
mnt->vfs_mount_inode = 0; // root not mounted on another fs
|
||||
mnt->vfs_root_inode = ((vfs_inode_t)maj << 40) | ((vfs_inode_t)min << 32) | fses[fsType]->get_root_inode(mnt);
|
||||
mnt->vfs_up_inode = mnt->vfs_root_inode;
|
||||
mounts = mnt;
|
||||
return 0; // successfully mounted root
|
||||
}
|
||||
if (mountPoint[0] != '/')
|
||||
return -3; // mount point must be absolute
|
||||
if (!mounts)
|
||||
return -4; // no root dir yet
|
||||
vfs_stat_t stat;
|
||||
if (vfs_stat(mountPoint, &stat))
|
||||
return -5; // error statting
|
||||
if (stat.type != VFS_FT_DIR)
|
||||
return -6; // mountPoint not a directory
|
||||
vfs_inode_t vfs_inode = vfs_get_inode_number(mountPoint);
|
||||
vfs_inode_t updir = vfs_entry_lookup(vfs_inode, "..");
|
||||
if (!updir || (updir & 0x8000000000000000ULL))
|
||||
return -7;
|
||||
void *super = fses[fsType]->mount_super(maj, min);
|
||||
if (!super)
|
||||
return -3; // didn't mount superblock
|
||||
vfs_mount_t *mnt = (vfs_mount_t *) New(vfs_mount_t);
|
||||
mnt->refs = 0;
|
||||
mnt->super = super;
|
||||
mnt->fs = fsType;
|
||||
mnt->major = maj;
|
||||
mnt->minor = min;
|
||||
mnt->mountPoint = (char *) kmalloc(strlen(mountPoint) + 1);
|
||||
strcpy(mnt->mountPoint, mountPoint);
|
||||
mnt->vfs_mount_inode = vfs_inode;
|
||||
mnt->vfs_up_inode = updir;
|
||||
mnt->vfs_root_inode = ((vfs_inode_t)maj << 40) | ((vfs_inode_t)min << 32) | fses[fsType]->get_root_inode(mnt);
|
||||
vfs_mount_t *mount = mounts;
|
||||
while (mount->next)
|
||||
mount = mount->next;
|
||||
mount->next = mnt; // add mnt to end of mounts list
|
||||
mnt->prev = mount;
|
||||
mnt->next = NULL;
|
||||
vfs_get_file_addr(updir).mount->refs++;
|
||||
return -256;
|
||||
}
|
||||
|
||||
int vfs_umount(char *mountPoint)
|
||||
{
|
||||
vfs_inode_t vfs_inode = vfs_get_inode_number(mountPoint);
|
||||
if (!vfs_inode || (vfs_inode & 0x8000000000000000ULL))
|
||||
return -1; // invalid
|
||||
vfs_mount_t *mnt = mounts;
|
||||
while (mnt)
|
||||
{
|
||||
if (mnt->vfs_root_inode == vfs_inode) // found mount point to unmount
|
||||
{
|
||||
if (mnt->refs)
|
||||
return -2; // open references to mount point;
|
||||
if (mnt->prev)
|
||||
mnt->prev->next = mnt->next;
|
||||
if (mnt->next)
|
||||
mnt->next->prev = mnt->prev;
|
||||
if (mnt == mounts)
|
||||
mounts = NULL;
|
||||
kfree(mnt->mountPoint);
|
||||
kfree(mnt);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -3; // invalid mount point
|
||||
}
|
||||
|
||||
vfs_inode_t vfs_get_inode_number(char *path)
|
||||
{
|
||||
if (path[0] != '/')
|
||||
return 0;
|
||||
if (!mounts)
|
||||
return 0;
|
||||
return vfs_get_inode_number_rel(mounts->vfs_root_inode, path + 1);
|
||||
}
|
||||
|
||||
vfs_inode_t vfs_get_inode_number_rel(vfs_inode_t dir_inode, char *path)
|
||||
{
|
||||
char *path_copy = (char *) kmalloc(strlen(path) + 1);
|
||||
strcpy(path_copy, path);
|
||||
int stanzas = str_split(path_copy, '/');
|
||||
char *lookup = path_copy;
|
||||
vfs_inode_t vfs_inode = dir_inode;
|
||||
for (; stanzas > 0; stanzas--)
|
||||
{
|
||||
vfs_inode_t vfs_inode_this_dir = vfs_inode;
|
||||
vfs_inode = (strcmp("", lookup) ? vfs_entry_lookup(vfs_inode, lookup) : vfs_inode_this_dir);
|
||||
vfs_stat_t stat;
|
||||
if (vfs_stat_inode(vfs_inode, &stat))
|
||||
return 0x8000000000000002ULL;
|
||||
if (stat.type == VFS_FT_SYMLINK)
|
||||
{
|
||||
char *link = (char *) kmalloc(4096);
|
||||
vfs_link_deref(vfs_inode, link);
|
||||
if (link[0] == '/')
|
||||
vfs_inode = vfs_get_inode_number(link);
|
||||
else
|
||||
vfs_inode = vfs_get_inode_number_rel(vfs_inode_this_dir, link);
|
||||
kfree(link);
|
||||
}
|
||||
if (!vfs_inode || (vfs_inode & 0x8000000000000000ULL))
|
||||
{
|
||||
kfree(path_copy);
|
||||
return 0;
|
||||
}
|
||||
lookup = str_advance(lookup);
|
||||
}
|
||||
kfree(path_copy);
|
||||
return vfs_inode;
|
||||
}
|
||||
|
||||
// look for entry in dir_inode, return the vfs_inode for the entry
|
||||
vfs_inode_t vfs_entry_lookup(vfs_inode_t dir_inode, char *entry)
|
||||
{
|
||||
vfs_open_file_t *open_dir = vfs_open_dir_inode(dir_inode);
|
||||
if (!open_dir)
|
||||
return 0x8000000000000001ULL;
|
||||
vfs_dir_entry_t dentry;
|
||||
while (!vfs_read_dir(open_dir, &dentry))
|
||||
{
|
||||
if (!strcmp(dentry.name, entry))
|
||||
{
|
||||
vfs_close_dir(open_dir);
|
||||
return vfs_real_inode((dir_inode & 0xFFFFFFFF00000000ULL) | dentry.inode_number);
|
||||
}
|
||||
}
|
||||
vfs_close_dir(open_dir);
|
||||
return 0x8000000000000002ULL;
|
||||
}
|
||||
|
||||
// return the "real" vfs inode number (inode of the root of
|
||||
// a mounted filesystem instead of the inode of the folder
|
||||
// that the filesystem is mounted to)
|
||||
vfs_inode_t vfs_real_inode(vfs_inode_t vfs_inode)
|
||||
{
|
||||
vfs_mount_t *mnt = mounts;
|
||||
while (mnt)
|
||||
{
|
||||
if (mnt->vfs_mount_inode == vfs_inode)
|
||||
return mnt->vfs_root_inode;
|
||||
mnt = mnt->next;
|
||||
}
|
||||
return vfs_inode;
|
||||
}
|
||||
|
||||
// translage a vfs inode number into a mount pointer and relative
|
||||
// inode for a mounted filesystem
|
||||
vfs_file_addr_t vfs_get_file_addr(vfs_inode_t vfs_inode)
|
||||
{
|
||||
vfs_inode = vfs_real_inode(vfs_inode);
|
||||
vfs_file_addr_t addr = {mounts, vfs_inode & 0xFFFFFFFF};
|
||||
vfs_mount_t *mnt = mounts;
|
||||
while (mnt)
|
||||
{
|
||||
if ( (mnt->vfs_root_inode & 0xFFFFFFFF00000000ULL) == (vfs_inode & 0xFFFFFFFF00000000ULL) )
|
||||
{
|
||||
addr.mount = mnt;
|
||||
return addr;
|
||||
}
|
||||
mnt = mnt->next;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
int vfs_mount_count()
|
||||
{
|
||||
vfs_mount_t *mnt = mounts;
|
||||
int count = 0;
|
||||
while (mnt)
|
||||
{
|
||||
count++;
|
||||
mnt = mnt->next;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
vfs_mount_t *vfs_get_mount(int index)
|
||||
{
|
||||
vfs_mount_t *mnt = mounts;
|
||||
while (mnt && index)
|
||||
{
|
||||
mnt = mnt->next;
|
||||
index--;
|
||||
}
|
||||
if (!index)
|
||||
return mnt;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int vfs_free_inodes(vfs_mount_t *mount)
|
||||
{
|
||||
if (fses[mount->fs]->free_inodes)
|
||||
return fses[mount->fs]->free_inodes(mount);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int vfs_total_inodes(vfs_mount_t *mount)
|
||||
{
|
||||
if (fses[mount->fs]->total_inodes)
|
||||
return fses[mount->fs]->total_inodes(mount);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int vfs_free_blocks(vfs_mount_t *mount)
|
||||
{
|
||||
if (fses[mount->fs]->free_blocks)
|
||||
return fses[mount->fs]->free_blocks(mount);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int vfs_total_blocks(vfs_mount_t *mount)
|
||||
{
|
||||
if (fses[mount->fs]->total_blocks)
|
||||
return fses[mount->fs]->total_blocks(mount);
|
||||
return -1;
|
||||
}
|
||||
|
||||
vfs_inode_t vfs_alloc_inode(vfs_mount_t *mount)
|
||||
{
|
||||
if (fses[mount->fs]->alloc_inode)
|
||||
{
|
||||
u32_t fs_inode = fses[mount->fs]->alloc_inode(mount);
|
||||
if (!fs_inode)
|
||||
return 0;
|
||||
return (mount->vfs_root_inode & 0xFFFFFFFF00000000ULL) | fs_inode;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vfs_free_inode(vfs_mount_t *mount, u32_t inode_number)
|
||||
{
|
||||
if (fses[mount->fs]->free_inode)
|
||||
return fses[mount->fs]->free_inode(mount, inode_number);
|
||||
return -256;
|
||||
}
|
||||
|
||||
u32_t vfs_alloc_block(vfs_mount_t *mount)
|
||||
{
|
||||
if (fses[mount->fs]->alloc_block)
|
||||
return fses[mount->fs]->alloc_block(mount);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vfs_free_block(vfs_mount_t *mount, u32_t block_number)
|
||||
{
|
||||
if (fses[mount->fs]->free_block)
|
||||
return fses[mount->fs]->free_block(mount, block_number);
|
||||
return -256;
|
||||
}
|
||||
|
||||
int vfs_link_deref(vfs_inode_t vfs_inode, char *link)
|
||||
{
|
||||
vfs_stat_t stat;
|
||||
if (vfs_stat_inode(vfs_inode, &stat))
|
||||
return -1;
|
||||
if (stat.type != VFS_FT_SYMLINK)
|
||||
return -2;
|
||||
vfs_file_addr_t addr = vfs_get_file_addr(vfs_inode);
|
||||
if (fses[addr.mount->fs]->link_deref)
|
||||
return fses[addr.mount->fs]->link_deref(addr.mount, addr.inode, link);
|
||||
return -3;
|
||||
}
|
||||
|
||||
// stat a file, fills a vfs_stat_t structure with stat information and returns standard status
|
||||
int vfs_stat(char *file, vfs_stat_t *stat)
|
||||
{
|
||||
vfs_inode_t vfs_inode = vfs_get_inode_number(file);
|
||||
if (!vfs_inode || (vfs_inode & 0x8000000000000000ULL))
|
||||
return -256;
|
||||
return vfs_stat_inode(vfs_inode, stat);
|
||||
}
|
||||
|
||||
int vfs_stat_inode(vfs_inode_t vfs_inode, vfs_stat_t *stat)
|
||||
{
|
||||
vfs_file_addr_t addr = vfs_get_file_addr(vfs_inode);
|
||||
if (fses[addr.mount->fs]->stat)
|
||||
return fses[addr.mount->fs]->stat(addr.mount, addr.inode, stat);
|
||||
return -257;
|
||||
}
|
||||
|
||||
vfs_open_file_t *vfs_open_dir(char *path)
|
||||
{
|
||||
vfs_inode_t vfs_inode = vfs_get_inode_number(path);
|
||||
if (!vfs_inode || (vfs_inode & 0x8000000000000000ULL))
|
||||
return NULL;
|
||||
return vfs_open_dir_inode(vfs_inode);
|
||||
}
|
||||
|
||||
vfs_open_file_t *vfs_open_dir_inode(vfs_inode_t vfs_inode)
|
||||
{
|
||||
vfs_file_addr_t addr = vfs_get_file_addr(vfs_inode);
|
||||
vfs_open_file_t *open_dir = (vfs_open_file_t *) New(vfs_open_file_t);
|
||||
if (fses[addr.mount->fs]->open_dir && !(fses[addr.mount->fs]->open_dir(addr.mount, addr.inode, open_dir)))
|
||||
{
|
||||
open_dir->mount = addr.mount;
|
||||
return open_dir;
|
||||
}
|
||||
kfree(open_dir);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int vfs_read_dir(vfs_open_file_t *open_dir, vfs_dir_entry_t *dentry)
|
||||
{
|
||||
return !(fses[open_dir->mount->fs]->read_dir &&
|
||||
!(fses[open_dir->mount->fs]->read_dir(open_dir->mount, open_dir, dentry)));
|
||||
}
|
||||
|
||||
int vfs_close_dir(vfs_open_file_t *open_dir)
|
||||
{
|
||||
int status = 0;
|
||||
if (fses[open_dir->mount->fs]->close_dir)
|
||||
status = fses[open_dir->mount->fs]->close_dir(open_dir->mount, open_dir);
|
||||
kfree(open_dir);
|
||||
return status;
|
||||
}
|
||||
|
||||
vfs_open_file_t *vfs_open_block_file(char *path)
|
||||
{
|
||||
vfs_inode_t vfs_inode = vfs_get_inode_number(path);
|
||||
if (!vfs_inode || (vfs_inode & 0x8000000000000000ULL))
|
||||
return NULL;
|
||||
return vfs_open_block_file_inode(vfs_inode);
|
||||
}
|
||||
|
||||
vfs_open_file_t *vfs_open_block_file_inode(vfs_inode_t vfs_inode)
|
||||
{
|
||||
vfs_file_addr_t addr = vfs_get_file_addr(vfs_inode);
|
||||
vfs_open_file_t *open_file = (vfs_open_file_t *) New(vfs_open_file_t);
|
||||
if (fses[addr.mount->fs]->open_block_file && !(fses[addr.mount->fs]->open_block_file(addr.mount, addr.inode, open_file)))
|
||||
{
|
||||
open_file->mount = addr.mount;
|
||||
return open_file;
|
||||
}
|
||||
kfree(open_file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int vfs_read_block_file(vfs_open_file_t *open_file, void *buffer)
|
||||
{
|
||||
if (fses[open_file->mount->fs]->read_block_file)
|
||||
return fses[open_file->mount->fs]->read_block_file(open_file->mount, open_file, buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vfs_block_file_seek(vfs_open_file_t *open_file, u32_t block_number)
|
||||
{
|
||||
if (fses[open_file->mount->fs]->block_file_seek)
|
||||
return fses[open_file->mount->fs]->block_file_seek(open_file->mount, open_file, block_number);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int vfs_close_block_file(vfs_open_file_t *open_file)
|
||||
{
|
||||
int status = 0;
|
||||
if (fses[open_file->mount->fs]->close_block_file)
|
||||
status = fses[open_file->mount->fs]->close_block_file(open_file->mount, open_file);
|
||||
kfree(open_file);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
// vfs.h
|
||||
// Author: Josh Holtrop
|
||||
// Date: 08/22/04
|
||||
// Modified: 12/21/04
|
||||
|
||||
#ifndef __HOS_VFS_H__
|
||||
#define __HOS_VFS_H__ __HOS_VFS_H__
|
||||
|
||||
#include "hos_defines.h"
|
||||
#include "fs/devices.h"
|
||||
|
||||
#define FS_EXT2 1
|
||||
#define VFS_MAX_FS 10
|
||||
|
||||
#define VFS_FT_UNKNOWN 0
|
||||
#define VFS_FT_FILE 1
|
||||
#define VFS_FT_DIR 2
|
||||
#define VFS_FT_CHAR 3
|
||||
#define VFS_FT_BLOCK 4
|
||||
#define VFS_FT_FIFO 5
|
||||
#define VFS_FT_SOCK 6
|
||||
#define VFS_FT_SYMLINK 7
|
||||
|
||||
#define VFS_PERMS_OX 0x0001
|
||||
#define VFS_PERMS_OW 0x0002
|
||||
#define VFS_PERMS_OR 0x0004
|
||||
#define VFS_PERMS_GX 0x0008
|
||||
#define VFS_PERMS_GW 0x0010
|
||||
#define VFS_PERMS_GR 0x0020
|
||||
#define VFS_PERMS_UX 0x0040
|
||||
#define VFS_PERMS_UW 0x0080
|
||||
#define VFS_PERMS_UR 0x0100
|
||||
#define VFS_PERMS_STICKY 0x0200
|
||||
#define VFS_PERMS_SGID 0x0400
|
||||
#define VFS_PERMS_SUID 0x0800
|
||||
|
||||
#define EOF 1000000
|
||||
|
||||
typedef u64_t vfs_inode_t;
|
||||
|
||||
/* Structure to hold information about a mount point */
|
||||
typedef struct vfs_mount_s
|
||||
{
|
||||
int refs;
|
||||
void *super;
|
||||
int fs;
|
||||
major_t major;
|
||||
minor_t minor;
|
||||
char *mountPoint;
|
||||
vfs_inode_t vfs_mount_inode;
|
||||
vfs_inode_t vfs_up_inode;
|
||||
vfs_inode_t vfs_root_inode;
|
||||
struct vfs_mount_s *next;
|
||||
struct vfs_mount_s *prev;
|
||||
} vfs_mount_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u16_t type; // file type, of VFS_FILE_TYPE_*
|
||||
u32_t size;
|
||||
u32_t inode;
|
||||
u16_t permissions;
|
||||
u16_t uid;
|
||||
u16_t gid;
|
||||
u32_t atime;
|
||||
u32_t mtime;
|
||||
u32_t ctime;
|
||||
u16_t links;
|
||||
u32_t dev;
|
||||
} vfs_stat_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vfs_mount_t *mount;
|
||||
void *fs_data;
|
||||
} vfs_open_file_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[257];
|
||||
u32_t inode_number; // relative inode number returned from fs
|
||||
} vfs_dir_entry_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vfs_mount_t *mount;
|
||||
u32_t inode;
|
||||
} vfs_file_addr_t;
|
||||
|
||||
/* Every filesystem must provide pointers to its respective functions in a structure like this */
|
||||
typedef struct
|
||||
{
|
||||
void *(*mount_super)(major_t major, minor_t minor);
|
||||
int (*umount_super)(vfs_mount_t *mount);
|
||||
int (*stat)(vfs_mount_t *mount, u32_t inode_number, vfs_stat_t *stat);
|
||||
u32_t (*get_root_inode)(vfs_mount_t *mount);
|
||||
int (*link_deref)(vfs_mount_t *mount, u32_t inode_number, char *link);
|
||||
int (*free_inodes)(vfs_mount_t *mount);
|
||||
int (*total_inodes)(vfs_mount_t *mount);
|
||||
int (*free_blocks)(vfs_mount_t *mount);
|
||||
int (*total_blocks)(vfs_mount_t *mount);
|
||||
|
||||
u32_t (*alloc_inode)(vfs_mount_t *mount);
|
||||
int (*free_inode)(vfs_mount_t *mount, u32_t inode_number);
|
||||
u32_t (*alloc_block)(vfs_mount_t *mount);
|
||||
int (*free_block)(vfs_mount_t *mount, u32_t block_number);
|
||||
|
||||
int (*open_dir)(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *dir);
|
||||
int (*read_dir)(vfs_mount_t *mount, vfs_open_file_t *dir, vfs_dir_entry_t *dentry);
|
||||
int (*close_dir)(vfs_mount_t *mount, vfs_open_file_t *dir);
|
||||
|
||||
int (*open_file)(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *open_file);
|
||||
int (*read_file)(vfs_mount_t *mount, vfs_open_file_t *open_file);
|
||||
int (*close_file)(vfs_mount_t *mount, vfs_open_file_t *open_file);
|
||||
|
||||
int (*open_block_file)(vfs_mount_t *mount, u32_t inode_number, vfs_open_file_t *open_file);
|
||||
int (*read_block_file)(vfs_mount_t *mount, vfs_open_file_t *open_file, void *buffer);
|
||||
int (*block_file_seek)(vfs_mount_t *mount, vfs_open_file_t *open_file, u32_t block_number);
|
||||
int (*close_block_file)(vfs_mount_t *mount, vfs_open_file_t *open_file);
|
||||
|
||||
} vfs_fs_t;
|
||||
|
||||
|
||||
int vfs_init();
|
||||
int vfs_mount(major_t maj, minor_t min, int fsType, char *mountPoint);
|
||||
int vfs_umount(char *mountPoint);
|
||||
int vfs_register_fs(int fsn, vfs_fs_t *fs);
|
||||
int vfs_umount(char *mountPoint);
|
||||
vfs_inode_t vfs_get_inode_number(char *path);
|
||||
vfs_inode_t vfs_get_inode_number_rel(vfs_inode_t dir_inode, char *path);
|
||||
vfs_inode_t vfs_real_inode(vfs_inode_t vfs_inode);
|
||||
vfs_file_addr_t vfs_get_file_addr(vfs_inode_t vfs_inode);
|
||||
vfs_inode_t vfs_entry_lookup(vfs_inode_t dir_inode, char *entry);
|
||||
|
||||
int vfs_mount_count();
|
||||
vfs_mount_t *vfs_get_mount(int index);
|
||||
int vfs_free_inodes(vfs_mount_t *mount);
|
||||
int vfs_total_inodes(vfs_mount_t *mount);
|
||||
int vfs_free_blocks(vfs_mount_t *mount);
|
||||
int vfs_total_blocks(vfs_mount_t *mount);
|
||||
|
||||
vfs_inode_t vfs_alloc_inode(vfs_mount_t *mount);
|
||||
int vfs_free_inode(vfs_mount_t *mount, u32_t inode_number);
|
||||
u32_t vfs_alloc_block(vfs_mount_t *mount);
|
||||
int vfs_free_block(vfs_mount_t *mount, u32_t block_number);
|
||||
|
||||
|
||||
int vfs_link_deref(vfs_inode_t vfs_inode, char *link);
|
||||
|
||||
int vfs_stat(char *file, vfs_stat_t *stat);
|
||||
int vfs_stat_inode(vfs_inode_t vfs_inode, vfs_stat_t *stat);
|
||||
|
||||
vfs_open_file_t *vfs_open_dir(char *path);
|
||||
vfs_open_file_t *vfs_open_dir_inode(vfs_inode_t inode);
|
||||
int vfs_read_dir(vfs_open_file_t *open_dir, vfs_dir_entry_t *dentry);
|
||||
int vfs_close_dir(vfs_open_file_t *open_dir);
|
||||
|
||||
vfs_open_file_t *vfs_open_block_file(char *file);
|
||||
vfs_open_file_t *vfs_open_block_file_inode(vfs_inode_t vfs_inode);
|
||||
int vfs_read_block_file(vfs_open_file_t *open_file, void *buffer);
|
||||
int vfs_block_file_seek(vfs_open_file_t *open_file, u32_t block_number);
|
||||
int vfs_close_block_file(vfs_open_file_t *open_file);
|
||||
|
||||
#endif
|
||||
|
||||
+31
-14
@@ -9,9 +9,15 @@
|
||||
#include "hos_defines.h"
|
||||
#include "sys/io.h"
|
||||
|
||||
extern dword _code;
|
||||
extern dword _bss;
|
||||
extern dword _end;
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
extern u32_t _code;
|
||||
extern u32_t _bss;
|
||||
extern u32_t _end;
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
//Enables (SeTs) Interrupt Flag on the processor
|
||||
static inline void enable_ints()
|
||||
@@ -47,34 +53,33 @@ static inline void halt()
|
||||
{
|
||||
asm("cli");
|
||||
asm("hlt");
|
||||
while (1);
|
||||
while (1) ;
|
||||
}
|
||||
|
||||
//Initializes 8253 Programmable Interrupt Timer
|
||||
static inline void timer_init()
|
||||
static inline void timer_init(u32_t freq)
|
||||
{
|
||||
//set timer : 2e9c = 100hz
|
||||
u32_t wait = 1193180 / freq; //how many ticks the PIT must wait before issuing an interrupt
|
||||
outportb(0x43, 0x34);
|
||||
outportb(0x40, 0x9c); //lsb
|
||||
outportb(0x40, 0x2e); //msb
|
||||
outportb(0x40, wait); //lsb
|
||||
outportb(0x40, wait >> 8); //msb
|
||||
}
|
||||
|
||||
//Returns the size of the kernel (code & data)
|
||||
// - this does include the bss section
|
||||
//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 dword kernel_size_used()
|
||||
static inline u32_t kernel_size_used()
|
||||
{
|
||||
return (dword)(&_end)-(dword)(&_code);
|
||||
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 dword kernel_size()
|
||||
static inline u32_t kernel_size()
|
||||
{
|
||||
return (dword)(&_bss)-(dword)(&_code);
|
||||
return (u32_t)(&_bss)-(u32_t)(&_code);
|
||||
}
|
||||
|
||||
//converts a binary-coded-decimal byte to its decimal equivalent
|
||||
@@ -89,6 +94,18 @@ 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
|
||||
|
||||
|
||||
+19
-33
@@ -6,65 +6,51 @@
|
||||
gdtr:
|
||||
dw gdt_end-gdt-1
|
||||
dd GDT_V
|
||||
gdt:
|
||||
gdt: ; 0
|
||||
dd 0
|
||||
dd 0
|
||||
KERNEL_CODE equ $-gdt
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
gVESA_CODE equ $-gdt
|
||||
dw 0xffff ;limit 15:0
|
||||
dw 0x0000 ;base 15:0
|
||||
db 0x00 ;base 23:16
|
||||
db 0x9A ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A])
|
||||
db 0x40 ;flags ([G][D/B][0][0]) / limit 19:16
|
||||
db 0x00 ;base 31:24
|
||||
VESA_DATA equ $-gdt
|
||||
dw 0xffff ;limit 15:0
|
||||
dw 0x0000 ;base 15:0
|
||||
db 0x00 ;base 23:16
|
||||
db 0x92 ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A])
|
||||
db 0x40 ;flags ([G][D/B][0][0]) / limit 19:16
|
||||
db 0x00 ;base 31:24
|
||||
VIDEO_TEXT equ $-gdt
|
||||
dw 0x7FFF ;limit 15:0
|
||||
dw 0x8000 ;base 15:0
|
||||
db 0x0B ;base 23:16
|
||||
db 0x92 ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A])
|
||||
db 0x40 ;flags ([G][D/B][0][0]) / limit 19:16
|
||||
db 0x00 ;base 31:24
|
||||
VIDEO_GRAPHICS equ $-gdt
|
||||
dw 0xFFFF ;limit 15:0
|
||||
dw 0x0000 ;base 15:0
|
||||
db 0x0A ;base 23:16
|
||||
db 0x92 ;access ([P][DPL][1][Executable][Direction/Conforming][Writable/Readable][A])
|
||||
db 0x40 ;flags ([G][D/B][0][0]) / limit 19:16
|
||||
db 0x00 ;base 31:24
|
||||
|
||||
TSS0_SEG equ $-gdt ; 40
|
||||
dw 0x67 ;limit 15:0
|
||||
dw 0 ;base 15:0
|
||||
db 0 ;base 23:16
|
||||
db 0xE9 ;access ([P][DPL][0][1][0][Busy][1])
|
||||
db 0x00 ;flags ([G][0][0][AVL]) / limit 19:16
|
||||
db 0 ;base 31:24
|
||||
|
||||
gdt_end:
|
||||
|
||||
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
|
||||
#include "mm/vmm.h"
|
||||
|
||||
//overload the operator "new"
|
||||
void * operator new (dword size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
//overload the operator "new[]"
|
||||
void * operator new[] (dword size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
//overload the operator "delete"
|
||||
void operator delete (void *p)
|
||||
{
|
||||
free(p);
|
||||
}
|
||||
|
||||
//overload the operator "delete[]"
|
||||
void operator delete[] (void *p)
|
||||
{
|
||||
free(p);
|
||||
}
|
||||
|
||||
+43
-33
@@ -1,48 +1,58 @@
|
||||
//hos_defines.h
|
||||
//03/17/03 Josh Holtrop
|
||||
//Modified: 03/02/04
|
||||
// hos_defines.h
|
||||
// Author: Josh Holtrop
|
||||
// Date: 08/15/04
|
||||
// Modified: 08/16/04
|
||||
|
||||
#ifndef __HOS_HOS_DEFINES__
|
||||
#define __HOS_HOS_DEFINES__ __HOS_HOS_DEFINES__
|
||||
#ifndef __HOS_DEFINES_H__
|
||||
#define __HOS_DEFINES_H__ __HOS_DEFINES_H__
|
||||
|
||||
#define FREERAM_START 0x368000 // 0x368000 is first available byte (this is right after the initrd @ 2mb, 1440kb.
|
||||
#define MAX_RAM 0x40000000 //1gb maximum RAM supported
|
||||
#define PARALLEL_DEBUG
|
||||
|
||||
#define PID_KERNEL 0x02 //kernel's PID
|
||||
#define PID_VMM 0x03
|
||||
#define PID_USER 0x10000 //user processes' start PID
|
||||
#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
|
||||
|
||||
//these defines are the memory locations of values saved by the stage 2 bootloader
|
||||
#define BOOT_MEMMAP_ENTRIES 0xC009040A
|
||||
#define BOOT_FIRST_MEMMAP 0xC0092000
|
||||
#define BOOT_VIDEO_MODE 0xC0090002
|
||||
#define BOOT_VIDEO_MODE_INFO_BLOCK 0xC0090306
|
||||
#define BOOT_HASRD 0xC0090000
|
||||
#define CONSOLE_MEMORY 0xC00B8000
|
||||
#define BIOS_CHAR_MAP 0xC00FFA6E
|
||||
#define LFB_MEMORY 0xF0000000
|
||||
|
||||
#define NULL 0
|
||||
#define SEG_KERNEL_CODE 8
|
||||
#define SEG_KERNEL_DATA 16
|
||||
#define SEG_USER_CODE 24
|
||||
#define SEG_USER_DATA 32
|
||||
#define SEG_TSS0 40
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef unsigned short word;
|
||||
typedef unsigned int dword;
|
||||
#define MAX_MODULES 16
|
||||
#define MAX_MMAP 16
|
||||
|
||||
typedef struct {
|
||||
dword lowdword;
|
||||
dword highdword;
|
||||
} __attribute__((packed)) qword;
|
||||
#define NULL 0
|
||||
|
||||
//overload the operator "new"
|
||||
void * operator new (dword size);
|
||||
#define HOS_INIT_TASK "/bin/init"
|
||||
|
||||
//overload the operator "new[]"
|
||||
void * operator new[] (dword size);
|
||||
#define New(x) kcalloc(1, sizeof(x))
|
||||
|
||||
//overload the operator "delete"
|
||||
void operator delete (void *p);
|
||||
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;
|
||||
|
||||
//overload the operator "delete[]"
|
||||
void operator delete[] (void *p);
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
extern u32_t _end;
|
||||
extern u32_t _bss;
|
||||
extern u32_t start;
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+39
-39
@@ -1,7 +1,7 @@
|
||||
;idt.inc
|
||||
;Author: Josh Holtrop
|
||||
;Date: 10/30/03
|
||||
;Modified: 03/02/04
|
||||
;Modified: 01/02/06
|
||||
|
||||
idtr:
|
||||
dw 50*8-1 ;size of idt
|
||||
@@ -67,51 +67,51 @@ isr_label 48
|
||||
isr_label 49
|
||||
|
||||
isr_main:
|
||||
cmp eax, 0x30
|
||||
jz isr_syscall
|
||||
|
||||
pusha
|
||||
push ds
|
||||
push es
|
||||
|
||||
; 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
|
||||
|
||||
call _isr
|
||||
|
||||
add esp, 4
|
||||
|
||||
pop es
|
||||
pop ds
|
||||
popa
|
||||
mov eax, [esp+8]
|
||||
mov [esp+4], eax
|
||||
pop eax
|
||||
|
||||
iret
|
||||
|
||||
|
||||
isr_syscall:
|
||||
pop eax ;syscall function number
|
||||
pusha
|
||||
isr_main_nodup:
|
||||
push ebx
|
||||
push ecx
|
||||
push edx
|
||||
push edi
|
||||
push esi
|
||||
push ebp
|
||||
push ds
|
||||
push es
|
||||
push fs
|
||||
push gs
|
||||
|
||||
sc1:
|
||||
cmp eax, 1 ;syscall 1 - putc
|
||||
jnz sc2
|
||||
push ebx
|
||||
call _putc
|
||||
add esp, 4
|
||||
jmp scdone
|
||||
sc2:
|
||||
push esp
|
||||
push eax ;interrupt number
|
||||
call isr
|
||||
add esp, 8
|
||||
|
||||
scdone:
|
||||
pop gs
|
||||
pop fs
|
||||
pop es
|
||||
pop ds
|
||||
popa
|
||||
pop ebp
|
||||
pop esi
|
||||
pop edi
|
||||
pop edx
|
||||
pop ecx
|
||||
pop ebx
|
||||
add esp, 4 ;bypass error code
|
||||
pop eax ;original saved eax
|
||||
|
||||
iret
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
;kernel.asm
|
||||
;Author: Josh Holtrop
|
||||
;Date: 10/30/03
|
||||
;Modified: 10/30/03
|
||||
|
||||
%define GDT_P 0x100000; ;1mb physical - Global Descriptor Table space
|
||||
%define GDT_V GDT_P+0xC0000000
|
||||
%define IDT_P 0x102000 ;1mb+8kb - Interrupt Descriptor Table space
|
||||
%define IDT_V IDT_P+0xC0000000
|
||||
%define PDBR_P 0x104000 ;1mb+16kb - Page Directory Base Register (first PD)
|
||||
%define PDBR_V PDBR_P+0xC0000000
|
||||
%define LOPT_P 0x105000 ;1mb+20kb - LOw Page Table for mapping first 4mb
|
||||
%define LOPT_V LOPT_P+0xC0000000
|
||||
%define KERNEL_P 0x106000 ;1mb+24kb - the kernel's physical address
|
||||
%define KERNEL_V KERNEL_P+0xC0000000 ;3gb+1mb+24kb, the virtual address of the kernel
|
||||
|
||||
[global _start]
|
||||
[extern _isr]
|
||||
[extern _k_init]
|
||||
[extern _putc]
|
||||
|
||||
bits 32
|
||||
|
||||
;This is where the kernel begins execution
|
||||
;At this point, the temporary gdt is set up to "map" 0xC000_0000 to 0x0.
|
||||
;We must 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.
|
||||
;Then we can start using our "real" gdt, then unmap the lower 4mb.
|
||||
_start:
|
||||
cli ;if they weren't already off
|
||||
|
||||
xor eax, eax
|
||||
mov edi, PDBR_V
|
||||
mov ecx, 1024 ;clear the PDBR
|
||||
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 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
|
||||
copy_gdt:
|
||||
lodsb
|
||||
stosb
|
||||
loop copy_gdt
|
||||
|
||||
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
|
||||
|
||||
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, 0xc0200000 ;stack just under 3gb+2mb, moves downward
|
||||
lidt [idtr] ;load idt
|
||||
|
||||
call _k_init
|
||||
haltit:
|
||||
hlt ;halt processor when k_init is done
|
||||
jmp haltit ;shouldn't get here...
|
||||
|
||||
%include "gdt.inc"
|
||||
%include "idt.inc"
|
||||
|
||||
|
||||
+288
@@ -0,0 +1,288 @@
|
||||
/* kernel.h
|
||||
* Author: Josh Holtrop
|
||||
* Date: 08/16/04
|
||||
* Modified: 11/02/05
|
||||
* This is the main kernel initialization and boot-strapping file
|
||||
*/
|
||||
|
||||
#include "kernel.h"
|
||||
#include "multiboot.h"
|
||||
#include "module.h"
|
||||
#include "lang/lang.h"
|
||||
#include "functions.h"
|
||||
#include "mm/mm.h"
|
||||
#include "mm/vmm.h"
|
||||
#include "lang/conv.h"
|
||||
#include "devices.h"
|
||||
#include "display/display.h"
|
||||
#include "display/kout.h"
|
||||
#include "sys/io.h"
|
||||
#include "sys/pic.h"
|
||||
#include "char/keyboard.h"
|
||||
#include "block/ramdisk.h"
|
||||
#include "fs/vfs.h"
|
||||
#include "fs/ext2/ext2.h"
|
||||
#include "sys/pci.h"
|
||||
#include "proc/proc.h"
|
||||
#include "syscall.h"
|
||||
|
||||
mb_info_t mb_info_block;
|
||||
mb_mmap_t mb_mmap[MAX_MMAP];
|
||||
u32_t mmap_entries;
|
||||
mb_module_t mb_modules[MAX_MODULES];
|
||||
mb_apm_t mb_apm_table;
|
||||
mb_module_t *real_mode_module; // pointer to real mode module (if present)
|
||||
real_mode_param_t rm_params;
|
||||
char mb_cmdline[256];
|
||||
int criticalCounter; // semaphore for if interrupts are disabled
|
||||
u32_t timer; // number of IRQ 0's
|
||||
|
||||
extern u32_t mm_freepages;
|
||||
extern u32_t proc_new_esp;
|
||||
extern u32_t cur_task;
|
||||
|
||||
/* This function runs in segmented memory - 0xC000_0000 is mapped to 0x0 but 0x0
|
||||
itself is an invalid linear address. Therefore, the multiboot information addresses
|
||||
must be manually adjusted by VIRT_OFFSET to become valid linear addresses. */
|
||||
mb_module_t *k_mbsave(mb_info_t *mbinfo, unsigned int mb_magic)
|
||||
{
|
||||
real_mode_module = NULL;
|
||||
if (mb_magic != MULTIBOOT_BOOTLOADER_MAGIC)
|
||||
{
|
||||
char *msg = "Bad multiboot magic identifier!";
|
||||
char *dest = (char *) CONSOLE_MEMORY;
|
||||
while (*msg)
|
||||
{
|
||||
*dest++ = *msg++;
|
||||
*dest++ = 0x04; //red error message
|
||||
}
|
||||
for (;;) ;
|
||||
}
|
||||
mb_info_block = *mbinfo;
|
||||
if (mb_info_block.flags & MB_BOOTLOADER_COMMAND_LINE)
|
||||
{
|
||||
mb_info_block.cmdline += VIRT_OFFSET;
|
||||
memcpy(mb_cmdline, (void *)mb_info_block.cmdline, 256);
|
||||
mb_cmdline[255] = 0;
|
||||
}
|
||||
if (mb_info_block.flags & MB_BOOTLOADER_MODS)
|
||||
{
|
||||
mb_info_block.mods_addr += VIRT_OFFSET;
|
||||
int i;
|
||||
for (i = 0; i < mb_info_block.mods_count && i < MAX_MODULES; i++)
|
||||
{
|
||||
mb_modules[i] = ((mb_module_t *)mb_info_block.mods_addr)[i];
|
||||
mb_modules[i].mod_start += VIRT_OFFSET;
|
||||
mb_modules[i].mod_end += VIRT_OFFSET;
|
||||
hos_module_header_t *mod = (hos_module_header_t *)mb_modules[i].mod_start;
|
||||
if (mod->mod_magic == 0x4D534F48 && mod->mod_type == MOD_REAL_MODE)
|
||||
real_mode_module = &mb_modules[i];
|
||||
}
|
||||
}
|
||||
if (mb_info_block.flags & MB_BOOTLOADER_MMAP)
|
||||
{
|
||||
mb_info_block.mmap_addr += (VIRT_OFFSET - 4); //-4 to get to size field, not base_addr_low field
|
||||
mb_mmap_t *mmap = (mb_mmap_t *)mb_info_block.mmap_addr;
|
||||
int i, sz = 0;
|
||||
for (i = 0; sz < mb_info_block.mmap_length && i < MAX_MMAP; i++)
|
||||
{
|
||||
sz += mmap->size + 4;
|
||||
mb_mmap[i] = *mmap;
|
||||
mmap = (mb_mmap_t *)(((u32_t) mmap) + mmap->size + 4);
|
||||
mmap_entries++;
|
||||
}
|
||||
}
|
||||
if (mb_info_block.flags & MB_BOOTLOADER_APM)
|
||||
{
|
||||
mb_info_block.apm_table += VIRT_OFFSET;
|
||||
mb_apm_table = *(mb_apm_t *)mb_info_block.apm_table;
|
||||
}
|
||||
return real_mode_module;
|
||||
}
|
||||
|
||||
/* Main kernel initialization routine */
|
||||
void k_init()
|
||||
{
|
||||
criticalCounter++;
|
||||
pic_remap(0x20, 0x28);
|
||||
pic_mask1(0); //unmask IRQ's 0-7
|
||||
pic_mask2(0); //unmask IRQ's 8-15
|
||||
timer_init(HOS_TIMER_FREQ);
|
||||
mm_init();
|
||||
vmm_init();
|
||||
devices_init();
|
||||
if (real_mode_module)
|
||||
{
|
||||
if (rm_params.vid_addr) // there is video memory to map in
|
||||
{
|
||||
u32_t vid_mem = rm_params.width * rm_params.height;
|
||||
switch (rm_params.bpp)
|
||||
{
|
||||
case 15: case 16:
|
||||
vid_mem <<= 1; break;
|
||||
case 24:
|
||||
vid_mem *= 3; break;
|
||||
case 32:
|
||||
vid_mem <<= 2; break;
|
||||
}
|
||||
// map in video memory so we can access the video card's LFB
|
||||
vmm_mapn(LFB_MEMORY, (u32_t)rm_params.vid_addr, (vid_mem >> 12) + 1);
|
||||
}
|
||||
}
|
||||
display_init(); // initialize display subsystem
|
||||
kprintf("HOS v0.16 initializing...\n");
|
||||
kprintf("Kernel load line: '%s'\n", mb_cmdline);
|
||||
kprintf("Kernel load size: %d (0x%x) bytes (%d kb)\n", kernel_size(), kernel_size(), kernel_size() >> 10);
|
||||
kprintf("Kernel memory size: %d (0x%x) bytes (%d kb)\n", kernel_size_used(), kernel_size_used(), kernel_size_used() >> 10);
|
||||
|
||||
k_check(pci_init(), "pci_init() failed!");
|
||||
k_check(vfs_init(), "vfs_init() failed!");
|
||||
k_check(proc_init(), "proc_init() failed!");
|
||||
|
||||
int i;
|
||||
for (i = 0; i < mb_info_block.mods_count; i++)
|
||||
{
|
||||
kprintf("Loaded kernel module %d: 0x%x - 0x%x (%d bytes, type %d)\n", i, mb_modules[i].mod_start, mb_modules[i].mod_end, mb_modules[i].mod_end - mb_modules[i].mod_start, ((hos_module_header_t*)mb_modules[i].mod_start)->mod_type);
|
||||
if (((mb_modules[i].mod_end - mb_modules[i].mod_start) > 2048) &&
|
||||
((ext2_super_block_t *)(mb_modules[i].mod_start + 1024))->s_magic == EXT2_MAGIC)
|
||||
{
|
||||
// we found an initrd
|
||||
minor_t initrd_minor = ramdisk_register((void *)mb_modules[i].mod_start, mb_modules[i].mod_end - mb_modules[i].mod_start);
|
||||
kprintf("initrd (%dkb) loaded\n", (mb_modules[i].mod_end - mb_modules[i].mod_start) >> 10);
|
||||
k_check(vfs_mount(DEV(MAJOR_RAMDISK, initrd_minor), "ext2", "/"), "Kernel panic: Could not mount initrd to /!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void *root = vfs_open_dir("///");
|
||||
char name[VFS_MAX_PATH_LENGTH];
|
||||
if (root)
|
||||
{
|
||||
vfs_dir_entry_t dentry;
|
||||
vfs_stat_t fstat;
|
||||
while (!vfs_read_dir(root, &dentry))
|
||||
{
|
||||
strcpy(name, "/");
|
||||
strcat(name, dentry.name);
|
||||
vfs_stat(name, &fstat);
|
||||
kprintf("%d\t", fstat.inode);
|
||||
putc(fstat.type == VFS_FT_DIR ? 'd' : fstat.type == VFS_FT_CHAR ? 'c' : fstat.type == VFS_FT_BLOCK ? 'b' : fstat.type == VFS_FT_SYMLINK ? 'l' : '-');
|
||||
putc(fstat.permissions & VFS_PERMS_UR ? 'r' : '-');
|
||||
putc(fstat.permissions & VFS_PERMS_UW ? 'w' : '-');
|
||||
putc(fstat.permissions & VFS_PERMS_UX ? 'x' : '-');
|
||||
|
||||
putc(fstat.permissions & VFS_PERMS_GR ? 'r' : '-');
|
||||
putc(fstat.permissions & VFS_PERMS_GW ? 'w' : '-');
|
||||
putc(fstat.permissions & VFS_PERMS_GX ? 'x' : '-');
|
||||
|
||||
putc(fstat.permissions & VFS_PERMS_OR ? 'r' : '-');
|
||||
putc(fstat.permissions & VFS_PERMS_OW ? 'w' : '-');
|
||||
putc(fstat.permissions & VFS_PERMS_OX ? 'x' : '-');
|
||||
|
||||
kprintf(" %d\t%d\t%d\t%d\t%s", fstat.links, fstat.uid, fstat.gid, fstat.size, dentry.name);
|
||||
if (fstat.type == VFS_FT_CHAR || fstat.type == VFS_FT_BLOCK)
|
||||
kprintf("\t(%d, %d)", fstat.dev >> 8, fstat.dev & 0xFF);
|
||||
if (fstat.type == VFS_FT_SYMLINK)
|
||||
{
|
||||
char *link = kmalloc(4096);
|
||||
vfs_link_deref(name, link);
|
||||
kprintf(" -> %s", link);
|
||||
kfree(link);
|
||||
}
|
||||
putc('\n');
|
||||
}
|
||||
vfs_close_dir(root);
|
||||
}
|
||||
else
|
||||
kprintf("Error: Could not open directory\n");
|
||||
|
||||
/* Create the initial task */
|
||||
vfs_stat_t stat;
|
||||
if (!vfs_stat(HOS_INIT_TASK, &stat))
|
||||
{
|
||||
if (stat.permissions &
|
||||
(VFS_PERMS_UX | VFS_PERMS_GX | VFS_PERMS_UX))
|
||||
{
|
||||
u8_t *buf = kmalloc(stat.size);
|
||||
void *file = vfs_open_file(HOS_INIT_TASK, VFS_MODE_READ);
|
||||
vfs_read_file_block(file, buf, stat.size);
|
||||
vfs_close_file(file);
|
||||
create_task(buf, stat.size, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
criticalCounter--;
|
||||
}
|
||||
|
||||
void isr(u32_t num, int_stack_t *int_stack)
|
||||
{
|
||||
criticalCounter++;
|
||||
switch (num)
|
||||
{
|
||||
case 0x0: /* divide by zero */
|
||||
kprintf("divide by zero, current process: %u\n", cur_task);
|
||||
break;
|
||||
case 0x20: // timer
|
||||
timer++;
|
||||
(*(u16_t *)CONSOLE_MEMORY)++;
|
||||
proc_sched(int_stack);
|
||||
pic_eoi();
|
||||
break;
|
||||
case 0x21: // keyboard
|
||||
isr_keyboard();
|
||||
pic_eoi();
|
||||
break;
|
||||
case 0x30:
|
||||
syscall(cur_task, int_stack);
|
||||
break;
|
||||
case 0x0D: /* general protection (error code) */
|
||||
kprintf("General protection fault process %u, error #%u\n", cur_task, int_stack->error);
|
||||
break;
|
||||
case 0x0E: /* Page fault (error code) */
|
||||
kprintf("Page fault process %u, error #%u\n", cur_task, int_stack->error);
|
||||
break;
|
||||
case 0x01: /* debug exception */
|
||||
case 0x02: /* non-maskable interrupt */
|
||||
case 0x03: /* breakpoint */
|
||||
case 0x04: /* overflow */
|
||||
case 0x05: /* bound exception */
|
||||
case 0x06: /* invalid opcode */
|
||||
case 0x07: /* FPU not available */
|
||||
case 0x08: /* Double fault (error code) */
|
||||
case 0x09: /* coprocessor segment overrun */
|
||||
case 0x0A: /* invalid TSS (error code) */
|
||||
case 0x0B: /* segment not present (error code) */
|
||||
case 0x0C: /* stack exception (error code) */
|
||||
case 0x10: /* floating point error */
|
||||
case 0x11: /* alignment check */
|
||||
case 0x12: /* machine check */
|
||||
default:
|
||||
kprintf("Unhandled interrupt #%d, CR2 = 0x%x, int_stack at 0x%x!\n", num, read_cr2(), int_stack);
|
||||
halt();
|
||||
}
|
||||
criticalCounter--;
|
||||
}
|
||||
|
||||
|
||||
void k_enter_critical() // functions for implementing "atomic actions"
|
||||
{
|
||||
disable_ints();
|
||||
criticalCounter++;
|
||||
}
|
||||
|
||||
void k_leave_critical()
|
||||
{
|
||||
criticalCounter--;
|
||||
if (!criticalCounter)
|
||||
enable_ints();
|
||||
}
|
||||
|
||||
void k_check(int val, char *msg)
|
||||
{
|
||||
if (val)
|
||||
{
|
||||
kprintf("\e[31;1m%s\n", msg);
|
||||
halt();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
// kernel.c
|
||||
// Author: Josh Holtrop
|
||||
// Date: 08/13/03
|
||||
// Holtrop's Operating System - Version 0.13
|
||||
// Modified: 03/08/04
|
||||
|
||||
#include "hos_defines.h" //#DEFINE's for kernel
|
||||
|
||||
#include "functions.h" //general functions
|
||||
#include "asmfuncs.h" //assembly functions
|
||||
#include "kio.h" //kernel input/output functions
|
||||
#include "mm/mm.h" //physical memory management functions
|
||||
#include "mm/vmm.h" //virtual memory management & paging functions
|
||||
#include "char/keyboard.h" //generic keyboard driver & functions
|
||||
#include "char/mouse.h" //generic ps/2 mouse driver & functions
|
||||
#include "block/fdc.h" //Floppy Disk Controller functions
|
||||
#include "sys/cmos.h" //CMOS interface functions
|
||||
#include "sys/io.h" //port i/o functions
|
||||
#include "sys/pic.h" //Programmable Interrupt Controller functions
|
||||
#include "sys/rtc.h" //Real Time Clock functions
|
||||
#include "video/video.h" //video functions
|
||||
#include "fs/vfs.h" //Virtual File System layer
|
||||
#include "fs/devfs.h" //Device filesystem
|
||||
|
||||
extern "C" {
|
||||
|
||||
void isr(dword num);
|
||||
void k_init();
|
||||
|
||||
dword timer = 0;
|
||||
|
||||
//Main kernel initialization method
|
||||
void k_init()
|
||||
{
|
||||
// ===== Initialization
|
||||
fdc_sendDOR(0x0C); //turn off floppy motor!!
|
||||
mm_init();
|
||||
vmm_init();
|
||||
video_init();
|
||||
kio_init();
|
||||
kio_console_cls();
|
||||
pic_remap(0x20, 0x28);
|
||||
timer_init();
|
||||
mouse_init();
|
||||
pic_mask1(0); //unmask IRQ's 0-7
|
||||
pic_mask2(0); //unmask IRQ's 8-15
|
||||
enable_ints();
|
||||
kbd_resetLEDs(); //after enabling interrupts!!
|
||||
if (video_Mode())
|
||||
{
|
||||
int w = video_getWidth(), h = video_getHeight();
|
||||
int p = w * h - 1;
|
||||
for (; p >= 0; p--)
|
||||
video_pseti(p, 0x00000075);
|
||||
int x = w >> 1, y = h >> 1, sz = h >> 1;
|
||||
for (p = 0; p <= sz; p += 24)
|
||||
{
|
||||
video_line(x + p, y, x, y + sz - p, 0x0000FF00);
|
||||
video_line(x + p, y, x, y - sz + p, 0x0000FF00);
|
||||
video_line(x - p, y, x, y + sz - p, 0x0000FF00);
|
||||
video_line(x - p, y, x, y - sz + p, 0x0000FF00);
|
||||
}
|
||||
kio_drawConsole();
|
||||
}
|
||||
|
||||
printf("HOS 0.14 - Kernel File Size: %uKb Mem Used: %uKb\n", kernel_size()>>10, kernel_size_used()>>10);
|
||||
printf("Memory available to OS: %u MB (%u bytes)\n", mm_getTotalMegs(), mm_getTotalMem());
|
||||
printf("Free memory: %u bytes (%u pages)\n", mm_freemem(), mm_freemem()>>12);
|
||||
printf("Built on %s at %s\n", __DATE__, __TIME__);
|
||||
printf("%b/%b/%b %b:%b:%b\n", rtc_readMonth(), rtc_readDay(), rtc_readYear(), rtc_readHour(), rtc_readMinute(), rtc_readSecond());
|
||||
|
||||
vfs_init();
|
||||
devfs_init("/dev");
|
||||
list();
|
||||
|
||||
printf("Done.\n");
|
||||
|
||||
dword key = 0;
|
||||
for (;;)
|
||||
{
|
||||
key = kbdWaitKey();
|
||||
if ((key & 0xFF) > 2) //key is not a control key
|
||||
putc(key);
|
||||
}
|
||||
}
|
||||
|
||||
// main Interrupt Service Routine - handles all interrupts unless caught by kernel.asm
|
||||
void isr(dword num)
|
||||
{
|
||||
switch(num)
|
||||
{
|
||||
case 14:
|
||||
printf("Page fault, CR2 = 0x%x\n", read_cr2());
|
||||
{
|
||||
enable_ints();
|
||||
for (;;) ; //infinetly loop so that my KVM will still work :) 06/10/04
|
||||
}
|
||||
// halt();
|
||||
break;
|
||||
case 0x20: // IRQ0 - timer interrupt
|
||||
timer++;
|
||||
(*(byte *)(0xc00b8000))++;
|
||||
if (!(timer % 100))
|
||||
{
|
||||
dword curPos = kio_getCursorPosition();
|
||||
kio_writeCursorPosition(72);
|
||||
printf("%b:%b:%b\n", rtc_readHour(), rtc_readMinute(), rtc_readSecond());
|
||||
kio_writeCursorPosition(curPos);
|
||||
}
|
||||
pic_eoi();
|
||||
break;
|
||||
case 0x21: // IRQ1 - keyboard interrupt
|
||||
isr_keyboard(); //isr_keybard() takes care of calling eoi()
|
||||
break;
|
||||
case 0x2C: // IRQ12 - PS/2 mouse
|
||||
isr_mouse();
|
||||
pic_eoi2();
|
||||
break;
|
||||
default:
|
||||
printf("Interrupt %d (0x%x) Unhandled!!\n", num, num);
|
||||
halt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
-227
@@ -1,227 +0,0 @@
|
||||
// kio.c
|
||||
// Author: Josh Holtrop
|
||||
// Created: 12/25/03
|
||||
// Modified: 04/06/04
|
||||
|
||||
#include "hos_defines.h"
|
||||
#include "kio.h"
|
||||
#include "asmfuncs.h"
|
||||
#include "video/video.h"
|
||||
|
||||
dword graphical;
|
||||
dword cursorPosition; //Caches the current cursor position
|
||||
word console_memory[2000]; //holds a copy of the console's memory
|
||||
|
||||
// This is the main output routine, it uses a format string and a variable
|
||||
// number of arguments to print formatted text
|
||||
extern "C" {
|
||||
|
||||
void kio_init()
|
||||
{
|
||||
graphical = video_Mode();
|
||||
cursorPosition = 0;
|
||||
writeCursorPosition(0);
|
||||
}
|
||||
|
||||
void printf(char *fmt, ...)
|
||||
{
|
||||
dword *params = ((dword *)(&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 '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 draws a single character
|
||||
void putc(dword chr)
|
||||
{
|
||||
char charac = (char)chr;
|
||||
word *vidmem = (word *)0xC00B8000;
|
||||
if (charac == '\n')
|
||||
{
|
||||
if (cursorPosition % 80)
|
||||
cursorPosition = cursorPosition + 80 - (cursorPosition % 80);
|
||||
else
|
||||
cursorPosition += 80;
|
||||
}
|
||||
else if (charac == '\t')
|
||||
{
|
||||
if (cursorPosition % 8)
|
||||
cursorPosition = cursorPosition + 8 - (cursorPosition % 8);
|
||||
else
|
||||
cursorPosition += 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (graphical)
|
||||
{
|
||||
console_memory[cursorPosition] = charac | 0x0700;
|
||||
kio_drawConsoleChar(cursorPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
console_memory[cursorPosition] = charac | 0x0700;
|
||||
vidmem[cursorPosition] = charac | 0x0700;
|
||||
}
|
||||
cursorPosition++;
|
||||
}
|
||||
if (cursorPosition >= 2000)
|
||||
{
|
||||
kio_console_scroll();
|
||||
cursorPosition = 2000-80;
|
||||
}
|
||||
if (!graphical)
|
||||
writeCursorPosition(cursorPosition);
|
||||
}
|
||||
|
||||
|
||||
// This function displays a number in hexadecimal
|
||||
void putHex(dword number)
|
||||
{
|
||||
int hitNum = 0;
|
||||
int i;
|
||||
for (i = 7; i >= 0; i--)
|
||||
{
|
||||
dword val = (number >> (i*4)) & 0xF;
|
||||
if ((val != 0) || (i == 0))
|
||||
hitNum = 1;
|
||||
if (hitNum)
|
||||
{
|
||||
val = val + '0';
|
||||
if (val > '9')
|
||||
val = val + ('A' - '9' - 1);
|
||||
putc(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void kio_putBCD(dword bcd)
|
||||
{
|
||||
putc(((bcd & 0xF0) >> 4) + '0');
|
||||
putc((bcd & 0xF) + '0');
|
||||
}
|
||||
|
||||
|
||||
void kio_console_scroll()
|
||||
{
|
||||
memcpyd(console_memory, console_memory + 80, 960);
|
||||
memsetw(console_memory + 1920, 0x0720, 80);
|
||||
if (graphical)
|
||||
kio_drawConsole();
|
||||
else
|
||||
memcpyd((void *)0xC00B8000, console_memory, 1000);
|
||||
}
|
||||
|
||||
|
||||
void kio_console_cls()
|
||||
{
|
||||
memsetw(console_memory, 0x0720, 2000);
|
||||
if (graphical)
|
||||
kio_drawConsole();
|
||||
else
|
||||
memcpyd((void *)0xC00B8000, console_memory, 1000);
|
||||
writeCursorPosition(0);
|
||||
}
|
||||
|
||||
|
||||
// This function draws a simple "console" window in graphical mode to display text
|
||||
void kio_drawConsole()
|
||||
{
|
||||
video_rectf(8, 8, 491, 261, 0);
|
||||
video_rect(7, 7, 492, 262, 0x00777777);
|
||||
int x, y;
|
||||
x = 250, y = 135;
|
||||
int s = 100, p = 0;
|
||||
for (p = 0; p <= s; p += 16)
|
||||
{
|
||||
video_line(x + p, y, x, y + s - p, 0x00008800);
|
||||
video_line(x + p, y, x, y - s + p, 0x00008800);
|
||||
video_line(x - p, y, x, y + s - p, 0x00008800);
|
||||
video_line(x - p, y, x, y - s + p, 0x00008800);
|
||||
}
|
||||
|
||||
for (x = 0; x < 80; x++)
|
||||
{
|
||||
for (y = 0; y < 25; y++)
|
||||
{
|
||||
video_renderChar(x*6+10, y*10+10, console_memory[y*80+x], 0, 0x00FFFFFF, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This function draws a "console" character to the graphical video screen
|
||||
void kio_drawConsoleChar(dword position)
|
||||
{
|
||||
int x = position % 80;
|
||||
int y = position / 80;
|
||||
video_renderChar(x*6+10, y*10+10, console_memory[y*80+x], 0, 0x00FFFFFF, 1, 0);
|
||||
}
|
||||
|
||||
|
||||
dword kio_getCursorPosition()
|
||||
{
|
||||
return cursorPosition;
|
||||
}
|
||||
|
||||
void kio_writeCursorPosition(dword position)
|
||||
{
|
||||
cursorPosition = position;
|
||||
if (!graphical)
|
||||
writeCursorPosition(position);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
// kio.h
|
||||
// Author: Josh Holtrop
|
||||
// Created: 12/25/03
|
||||
// Modified: 05/21/04
|
||||
|
||||
#ifndef __HOS_KIO__
|
||||
#define __HOS_KIO__ __HOS_KIO__
|
||||
|
||||
#include "hos_defines.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
void kio_init();
|
||||
void printf(char *fmt, ...);
|
||||
void putc(dword chr);
|
||||
void putHex(dword number);
|
||||
void kio_drawConsole();
|
||||
void kio_drawConsoleChar(dword position);
|
||||
void kio_console_scroll();
|
||||
void kio_console_cls();
|
||||
void kio_putBCD(dword bcd);
|
||||
dword kio_getCursorPosition();
|
||||
void kio_writeCursorPosition(dword position);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,210 +0,0 @@
|
||||
|
||||
// LinkedList.h
|
||||
// implements a LinkedList container for HOS
|
||||
// Author: Josh Holtrop
|
||||
// Date: 05/22/04
|
||||
// Modified: 06/09/04
|
||||
|
||||
#ifndef __HOS_LINKEDLIST__
|
||||
#define __HOS_LINKEDLIST__ __HOS_LINKEDLIST__
|
||||
|
||||
template <typename Element>
|
||||
class LinkedList
|
||||
{
|
||||
private:
|
||||
class LinkedNode
|
||||
{
|
||||
public:
|
||||
LinkedNode()
|
||||
{
|
||||
prev = next = 0;
|
||||
}
|
||||
LinkedNode(Element dataElement)
|
||||
{
|
||||
data = dataElement;
|
||||
prev = next = 0;
|
||||
}
|
||||
Element data;
|
||||
LinkedNode *next;
|
||||
LinkedNode *prev;
|
||||
};
|
||||
|
||||
LinkedNode *firstNode;
|
||||
LinkedNode *lastNode;
|
||||
int count;
|
||||
|
||||
public:
|
||||
class iterator
|
||||
{
|
||||
private:
|
||||
LinkedNode *theNode;
|
||||
public:
|
||||
iterator(LinkedNode & node)
|
||||
{
|
||||
theNode = &node;
|
||||
}
|
||||
iterator(LinkedNode *node)
|
||||
{
|
||||
theNode = node;
|
||||
}
|
||||
Element & operator*()
|
||||
{
|
||||
return theNode->data;
|
||||
}
|
||||
void operator++() //prefix
|
||||
{
|
||||
theNode = theNode->next;
|
||||
}
|
||||
void operator++(int dum) //postfix
|
||||
{
|
||||
theNode = theNode->next;
|
||||
}
|
||||
bool operator==(const iterator & second) const
|
||||
{ return theNode == second.theNode; }
|
||||
bool operator!=(const iterator & second) const
|
||||
{ return theNode != second.theNode; }
|
||||
};
|
||||
|
||||
class reverse_iterator
|
||||
{
|
||||
private:
|
||||
LinkedNode *theNode;
|
||||
public:
|
||||
reverse_iterator(LinkedNode & node)
|
||||
{
|
||||
theNode = &node;
|
||||
}
|
||||
reverse_iterator(LinkedNode *node)
|
||||
{
|
||||
theNode = node;
|
||||
}
|
||||
Element & operator*()
|
||||
{
|
||||
return theNode->data;
|
||||
}
|
||||
void operator++() //prefix
|
||||
{
|
||||
theNode = theNode->prev;
|
||||
}
|
||||
void operator++(int dum) //postfix
|
||||
{
|
||||
theNode = theNode->prev;
|
||||
}
|
||||
bool operator==(const reverse_iterator & second) const
|
||||
{ return theNode == second.theNode; }
|
||||
bool operator!=(const reverse_iterator & second) const
|
||||
{ return theNode != second.theNode; }
|
||||
};
|
||||
|
||||
/* Basic constructor */
|
||||
LinkedList();
|
||||
|
||||
/* How many elements in the list */
|
||||
int size() { return count; }
|
||||
|
||||
/* Return some iterators for traversing the list */
|
||||
iterator begin() { return iterator(firstNode->next); }
|
||||
iterator end() { return iterator(lastNode->next); }
|
||||
reverse_iterator rbegin() { return reverse_iterator(lastNode); }
|
||||
reverse_iterator rend() { return reverse_iterator(firstNode); }
|
||||
|
||||
/* Insert an element, its position will be index */
|
||||
LinkedList & insert(int index, Element e);
|
||||
|
||||
/* Append an element to the end of the list */
|
||||
LinkedList & push_back(Element e);
|
||||
|
||||
/* Remove an element at position index */
|
||||
LinkedList & remove(int index);
|
||||
|
||||
/* Pop an element from the end of the list */
|
||||
LinkedList & pop_back();
|
||||
|
||||
/* Direct access to an element in the list */
|
||||
Element & operator[](int index);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
LinkedList<T>::LinkedList()
|
||||
{
|
||||
firstNode = lastNode = new LinkedNode(); //head node
|
||||
count = 0;
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
LinkedList<Element> & LinkedList<Element>::insert(int index, Element e)
|
||||
{
|
||||
if (index == count)
|
||||
push_back(e);
|
||||
else if (index >= 0 && index < count)
|
||||
{
|
||||
LinkedNode *nptr = firstNode;
|
||||
for (int i = 0; i <= index; i++)
|
||||
nptr = nptr->next;
|
||||
LinkedNode *newptr = new LinkedNode(e);
|
||||
newptr->next = nptr;
|
||||
newptr->prev = nptr->prev;
|
||||
newptr->prev->next = newptr;
|
||||
nptr->prev = newptr;
|
||||
count++;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
LinkedList<Element> & LinkedList<Element>::push_back(Element e)
|
||||
{
|
||||
lastNode->next = new LinkedNode(e);
|
||||
lastNode->next->prev = lastNode;
|
||||
lastNode = lastNode->next;
|
||||
count++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
LinkedList<Element> & LinkedList<Element>::remove(int index)
|
||||
{
|
||||
if (index == count-1)
|
||||
pop_back();
|
||||
else if (index >= 0 && index < count)
|
||||
{
|
||||
LinkedNode *nptr = firstNode;
|
||||
for (int i = 0; i <= index; i++)
|
||||
nptr = nptr->next;
|
||||
nptr->prev->next = nptr->next;
|
||||
nptr->next->prev = nptr->prev;
|
||||
delete nptr;
|
||||
count--;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
LinkedList<Element> & LinkedList<Element>::pop_back()
|
||||
{
|
||||
if (count)
|
||||
{
|
||||
lastNode = lastNode->prev;
|
||||
delete lastNode->next;
|
||||
lastNode->next = 0;
|
||||
count--;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
Element & LinkedList<Element>::operator[](int index)
|
||||
{
|
||||
if (index >= 0 && index < count)
|
||||
{
|
||||
LinkedNode *nptr = firstNode;
|
||||
for (int i = 0; i <= index; i++)
|
||||
nptr = nptr->next;
|
||||
return nptr->data;
|
||||
}
|
||||
return firstNode->data;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
// conv.h
|
||||
// Author: Josh Holtrop
|
||||
// Date: 08/02/04
|
||||
// Modified: 12/30/04
|
||||
|
||||
#include "conv.h"
|
||||
#include "hos_defines.h"
|
||||
|
||||
// BCD to string
|
||||
// returns number of characters generated before null terminator
|
||||
int bcdtoa(u32_t bcd, char *buf)
|
||||
{
|
||||
*buf++ = ((bcd & 0xF0) >> 4) + '0';
|
||||
*buf++ = (bcd & 0xF) + '0';
|
||||
*buf = 0;
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
// convert integer to hexadecimal string
|
||||
int itox(u32_t num, char *buf)
|
||||
{
|
||||
int s, i = 0;
|
||||
for (s = 28; s >= 0; s -= 4)
|
||||
{
|
||||
u32_t val = (num >> s) & 0xF;
|
||||
if (i || val || (!s))
|
||||
{
|
||||
val = (val > 9) ? (val + 'A' - 10) : (val + '0');
|
||||
buf[i++] = val;
|
||||
}
|
||||
}
|
||||
buf[i] = 0;
|
||||
return i - 1;
|
||||
}
|
||||
|
||||
|
||||
// convert integer to an octal string
|
||||
int itoo(u32_t num, char *buf)
|
||||
{
|
||||
int s, i = 0;
|
||||
for (s = 30; s >= 0; s -= 3)
|
||||
{
|
||||
u32_t val = (num >> s) & 0x7;
|
||||
if (i || val || (!s))
|
||||
buf[i++] = val + '0';
|
||||
}
|
||||
buf[i] = 0;
|
||||
return i - 1;
|
||||
}
|
||||
|
||||
|
||||
// convert signed integer to decimal string
|
||||
int itoa(int num, char *buf)
|
||||
{
|
||||
// 4,294,967,296
|
||||
int hitNum = 0, i = 0, mod, val;
|
||||
if (num < 0)
|
||||
{
|
||||
buf[i++] = '-';
|
||||
num = -num;
|
||||
}
|
||||
for (mod = 1000000000; mod >= 1; mod /= 10)
|
||||
{
|
||||
val = num / mod;
|
||||
num %= mod;
|
||||
if (val || (mod == 1))
|
||||
hitNum = 1;
|
||||
if (hitNum)
|
||||
{
|
||||
buf[i++] = val + '0';
|
||||
}
|
||||
}
|
||||
buf[i] = 0;
|
||||
return i - 1;
|
||||
}
|
||||
|
||||
|
||||
// convert an unsigned integer to decimal string
|
||||
int utoa(u32_t num, char *buf)
|
||||
{
|
||||
// 4,294,967,296
|
||||
int hitNum = 0, i = 0, mod, val;
|
||||
for (mod = 1000000000; mod >= 1; mod /= 10)
|
||||
{
|
||||
val = num / mod;
|
||||
num %= mod;
|
||||
if (val || (mod == 1))
|
||||
hitNum = 1;
|
||||
if (hitNum)
|
||||
{
|
||||
buf[i++] = val + '0';
|
||||
}
|
||||
}
|
||||
buf[i] = 0;
|
||||
return i - 1;
|
||||
}
|
||||
|
||||
|
||||
char asciiSwitchCase(char chr)
|
||||
{
|
||||
if (chr >= 'A' && chr <= 'Z')
|
||||
return chr + ('a' - 'A');
|
||||
if (chr >= 'a' && chr <= 'z')
|
||||
return chr - ('a' - 'A');
|
||||
return chr;
|
||||
}
|
||||
|
||||
|
||||
Loaded 100 of 151 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user