5650 - support a second OS: soso
https://github.com/ozkl/soso + Much smaller than Linux; builds instantly + Supports graphics - No network support - Doesn't work on a cloud server (yet?)
This commit is contained in:
parent
ded2b24ce2
commit
46bb1d3157
54
Readme.md
54
Readme.md
|
@ -9,10 +9,10 @@ to run, and nothing else.
|
|||
```sh
|
||||
$ git clone https://github.com/akkartik/mu
|
||||
$ cd mu
|
||||
# package up a "hello world" binary and Linux kernel into mu.iso
|
||||
$ ./gen_iso examples/ex6.subx
|
||||
# package up a "hello world" binary and kernel into mu_soso.iso
|
||||
$ ./gen_soso_iso init.soso examples/ex6.subx
|
||||
# try it out
|
||||
$ qemu-system-x86_64 -m 256M -cdrom mu.iso -boot d
|
||||
$ qemu-system-i386 -cdrom mu_soso.iso
|
||||
# print the message
|
||||
```
|
||||
|
||||
|
@ -61,7 +61,7 @@ code. Here's a program (`examples/ex1.subx`) that returns 42:
|
|||
You can generate tiny zero-dependency ELF binaries with it that run on Linux.
|
||||
|
||||
```sh
|
||||
$ ./subx translate examples/ex1.subx -o examples/ex1 # on Linux or BSD or Mac
|
||||
$ ./subx translate init.linux examples/ex1.subx -o examples/ex1 # on Linux or BSD or Mac
|
||||
$ ./examples/ex1 # only on Linux
|
||||
$ echo $?
|
||||
42
|
||||
|
@ -82,7 +82,7 @@ messages.
|
|||
Emulated runs can generate a trace that permits [time-travel debugging](https://github.com/akkartik/mu/blob/master/browse_trace/Readme.md).
|
||||
|
||||
```sh
|
||||
$ ./subx --debug translate examples/factorial.subx -o examples/factorial
|
||||
$ ./subx --debug translate init.linux examples/factorial.subx -o examples/factorial
|
||||
saving address->label information to 'labels'
|
||||
saving address->source information to 'source_lines'
|
||||
|
||||
|
@ -104,23 +104,23 @@ You can use SubX to translate itself. For example, running natively on Linux:
|
|||
|
||||
```sh
|
||||
# generate translator phases using the C++ translator
|
||||
$ ./subx translate 0*.subx apps/subx-common.subx apps/hex.subx -o hex
|
||||
$ ./subx translate 0*.subx apps/subx-common.subx apps/survey.subx -o survey
|
||||
$ ./subx translate 0*.subx apps/subx-common.subx apps/pack.subx -o pack
|
||||
$ ./subx translate 0*.subx apps/subx-common.subx apps/assort.subx -o assort
|
||||
$ ./subx translate 0*.subx apps/subx-common.subx apps/dquotes.subx -o dquotes
|
||||
$ ./subx translate 0*.subx apps/subx-common.subx apps/tests.subx -o tests
|
||||
$ ./subx translate init.linux 0*.subx apps/subx-common.subx apps/hex.subx -o hex
|
||||
$ ./subx translate init.linux 0*.subx apps/subx-common.subx apps/survey.subx -o survey
|
||||
$ ./subx translate init.linux 0*.subx apps/subx-common.subx apps/pack.subx -o pack
|
||||
$ ./subx translate init.linux 0*.subx apps/subx-common.subx apps/assort.subx -o assort
|
||||
$ ./subx translate init.linux 0*.subx apps/subx-common.subx apps/dquotes.subx -o dquotes
|
||||
$ ./subx translate init.linux 0*.subx apps/subx-common.subx apps/tests.subx -o tests
|
||||
$ chmod +x hex survey pack assort dquotes tests
|
||||
|
||||
# use the generated translator phases to translate SubX programs
|
||||
$ cat examples/ex1.subx |./tests |./dquotes |./assort |./pack |./survey |./hex > a.elf
|
||||
$ cat init.linux examples/ex1.subx |./tests |./dquotes |./assort |./pack |./survey |./hex > a.elf
|
||||
$ chmod +x a.elf
|
||||
$ ./a.elf
|
||||
$ echo $?
|
||||
42
|
||||
|
||||
# or, automating the above steps
|
||||
$ ./ntranslate ex1.subx
|
||||
$ ./ntranslate init.linux ex1.subx
|
||||
$ chmod +x a.elf
|
||||
$ ./a.elf
|
||||
$ echo $?
|
||||
|
@ -130,27 +130,32 @@ You can use SubX to translate itself. For example, running natively on Linux:
|
|||
Or, running in a VM on other platforms:
|
||||
|
||||
```sh
|
||||
$ ./translate ex1.subx # generates identical a.elf to above
|
||||
$ ./translate init.linux ex1.subx # generates identical a.elf to above
|
||||
$ ./subx run a.elf
|
||||
$ echo $?
|
||||
42
|
||||
```
|
||||
|
||||
Finally, as described at the top, you can turn it into a bootable disk image
|
||||
containing just your code and a Linux kernel. You can run the disk image on a
|
||||
cloud server that supports custom images. [Instructions for Linode.](http://akkartik.name/post/iso-on-linode)
|
||||
As described at the start, you can package up SubX binaries with the minimal
|
||||
hobbyist OS [soso](https://github.com/ozkl/soso) and run them on Qemu.
|
||||
(Requires graphics. Currently doesn't work on a cloud server.)
|
||||
|
||||
```sh
|
||||
$ ./gen_soso_iso init.soso examples/ex6.subx
|
||||
$ qemu-system-i386 -cdrom mu_soso.iso
|
||||
```
|
||||
|
||||
You can also package up SubX binaries with a Linux kernel and run them on
|
||||
either Qemu or [a cloud server that supports custom images](http://akkartik.name/post/iso-on-linode).
|
||||
(Takes 12 minutes with 8GB RAM. Requires 12 million LoC of C for the Linux
|
||||
kernel; that number will gradually go down.)
|
||||
|
||||
```sh
|
||||
$ sudo apt install build-essential flex bison wget libelf-dev libssl-dev xorriso
|
||||
$ ./gen_iso examples/ex6.subx
|
||||
$ ./gen_linux_iso init.linux examples/ex6.subx
|
||||
$ qemu-system-x86_64 -m 256M -cdrom mu.iso -boot d
|
||||
```
|
||||
|
||||
(`gen_iso` only came into existence 2019-08-09, and has a flabby laundry list
|
||||
of dependencies that I will gradually prune. It currently takes 12 minutes to
|
||||
run on a single core with 8 GB RAM, mostly to compile its fork of the Linux
|
||||
kernel.)
|
||||
|
||||
## What it looks like
|
||||
|
||||
Here is the above example again:
|
||||
|
@ -306,7 +311,7 @@ like decimal numbers.
|
|||
Try running this example now:
|
||||
|
||||
```sh
|
||||
$ ./subx translate examples/ex3.subx -o examples/ex3
|
||||
$ ./subx translate init.linux examples/ex3.subx -o examples/ex3
|
||||
$ ./subx run examples/ex3
|
||||
$ echo $?
|
||||
55
|
||||
|
@ -847,6 +852,7 @@ Mu builds on many ideas that have come before, especially:
|
|||
- Forth for demonstrating that ergonomics don't require grammar; and
|
||||
- [Minimal Linux Live](http://minimal.linux-bg.org) for teaching how to create
|
||||
a bootable disk image.
|
||||
- [Soso](https://github.com/ozkl/soso), a tiny hackable OS.
|
||||
|
||||
## Coda
|
||||
|
||||
|
|
18
build
18
build
|
@ -115,35 +115,37 @@ then
|
|||
# Assumption: SubX programs don't need to be retranslated every time we
|
||||
# rebuild the C++ bootstrap.
|
||||
|
||||
OS=${OS:-linux}
|
||||
|
||||
# simple example programs
|
||||
for n in `seq 1 12`
|
||||
do
|
||||
older_than examples/ex$n 049init.linux examples/ex$n.subx && {
|
||||
./subx_bin translate 049init.linux examples/ex$n.subx -o examples/ex$n
|
||||
older_than examples/ex$n init.$OS examples/ex$n.subx && {
|
||||
./subx_bin translate init.$OS examples/ex$n.subx -o examples/ex$n
|
||||
}
|
||||
done
|
||||
|
||||
# simple apps that use the standard library
|
||||
for app in factorial crenshaw2-1 crenshaw2-1b handle
|
||||
do
|
||||
older_than apps/$app 049init.linux [0-9]*.subx && apps/$app.subx {
|
||||
./subx_bin translate 049init.linux [0-9]*.subx apps/$app.subx -o apps/$app
|
||||
older_than apps/$app init.$OS [0-9]*.subx apps/$app.subx && {
|
||||
./subx_bin translate init.$OS [0-9]*.subx apps/$app.subx -o apps/$app
|
||||
}
|
||||
done
|
||||
|
||||
# self-hosting translator
|
||||
for phase in hex survey pack assort dquotes tests
|
||||
do
|
||||
older_than apps/$phase 049init.linux [0-9]*.subx apps/subx-common.subx apps/$phase.subx && {
|
||||
./subx_bin translate 049init.linux [0-9]*.subx apps/subx-common.subx apps/$phase.subx -o apps/$phase
|
||||
older_than apps/$phase init.$OS [0-9]*.subx apps/subx-common.subx apps/$phase.subx && {
|
||||
./subx_bin translate init.$OS [0-9]*.subx apps/subx-common.subx apps/$phase.subx -o apps/$phase
|
||||
}
|
||||
done
|
||||
|
||||
# higher-level syntax
|
||||
for phase in sigils
|
||||
do
|
||||
older_than apps/$phase 049init.linux [0-9]*.subx apps/subx-common.subx apps/$phase.subx && {
|
||||
./subx_bin translate 049init.linux [0-9]*.subx apps/subx-common.subx apps/$phase.subx -o apps/$phase
|
||||
older_than apps/$phase init.$OS [0-9]*.subx apps/subx-common.subx apps/$phase.subx && {
|
||||
./subx_bin translate init.$OS [0-9]*.subx apps/subx-common.subx apps/$phase.subx -o apps/$phase
|
||||
}
|
||||
done
|
||||
|
||||
|
|
3
clean
3
clean
|
@ -7,4 +7,5 @@ rm -rf .until
|
|||
test $# -gt 0 && exit 0 # convenience: 'clean top-level' to leave subsidiary tools alone
|
||||
rm -rf enumerate/enumerate tangle/tangle tangle/*_list */*.dSYM termbox/*.[oa]
|
||||
rm -rf browse_trace/browse_trace_bin browse_trace/*_list
|
||||
rm -rf tmp mu.iso
|
||||
rm -rf tmp mu-linux.iso outfs initrd.fat mu-soso.iso
|
||||
( cd kernel.soso && make clean; )
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
# Build one or more .subx files into an ELF binary, and package it up into a
|
||||
# bootable ISO image.
|
||||
# bootable ISO image with a Linux kernel.
|
||||
#
|
||||
# Must be run on Linux.
|
||||
#
|
||||
|
@ -17,21 +17,23 @@ then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
echo "=== constructing initramfs out of SubX binary"
|
||||
echo "=== building SubX binary"
|
||||
./ntranslate $*
|
||||
mv a.elf init
|
||||
chmod +x init
|
||||
|
||||
echo "=== constructing initramfs out of SubX binary"
|
||||
rm -rf tmp/isoimage
|
||||
mkdir -p tmp/isoimage/boot
|
||||
echo init | cpio -R root:root -H newc -o | xz -9 --check=none > tmp/isoimage/boot/rootfs.xz
|
||||
|
||||
if [ ! -d kernel ]
|
||||
then
|
||||
echo "=== cloning kernel"
|
||||
echo "=== cloning linux kernel"
|
||||
git clone https://github.com/akkartik/kernel
|
||||
fi
|
||||
|
||||
echo "=== building kernel"
|
||||
echo "=== building linux kernel"
|
||||
( cd kernel
|
||||
make bzImage -j $(grep ^processor /proc/cpuinfo | wc -l)
|
||||
)
|
||||
|
@ -48,7 +50,7 @@ cp syslinux.cfg \
|
|||
tmp/syslinux-*/bios/com32/elflink/ldlinux/ldlinux.c32 \
|
||||
tmp/isoimage/boot/syslinux
|
||||
|
||||
echo "=== generating ISO"
|
||||
echo "=== generating mu-linux.iso"
|
||||
# 'hybrid' ISO can also be used on non-optical media such as a disk or USB stick
|
||||
xorriso -as mkisofs \
|
||||
-isohybrid-mbr tmp/syslinux-*/bios/mbr/isohdpfx.bin \
|
||||
|
@ -57,4 +59,4 @@ xorriso -as mkisofs \
|
|||
-no-emul-boot \
|
||||
-boot-load-size 4 \
|
||||
-boot-info-table \
|
||||
tmp/isoimage -o mu.iso
|
||||
tmp/isoimage -o mu_linux.iso
|
44
gen_soso_iso
Executable file
44
gen_soso_iso
Executable file
|
@ -0,0 +1,44 @@
|
|||
#!/bin/sh
|
||||
# Build one or more .subx files into an ELF binary, and package it up into a
|
||||
# bootable ISO image with a Soso (https://github.com/ozkl/soso) kernel.
|
||||
#
|
||||
# Must be run on Linux.
|
||||
#
|
||||
# Soso is published under the 2-clause BSD license.
|
||||
|
||||
set -e
|
||||
|
||||
if [ $# -eq 0 ]
|
||||
then
|
||||
echo "Usage: `basename $0` file.subx ..."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=== building SubX binary"
|
||||
./ntranslate $*
|
||||
mv a.elf init
|
||||
chmod +x init
|
||||
|
||||
echo "=== constructing initramfs out of SubX binary"
|
||||
dd if=/dev/zero of=initrd.fat bs=8M count=1
|
||||
LOOP=`losetup -f`
|
||||
sudo losetup $LOOP initrd.fat
|
||||
sudo mkfs.vfat $LOOP
|
||||
sudo mount $LOOP /mnt
|
||||
cp init /mnt/
|
||||
umount /mnt
|
||||
losetup -d $LOOP
|
||||
sync
|
||||
chown $SUDO_USER:$SUDO_USER initrd.fat
|
||||
|
||||
echo "=== building soso kernel"
|
||||
( cd kernel.soso
|
||||
make
|
||||
)
|
||||
|
||||
echo "=== generating mu-soso.iso"
|
||||
mkdir -p outfs/boot/grub
|
||||
cp kernel.soso/grub.cfg outfs/boot/grub
|
||||
cp kernel.soso/kernel.bin outfs/boot/
|
||||
cp initrd.fat outfs/boot/
|
||||
grub-mkrescue -o mu_soso.iso outfs
|
40
init.soso
Normal file
40
init.soso
Normal file
|
@ -0,0 +1,40 @@
|
|||
# Some OS-specific preliminaries for Soso.
|
||||
|
||||
# Memory layout
|
||||
#
|
||||
# 0x40000000 - 0x40001ffff - for ELF code+data
|
||||
# 0x40002000 - 0x401ffffff - for heap
|
||||
== code 0x40000000
|
||||
== data 0x40001000
|
||||
|
||||
# Syscalls
|
||||
#
|
||||
# We don't have libc, so we need to know Soso's precise syscall layout.
|
||||
# https://github.com/ozkl/soso/blob/master/kernel/syscalltable.h
|
||||
== code
|
||||
|
||||
syscall_exit: # status/ebx : int
|
||||
b8/copy-to-eax 8/imm32
|
||||
cd/syscall 0x80/imm8
|
||||
|
||||
syscall_read: # fd/ebx : int, buf/ecx : address, size/edx : int -> nbytes-or-error/eax : int
|
||||
b8/copy-to-eax 2/imm32
|
||||
cd/syscall 0x80/imm8
|
||||
c3/return
|
||||
|
||||
syscall_write: # fd/ebx : int, buf/ecx : address, size/edx : int -> nbytes-or-error/eax : int
|
||||
b8/copy-to-eax 3/imm32
|
||||
cd/syscall 0x80/imm8
|
||||
c3/return
|
||||
|
||||
syscall_open: # filename/ebx : (address null-terminated-string), flags/ecx : int -> fd-or-error/eax : int
|
||||
b8/copy-to-eax 0/imm32
|
||||
cd/syscall 0x80/imm8
|
||||
c3/return
|
||||
|
||||
syscall_close: # fd/ebx : int -> status/eax
|
||||
b8/copy-to-eax 1/imm32
|
||||
cd/syscall 0x80/imm8
|
||||
c3/return
|
||||
|
||||
# anonymous mmap not implemented
|
25
kernel.soso/LICENSE
Normal file
25
kernel.soso/LICENSE
Normal file
|
@ -0,0 +1,25 @@
|
|||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2017, ozkl
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
19
kernel.soso/Makefile
Normal file
19
kernel.soso/Makefile
Normal file
|
@ -0,0 +1,19 @@
|
|||
CC=cc
|
||||
LD=ld
|
||||
CFLAGS=-nostdlib -nostdinc -fno-builtin -m32 -c
|
||||
LDFLAGS=-Tlink.ld -m elf_i386
|
||||
ASFLAGS=-felf
|
||||
|
||||
OBJ = $(patsubst %.c,%.o,$(wildcard *.c)) $(patsubst %.asm,%.o,$(wildcard *.asm))
|
||||
|
||||
kernel.bin: $(OBJ)
|
||||
$(LD) $(LDFLAGS) -o kernel.bin $(OBJ) font/font.o
|
||||
|
||||
%.o:%.c
|
||||
$(CC) $(CFLAGS) $< -o $@
|
||||
|
||||
%.o:%.asm
|
||||
nasm $(ASFLAGS) $< -o $@
|
||||
|
||||
clean:
|
||||
-rm *.o kernel.bin
|
1
kernel.soso/Readme
Normal file
1
kernel.soso/Readme
Normal file
|
@ -0,0 +1 @@
|
|||
Fork of https://github.com/ozkl/soso at git hash c7bde44ffb8f081d68b5ae61444d419539475833.
|
257
kernel.soso/alloc.c
Normal file
257
kernel.soso/alloc.c
Normal file
|
@ -0,0 +1,257 @@
|
|||
#include "common.h"
|
||||
#include "screen.h"
|
||||
#include "alloc.h"
|
||||
#include "vmm.h"
|
||||
#include "process.h"
|
||||
#include "debugprint.h"
|
||||
|
||||
#define KMALLOC_MINSIZE 16
|
||||
|
||||
extern uint32 *gKernelPageDirectory;
|
||||
|
||||
static char *gKernelHeap = NULL;
|
||||
static uint32 gKernelHeapUsed = 0;
|
||||
|
||||
|
||||
void initializeKernelHeap()
|
||||
{
|
||||
gKernelHeap = (char *) KERN_HEAP_BEGIN;
|
||||
|
||||
ksbrkPage(1);
|
||||
}
|
||||
|
||||
void *ksbrkPage(int n)
|
||||
{
|
||||
struct MallocHeader *chunk;
|
||||
char *p_addr;
|
||||
int i;
|
||||
|
||||
if ((gKernelHeap + (n * PAGESIZE_4M)) > (char *) KERN_HEAP_END) {
|
||||
//Screen_PrintF("ERROR: ksbrk(): no virtual memory left for kernel heap !\n");
|
||||
return (char *) -1;
|
||||
}
|
||||
|
||||
chunk = (struct MallocHeader *) gKernelHeap;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
p_addr = getPageFrame4M();
|
||||
|
||||
//Screen_PrintF("DEBUG: ksbrkPage(): got 4M on physical %x\n", p_addr);
|
||||
|
||||
if ((int)(p_addr) < 0)
|
||||
{
|
||||
PANIC("PANIC: ksbrkPage(): no free page frame available !");
|
||||
return (char *) -1;
|
||||
}
|
||||
|
||||
addPageToPd(gKernelPageDirectory, gKernelHeap, p_addr, 0); //add PG_USER to allow user programs to read kernel heap
|
||||
|
||||
gKernelHeap += PAGESIZE_4M;
|
||||
}
|
||||
|
||||
chunk->size = PAGESIZE_4M * n;
|
||||
chunk->used = 0;
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
void *kmalloc(uint32 size)
|
||||
{
|
||||
if (size==0)
|
||||
return 0;
|
||||
|
||||
unsigned long realsize;
|
||||
struct MallocHeader *chunk, *other;
|
||||
|
||||
if ((realsize = sizeof(struct MallocHeader) + size) < KMALLOC_MINSIZE)
|
||||
{
|
||||
realsize = KMALLOC_MINSIZE;
|
||||
}
|
||||
|
||||
chunk = (struct MallocHeader *) KERN_HEAP_BEGIN;
|
||||
while (chunk->used || chunk->size < realsize)
|
||||
{
|
||||
if (chunk->size == 0)
|
||||
{
|
||||
printkf("\nPANIC: kmalloc(): corrupted chunk on %x with null size (heap %x) !\nSystem halted\n", chunk, gKernelHeap);
|
||||
|
||||
PANIC("kmalloc()");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
chunk = (struct MallocHeader *)((char *)chunk + chunk->size);
|
||||
|
||||
if (chunk == (struct MallocHeader *) gKernelHeap)
|
||||
{
|
||||
if ((int)(ksbrkPage((realsize / PAGESIZE_4M) + 1)) < 0)
|
||||
{
|
||||
PANIC("kmalloc(): no memory left for kernel !\nSystem halted\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (chunk > (struct MallocHeader *) gKernelHeap)
|
||||
{
|
||||
printkf("\nPANIC: kmalloc(): chunk on %x while heap limit is on %x !\nSystem halted\n", chunk, gKernelHeap);
|
||||
|
||||
PANIC("kmalloc()");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (chunk->size - realsize < KMALLOC_MINSIZE)
|
||||
{
|
||||
chunk->used = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
other = (struct MallocHeader *)((char *) chunk + realsize);
|
||||
other->size = chunk->size - realsize;
|
||||
other->used = 0;
|
||||
|
||||
chunk->size = realsize;
|
||||
chunk->used = 1;
|
||||
}
|
||||
|
||||
gKernelHeapUsed += realsize;
|
||||
|
||||
return (char *) chunk + sizeof(struct MallocHeader);
|
||||
}
|
||||
|
||||
void kfree(void *v_addr)
|
||||
{
|
||||
if (v_addr==(void*)0)
|
||||
return;
|
||||
|
||||
struct MallocHeader *chunk, *other;
|
||||
|
||||
chunk = (struct MallocHeader *)((uint32)v_addr - sizeof(struct MallocHeader));
|
||||
chunk->used = 0;
|
||||
|
||||
gKernelHeapUsed -= chunk->size;
|
||||
|
||||
//Merge free block with next free block
|
||||
while ((other = (struct MallocHeader *)((char *)chunk + chunk->size))
|
||||
&& other < (struct MallocHeader *)gKernelHeap
|
||||
&& other->used == 0)
|
||||
{
|
||||
chunk->size += other->size;
|
||||
}
|
||||
}
|
||||
|
||||
static void sbrkPage(Process* process, int pageCount)
|
||||
{
|
||||
if (pageCount > 0)
|
||||
{
|
||||
for (int i = 0; i < pageCount; ++i)
|
||||
{
|
||||
if ((process->heapNextUnallocatedPageBegin + PAGESIZE_4M) > (char*)USER_OFFSET_END)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
char * p_addr = getPageFrame4M();
|
||||
|
||||
if ((int)(p_addr) < 0)
|
||||
{
|
||||
//PANIC("sbrkPage(): no free page frame available !");
|
||||
return;
|
||||
}
|
||||
|
||||
addPageToPd(process->pd, process->heapNextUnallocatedPageBegin, p_addr, PG_USER);
|
||||
|
||||
process->heapNextUnallocatedPageBegin += PAGESIZE_4M;
|
||||
}
|
||||
}
|
||||
else if (pageCount < 0)
|
||||
{
|
||||
pageCount *= -1;
|
||||
|
||||
for (int i = 0; i < pageCount; ++i)
|
||||
{
|
||||
if (process->heapNextUnallocatedPageBegin - PAGESIZE_4M >= process->heapBegin)
|
||||
{
|
||||
process->heapNextUnallocatedPageBegin -= PAGESIZE_4M;
|
||||
|
||||
//This also releases the page frame
|
||||
removePageFromPd(process->pd, process->heapNextUnallocatedPageBegin, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void initializeProcessHeap(Process* process)
|
||||
{
|
||||
process->heapBegin = (char*) USER_OFFSET;
|
||||
process->heapEnd = process->heapBegin;
|
||||
process->heapNextUnallocatedPageBegin = process->heapBegin;
|
||||
|
||||
//Userland programs (their code, data,..) start from USER_OFFSET
|
||||
//So we should leave some space for them by moving heap pointer.
|
||||
//As a result userspace malloc functions start from a forward point (+ USER_EXE_IMAGE).
|
||||
|
||||
sbrk(process, USER_EXE_IMAGE);
|
||||
}
|
||||
|
||||
void *sbrk(Process* process, int nBytes)
|
||||
{
|
||||
printkf("sbrk:1: pid:%d nBytes:%d\n", process->pid, nBytes);
|
||||
|
||||
char* previousBreak = process->heapEnd;
|
||||
printkf("before: %x\n", previousBreak);
|
||||
|
||||
if (nBytes > 0)
|
||||
{
|
||||
int remainingInThePage = process->heapNextUnallocatedPageBegin - process->heapEnd;
|
||||
|
||||
//Screen_PrintF("sbrk:2: remainingInThePage:%d\n", remainingInThePage);
|
||||
|
||||
if (nBytes > remainingInThePage)
|
||||
{
|
||||
int bytesNeededInNewPages = nBytes - remainingInThePage;
|
||||
int neededNewPageCount = (bytesNeededInNewPages / PAGESIZE_4M) + 1;
|
||||
|
||||
//Screen_PrintF("sbrk:3: neededNewPageCount:%d\n", neededNewPageCount);
|
||||
|
||||
uint32 freePages = getFreePageCount();
|
||||
if ((uint32)neededNewPageCount + 1 > freePages)
|
||||
{
|
||||
return (void*)-1;
|
||||
}
|
||||
|
||||
sbrkPage(process, neededNewPageCount);
|
||||
}
|
||||
}
|
||||
else if (nBytes < 0)
|
||||
{
|
||||
char* currentPageBegin = process->heapNextUnallocatedPageBegin - PAGESIZE_4M;
|
||||
|
||||
int remainingInThePage = process->heapEnd - currentPageBegin;
|
||||
|
||||
//Screen_PrintF("sbrk:4: remainingInThePage:%d\n", remainingInThePage);
|
||||
|
||||
if (-nBytes > remainingInThePage)
|
||||
{
|
||||
int bytesInPreviousPages = -nBytes - remainingInThePage;
|
||||
int neededNewPageCount = (bytesInPreviousPages / PAGESIZE_4M) + 1;
|
||||
|
||||
//Screen_PrintF("sbrk:5: neededNewPageCount:%d\n", neededNewPageCount);
|
||||
|
||||
sbrkPage(process, -neededNewPageCount);
|
||||
}
|
||||
}
|
||||
|
||||
process->heapEnd += nBytes;
|
||||
printkf("after: %x\n", process->heapEnd);
|
||||
|
||||
return previousBreak;
|
||||
}
|
||||
|
||||
uint32 getKernelHeapUsed()
|
||||
{
|
||||
return gKernelHeapUsed;
|
||||
}
|
25
kernel.soso/alloc.h
Normal file
25
kernel.soso/alloc.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef ALLOC_H
|
||||
#define ALLOC_H
|
||||
|
||||
#include "common.h"
|
||||
#include "process.h"
|
||||
|
||||
void initializeKernelHeap();
|
||||
void *ksbrkPage(int n);
|
||||
void *kmalloc(uint32 size);
|
||||
void kfree(void *v_addr);
|
||||
|
||||
void initializeProcessHeap(Process* process);
|
||||
void *sbrk(Process* process, int nBytes);
|
||||
|
||||
uint32 getKernelHeapUsed();
|
||||
|
||||
struct MallocHeader
|
||||
{
|
||||
unsigned long size:31;
|
||||
unsigned long used:1;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct MallocHeader MallocHeader;
|
||||
|
||||
#endif // ALLOC_H
|
51
kernel.soso/boot.asm
Normal file
51
kernel.soso/boot.asm
Normal file
|
@ -0,0 +1,51 @@
|
|||
MBOOT_PAGE_ALIGN equ 1<<0
|
||||
MBOOT_MEM_INFO equ 1<<1
|
||||
MBOOT_USE_GFX equ 1<<2
|
||||
MBOOT_HEADER_MAGIC equ 0x1BADB002
|
||||
MBOOT_HEADER_FLAGS equ MBOOT_PAGE_ALIGN | MBOOT_MEM_INFO | MBOOT_USE_GFX
|
||||
MBOOT_CHECKSUM equ -(MBOOT_HEADER_MAGIC + MBOOT_HEADER_FLAGS)
|
||||
|
||||
|
||||
[BITS 32]
|
||||
|
||||
|
||||
section .multiboot
|
||||
align 4
|
||||
dd MBOOT_HEADER_MAGIC
|
||||
dd MBOOT_HEADER_FLAGS
|
||||
dd MBOOT_CHECKSUM
|
||||
dd 0x00000000 ; header_addr
|
||||
dd 0x00000000 ; load_addr
|
||||
dd 0x00000000 ; load_end_addr
|
||||
dd 0x00000000 ; bss_end_addr
|
||||
dd 0x00000000 ; entry_addr
|
||||
; Graphics requests
|
||||
dd 0x00000000 ; 0 = linear graphics
|
||||
dd 1024
|
||||
dd 768
|
||||
dd 32
|
||||
|
||||
section .bss
|
||||
align 16
|
||||
stack_bottom:
|
||||
resb 16384 ; 16 KiB
|
||||
stack_top:
|
||||
|
||||
[GLOBAL _start] ; this is the entry point. we tell linker script to set start address of kernel elf file.
|
||||
[EXTERN kmain]
|
||||
|
||||
section .text
|
||||
|
||||
_start:
|
||||
mov esp, stack_top
|
||||
|
||||
; push multiboot parameter to kmain()
|
||||
push ebx
|
||||
|
||||
; ...and run!
|
||||
cli
|
||||
call kmain
|
||||
|
||||
;never reach here
|
||||
cli
|
||||
hlt
|
441
kernel.soso/common.c
Normal file
441
kernel.soso/common.c
Normal file
|
@ -0,0 +1,441 @@
|
|||
#include "common.h"
|
||||
#include "screen.h"
|
||||
#include "ttydriver.h"
|
||||
|
||||
static BOOL gInterruptsWereEnabled = FALSE;
|
||||
|
||||
// Write a byte out to the specified port.
|
||||
void outb(uint16 port, uint8 value)
|
||||
{
|
||||
asm volatile ("outb %1, %0" : : "dN" (port), "a" (value));
|
||||
}
|
||||
|
||||
void outw(uint16 port, uint16 value)
|
||||
{
|
||||
asm volatile ("outw %1, %0" : : "dN" (port), "a" (value));
|
||||
}
|
||||
|
||||
uint8 inb(uint16 port)
|
||||
{
|
||||
uint8 ret;
|
||||
asm volatile("inb %1, %0" : "=a" (ret) : "dN" (port));
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16 inw(uint16 port)
|
||||
{
|
||||
uint16 ret;
|
||||
asm volatile ("inw %1, %0" : "=a" (ret) : "dN" (port));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Copy len bytes from src to dest.
|
||||
void* memcpy(uint8 *dest, const uint8 *src, uint32 len)
|
||||
{
|
||||
const uint8 *sp = (const uint8 *)src;
|
||||
uint8 *dp = (uint8 *)dest;
|
||||
for(; len != 0; len--) *dp++ = *sp++;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
// Write len copies of val into dest.
|
||||
void* memset(uint8 *dest, uint8 val, uint32 len)
|
||||
{
|
||||
uint8 *temp = (uint8 *)dest;
|
||||
for ( ; len != 0; len--) *temp++ = val;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
void* memmove(void* dest, const void* src, uint32 n)
|
||||
{
|
||||
uint8* _dest;
|
||||
uint8* _src;
|
||||
|
||||
if ( dest < src ) {
|
||||
_dest = ( uint8* )dest;
|
||||
_src = ( uint8* )src;
|
||||
|
||||
while ( n-- ) {
|
||||
*_dest++ = *_src++;
|
||||
}
|
||||
} else {
|
||||
_dest = ( uint8* )dest + n;
|
||||
_src = ( uint8* )src + n;
|
||||
|
||||
while ( n-- ) {
|
||||
*--_dest = *--_src;
|
||||
}
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
int memcmp( const void* p1, const void* p2, uint32 c )
|
||||
{
|
||||
const uint8* su1, *su2;
|
||||
int8 res = 0;
|
||||
|
||||
for ( su1 = p1, su2 = p2; 0 < c; ++su1, ++su2, c-- ) {
|
||||
if ( ( res = *su1 - *su2 ) != 0 ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Compare two strings. Should return -1 if
|
||||
// str1 < str2, 0 if they are equal or 1 otherwise.
|
||||
int strcmp(const char *str1, const char *str2)
|
||||
{
|
||||
int i = 0;
|
||||
int failed = 0;
|
||||
while(str1[i] != '\0' && str2[i] != '\0')
|
||||
{
|
||||
if(str1[i] != str2[i])
|
||||
{
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if ((str1[i] == '\0' && str2[i] != '\0') || (str1[i] != '\0' && str2[i] == '\0'))
|
||||
{
|
||||
failed = 1;
|
||||
}
|
||||
|
||||
return failed;
|
||||
}
|
||||
|
||||
int strncmp(const char *str1, const char *str2, int length)
|
||||
{
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
if (str1[i] != str2[i])
|
||||
{
|
||||
return str1[i] - str2[i];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Copy the NULL-terminated string src into dest, and
|
||||
// return dest.
|
||||
char *strcpy(char *dest, const char *src)
|
||||
{
|
||||
do
|
||||
{
|
||||
*dest++ = *src++;
|
||||
}
|
||||
while (*src != 0);
|
||||
*dest = '\0';
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
char *strcpyNonNull(char *dest, const char *src)
|
||||
{
|
||||
do
|
||||
{
|
||||
*dest++ = *src++;
|
||||
}
|
||||
while (*src != 0);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
//Copies the first num characters of source to destination. If the end of the source C string is found before num characters have been copied,
|
||||
//destination is padded with zeros until a total of num characters have been written to it.
|
||||
//No null-character is implicitly appended at the end of destination if source is longer than num.
|
||||
//Thus, in this case, destination shall not be considered a null terminated C string.
|
||||
char *strncpy(char *dest, const char *src, uint32 num)
|
||||
{
|
||||
BOOL sourceEnded = FALSE;
|
||||
for (uint32 i = 0; i < num; ++i)
|
||||
{
|
||||
if (sourceEnded == FALSE && src[i] == '\0')
|
||||
{
|
||||
sourceEnded = TRUE;
|
||||
}
|
||||
|
||||
if (sourceEnded)
|
||||
{
|
||||
dest[i] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
dest[i] = src[i];
|
||||
}
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
char* strcat(char *dest, const char *src)
|
||||
{
|
||||
size_t i,j;
|
||||
for (i = 0; dest[i] != '\0'; i++)
|
||||
;
|
||||
for (j = 0; src[j] != '\0'; j++)
|
||||
dest[i+j] = src[j];
|
||||
dest[i+j] = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
int strlen(const char *src)
|
||||
{
|
||||
int i = 0;
|
||||
while (*src++)
|
||||
i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
int strFirstIndexOf(const char *src, char c)
|
||||
{
|
||||
int i = 0;
|
||||
while (src[i])
|
||||
{
|
||||
if (src[i] == c)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32 rand()
|
||||
{
|
||||
static uint32 x = 123456789;
|
||||
static uint32 y = 362436069;
|
||||
static uint32 z = 521288629;
|
||||
static uint32 w = 88675123;
|
||||
|
||||
uint32 t;
|
||||
|
||||
t = x ^ (x << 11);
|
||||
x = y; y = z; z = w;
|
||||
return w = w ^ (w >> 19) ^ t ^ (t >> 8);
|
||||
}
|
||||
|
||||
int atoi(char *str)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
for (int i = 0; str[i] != '\0'; ++i)
|
||||
{
|
||||
result = result*10 + str[i] - '0';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void itoa (char *buf, int base, int d)
|
||||
{
|
||||
char *p = buf;
|
||||
char *p1, *p2;
|
||||
unsigned long ud = d;
|
||||
int divisor = 10;
|
||||
|
||||
|
||||
if (base == 'd' && d < 0)
|
||||
{
|
||||
*p++ = '-';
|
||||
buf++;
|
||||
ud = -d;
|
||||
}
|
||||
else if (base == 'x')
|
||||
{
|
||||
divisor = 16;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
int remainder = ud % divisor;
|
||||
|
||||
*p++ = (remainder < 10) ? remainder + '0' : remainder + 'A' - 10;
|
||||
}
|
||||
while (ud /= divisor);
|
||||
|
||||
|
||||
*p = 0;
|
||||
|
||||
//Reverse BUF.
|
||||
p1 = buf;
|
||||
p2 = p - 1;
|
||||
while (p1 < p2)
|
||||
{
|
||||
char tmp = *p1;
|
||||
*p1 = *p2;
|
||||
*p2 = tmp;
|
||||
p1++;
|
||||
p2--;
|
||||
}
|
||||
}
|
||||
|
||||
int sprintf_va(char* buffer, const char *format, __builtin_va_list vl)
|
||||
{
|
||||
char c;
|
||||
char buf[20];
|
||||
|
||||
int bufferIndex = 0;
|
||||
|
||||
while ((c = *format++) != 0)
|
||||
{
|
||||
if (c != '%')
|
||||
buffer[bufferIndex++] = c;
|
||||
else
|
||||
{
|
||||
char *p;
|
||||
|
||||
c = *format++;
|
||||
switch (c)
|
||||
{
|
||||
case 'x':
|
||||
buf[0] = '0';
|
||||
buf[1] = 'x';
|
||||
//itoa (buf + 2, c, *((int *) arg++));
|
||||
itoa (buf + 2, c, __builtin_va_arg(vl, int));
|
||||
p = buf;
|
||||
goto string;
|
||||
break;
|
||||
case 'd':
|
||||
case 'u':
|
||||
//itoa (buf, c, *((int *) arg++));
|
||||
itoa (buf, c, __builtin_va_arg(vl, int));
|
||||
p = buf;
|
||||
goto string;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
//p = *arg++;
|
||||
p = __builtin_va_arg(vl, char*);
|
||||
if (! p)
|
||||
p = "(null)";
|
||||
|
||||
string:
|
||||
while (*p)
|
||||
buffer[bufferIndex++] = (*p++);
|
||||
break;
|
||||
|
||||
default:
|
||||
//buffer[bufferIndex++] = (*((int *) arg++));
|
||||
buffer[bufferIndex++] = __builtin_va_arg(vl, int);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buffer[bufferIndex] = '\0';
|
||||
|
||||
return bufferIndex;
|
||||
}
|
||||
|
||||
int sprintf(char* buffer, const char *format, ...)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
__builtin_va_list vl;
|
||||
__builtin_va_start(vl, format);
|
||||
|
||||
result = sprintf_va(buffer, format, vl);
|
||||
|
||||
__builtin_va_end(vl);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void printkf(const char *format, ...)
|
||||
{
|
||||
char buffer[1024];
|
||||
buffer[0] = 'k';
|
||||
buffer[1] = ':';
|
||||
buffer[2] = 0;
|
||||
|
||||
Tty* tty = getActiveTTY();
|
||||
if (tty)
|
||||
{
|
||||
__builtin_va_list vl;
|
||||
__builtin_va_start(vl, format);
|
||||
|
||||
sprintf_va(buffer+2, format, vl);
|
||||
|
||||
__builtin_va_end(vl);
|
||||
|
||||
Tty_PutText(tty, buffer);
|
||||
|
||||
if (tty->flushScreen)
|
||||
{
|
||||
tty->flushScreen(tty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void panic(const char *message, const char *file, uint32 line)
|
||||
{
|
||||
disableInterrupts();
|
||||
|
||||
printkf("PANIC:%s:%d:%s\n", file, line, message);
|
||||
|
||||
halt();
|
||||
}
|
||||
|
||||
void warning(const char *message, const char *file, uint32 line)
|
||||
{
|
||||
printkf("WARNING:%s:%d:%s\n", file, line, message);
|
||||
}
|
||||
|
||||
void panic_assert(const char *file, uint32 line, const char *desc)
|
||||
{
|
||||
disableInterrupts();
|
||||
|
||||
printkf("ASSERTION-FAILED:%s:%d:%s\n", file, line, desc);
|
||||
|
||||
halt();
|
||||
}
|
||||
|
||||
uint32 readEsp()
|
||||
{
|
||||
uint32 stack_pointer;
|
||||
asm volatile("mov %%esp, %0" : "=r" (stack_pointer));
|
||||
|
||||
return stack_pointer;
|
||||
}
|
||||
|
||||
uint32 getCpuFlags()
|
||||
{
|
||||
uint32 eflags = 0;
|
||||
|
||||
asm("pushfl; pop %%eax; mov %%eax, %0": "=m"(eflags):);
|
||||
|
||||
return eflags;
|
||||
}
|
||||
|
||||
BOOL isInterruptsEnabled()
|
||||
{
|
||||
uint32 eflags = getCpuFlags();
|
||||
|
||||
uint32 interruptFlag = 0x200; //9th flag
|
||||
|
||||
return (eflags & interruptFlag) == interruptFlag;
|
||||
}
|
||||
|
||||
void beginCriticalSection()
|
||||
{
|
||||
gInterruptsWereEnabled = isInterruptsEnabled();
|
||||
|
||||
disableInterrupts();
|
||||
}
|
||||
|
||||
void endCriticalSection()
|
||||
{
|
||||
if (gInterruptsWereEnabled)
|
||||
{
|
||||
enableInterrupts();
|
||||
}
|
||||
}
|
125
kernel.soso/common.h
Normal file
125
kernel.soso/common.h
Normal file
|
@ -0,0 +1,125 @@
|
|||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
#define enableInterrupts() asm volatile("sti")
|
||||
#define disableInterrupts() asm volatile("cli")
|
||||
#define halt() asm volatile("hlt")
|
||||
|
||||
|
||||
typedef unsigned long long uint64;
|
||||
typedef signed long long int64;
|
||||
typedef unsigned int uint32;
|
||||
typedef int int32;
|
||||
typedef unsigned short uint16;
|
||||
typedef short int16;
|
||||
typedef unsigned char uint8;
|
||||
typedef char int8;
|
||||
typedef unsigned int size_t;
|
||||
|
||||
#define BOOL uint8
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#define NULL 0
|
||||
|
||||
#define KERN_PAGE_DIRECTORY 0x00001000
|
||||
|
||||
#define KERN_BASE 0x00100000
|
||||
|
||||
//16M is identity mapped as below.
|
||||
//First 8M we don't touch. Kernel code is there.
|
||||
//4M is reserved for 4K page directories.
|
||||
//4M is not used for now. kernel mini heap was here in old times.
|
||||
#define RESERVED_AREA 0x01000000 //16 mb
|
||||
#define KERN_PD_AREA_BEGIN 0x00800000 // 8 mb
|
||||
#define KERN_PD_AREA_END 0x00C00000 //12 mb
|
||||
#define KERN_NOTUSED_BEGIN 0x00C00000 //12 mb
|
||||
#define KERN_NOTUSED_END 0x01000000 //16 mb
|
||||
|
||||
#define GFX_MEMORY 0x01000000 //16 mb
|
||||
|
||||
#define KERN_HEAP_BEGIN 0x02000000 //32 mb
|
||||
#define KERN_HEAP_END 0x40000000 // 1 gb
|
||||
|
||||
|
||||
#define PAGE_INDEX_4K(addr) ((addr) >> 12)
|
||||
#define PAGE_INDEX_4M(addr) ((addr) >> 22)
|
||||
#define PAGING_FLAG 0x80000000 // CR0 - bit 31
|
||||
#define PSE_FLAG 0x00000010 // CR4 - bit 4
|
||||
#define PG_PRESENT 0x00000001 // page directory / table
|
||||
#define PG_WRITE 0x00000002
|
||||
#define PG_USER 0x00000004
|
||||
#define PG_4MB 0x00000080
|
||||
#define PAGESIZE_4K 0x00001000
|
||||
#define PAGESIZE_4M 0x00400000
|
||||
#define RAM_AS_4K_PAGES 0x100000
|
||||
#define RAM_AS_4M_PAGES 1024
|
||||
|
||||
#define KERNELMEMORY_PAGE_COUNT 256 //(KERN_HEAP_END / PAGESIZE_4M)
|
||||
|
||||
#define KERN_STACK_SIZE PAGESIZE_4K
|
||||
|
||||
//KERN_HEAP_END ends and this one starts
|
||||
#define USER_OFFSET 0x40000000
|
||||
#define USER_OFFSET_END 0xF0000000
|
||||
#define USER_OFFSET_MMAP 0xF0000000
|
||||
#define USER_OFFSET_MMAP_END 0xFFFFFFFF
|
||||
|
||||
#define USER_EXE_IMAGE 0x200000 //2MB
|
||||
#define USER_ARGV_ENV_SIZE 0x10000 //65KB
|
||||
#define USER_ARGV_ENV_LOC (USER_OFFSET + (USER_EXE_IMAGE - USER_ARGV_ENV_SIZE))
|
||||
//This means we support executable images up to 2MB
|
||||
//And user malloc functions will start from USER_OFFSET + USER_EXE_IMAGE
|
||||
//We will 65KB (0x10000) for argv and environ just before user malloc start
|
||||
//So USER_EXE_IMAGE - USER_ARGV_ENV_SIZE = 0x1F0000
|
||||
//That means argv and env data will start from USER_OFFSET + 0x1F0000
|
||||
//Of course libc should know this numbers :)
|
||||
|
||||
#define USER_STACK 0xF0000000
|
||||
|
||||
void outb(uint16 port, uint8 value);
|
||||
void outw(uint16 port, uint16 value);
|
||||
uint8 inb(uint16 port);
|
||||
uint16 inw(uint16 port);
|
||||
|
||||
#define PANIC(msg) panic(msg, __FILE__, __LINE__);
|
||||
#define WARNING(msg) warning(msg, __FILE__, __LINE__);
|
||||
#define ASSERT(b) ((b) ? (void)0 : panic_assert(__FILE__, __LINE__, #b))
|
||||
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||
|
||||
void warning(const char *message, const char *file, uint32 line);
|
||||
void panic(const char *message, const char *file, uint32 line);
|
||||
void panic_assert(const char *file, uint32 line, const char *desc);
|
||||
|
||||
void* memset(uint8 *dest, uint8 val, uint32 len);
|
||||
void* memcpy(uint8 *dest, const uint8 *src, uint32 len);
|
||||
void* memmove(void* dest, const void* src, uint32 n);
|
||||
int memcmp(const void* p1, const void* p2, uint32 c);
|
||||
|
||||
int strcmp(const char *str1, const char *str2);
|
||||
int strncmp(const char *str1, const char *str2, int length);
|
||||
char *strcpy(char *dest, const char *src);
|
||||
char *strcpyNonNull(char *dest, const char *src);
|
||||
char *strncpy(char *dest, const char *src, uint32 num);
|
||||
char* strcat(char *dest, const char *src);
|
||||
int strlen(const char *src);
|
||||
int strFirstIndexOf(const char *src, char c);
|
||||
int sprintf(char* buffer, const char *format, ...);
|
||||
|
||||
void printkf(const char *format, ...);
|
||||
|
||||
int atoi(char *str);
|
||||
void itoa(char *buf, int base, int d);
|
||||
|
||||
uint32 rand();
|
||||
|
||||
uint32 readEip();
|
||||
uint32 readEsp();
|
||||
uint32 getCpuFlags();
|
||||
BOOL isInterruptsEnabled();
|
||||
|
||||
void beginCriticalSection();
|
||||
void endCriticalSection();
|
||||
|
||||
#endif // COMMON_H
|
21
kernel.soso/commonuser.h
Normal file
21
kernel.soso/commonuser.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#ifndef COMMONUSER_H
|
||||
#define COMMONUSER_H
|
||||
|
||||
typedef struct SosoMessage
|
||||
{
|
||||
int messageType;
|
||||
int parameter1;
|
||||
int parameter2;
|
||||
int parameter3;
|
||||
} SosoMessage;
|
||||
|
||||
typedef struct TtyUserBuffer
|
||||
{
|
||||
unsigned short lineCount;
|
||||
unsigned short columnCount;
|
||||
unsigned short currentLine;
|
||||
unsigned short currentColumn;
|
||||
unsigned char* buffer;
|
||||
} TtyUserBuffer;
|
||||
|
||||
#endif // COMMONUSER_H
|
86
kernel.soso/debugprint.c
Normal file
86
kernel.soso/debugprint.c
Normal file
|
@ -0,0 +1,86 @@
|
|||
#include "debugprint.h"
|
||||
#include "common.h"
|
||||
#include "fs.h"
|
||||
|
||||
static File* gFile = NULL;
|
||||
|
||||
void Debug_initialize(const char* fileName)
|
||||
{
|
||||
FileSystemNode* node = getFileSystemNode(fileName);
|
||||
|
||||
gFile = open_fs(node, 0);
|
||||
}
|
||||
|
||||
void Debug_PrintF(const char *format, ...)
|
||||
{
|
||||
char **arg = (char **) &format;
|
||||
char c;
|
||||
char buf[20];
|
||||
char buffer[512];
|
||||
|
||||
int bufferIndex = 0;
|
||||
|
||||
//arg++;
|
||||
__builtin_va_list vl;
|
||||
__builtin_va_start(vl, format);
|
||||
|
||||
while ((c = *format++) != 0)
|
||||
{
|
||||
if (bufferIndex > 510)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (c != '%')
|
||||
buffer[bufferIndex++] = c;
|
||||
else
|
||||
{
|
||||
char *p;
|
||||
|
||||
c = *format++;
|
||||
switch (c)
|
||||
{
|
||||
case 'x':
|
||||
buf[0] = '0';
|
||||
buf[1] = 'x';
|
||||
//itoa (buf + 2, c, *((int *) arg++));
|
||||
itoa (buf + 2, c, __builtin_va_arg(vl, int));
|
||||
p = buf;
|
||||
goto string;
|
||||
break;
|
||||
case 'd':
|
||||
case 'u':
|
||||
//itoa (buf, c, *((int *) arg++));
|
||||
itoa (buf, c, __builtin_va_arg(vl, int));
|
||||
p = buf;
|
||||
goto string;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
//p = *arg++;
|
||||
p = __builtin_va_arg(vl, char*);
|
||||
if (! p)
|
||||
p = "(null)";
|
||||
|
||||
string:
|
||||
while (*p)
|
||||
buffer[bufferIndex++] = (*p++);
|
||||
break;
|
||||
|
||||
default:
|
||||
//buffer[bufferIndex++] = (*((int *) arg++));
|
||||
buffer[bufferIndex++] = __builtin_va_arg(vl, int);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buffer[bufferIndex] = '\0';
|
||||
|
||||
if (gFile)
|
||||
{
|
||||
write_fs(gFile, strlen(buffer), (uint8*)buffer);
|
||||
}
|
||||
|
||||
__builtin_va_end(vl);
|
||||
}
|
7
kernel.soso/debugprint.h
Normal file
7
kernel.soso/debugprint.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
#ifndef DEBUGPRINT_H
|
||||
#define DEBUGPRINT_H
|
||||
|
||||
void Debug_initialize(const char* fileName);
|
||||
void Debug_PrintF(const char *format, ...);
|
||||
|
||||
#endif // DEBUGPRINT_H
|
211
kernel.soso/descriptortables.c
Normal file
211
kernel.soso/descriptortables.c
Normal file
|
@ -0,0 +1,211 @@
|
|||
#include "screen.h"
|
||||
#include "common.h"
|
||||
#include "descriptortables.h"
|
||||
#include "isr.h"
|
||||
#include "process.h"
|
||||
|
||||
extern void flushGdt(uint32);
|
||||
extern void flushIdt(uint32);
|
||||
extern void flushTss();
|
||||
|
||||
|
||||
static void initializeGdt();
|
||||
static void initializeIdt();
|
||||
static void setGdtEntry(int32 num, uint32 base, uint32 limit, uint8 access, uint8 gran);
|
||||
static void setIdtEntry(uint8 num, uint32 base, uint16 sel, uint8 flags);
|
||||
|
||||
GdtEntry gGdtEntries[6];
|
||||
GdtPointer gGdtPointer;
|
||||
IdtEntry gIdtEntries[256];
|
||||
IdtPointer gIdtPointer;
|
||||
Tss gTss;
|
||||
|
||||
extern IsrFunction gInterruptHandlers[];
|
||||
|
||||
static void handleDoubleFault(Registers *regs);
|
||||
static void handleGeneralProtectionFault(Registers *regs);
|
||||
|
||||
void initializeDescriptorTables()
|
||||
{
|
||||
initializeGdt();
|
||||
|
||||
initializeIdt();
|
||||
|
||||
memset((uint8*)&gInterruptHandlers, 0, sizeof(IsrFunction)*256);
|
||||
|
||||
registerInterruptHandler(8, handleDoubleFault);
|
||||
registerInterruptHandler(13, handleGeneralProtectionFault);
|
||||
}
|
||||
|
||||
static void initializeGdt()
|
||||
{
|
||||
gGdtPointer.limit = (sizeof(GdtEntry) * 6) - 1;
|
||||
gGdtPointer.base = (uint32)&gGdtEntries;
|
||||
|
||||
setGdtEntry(0, 0, 0, 0, 0); // 0x00 Null segment
|
||||
setGdtEntry(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // 0x08 Code segment
|
||||
setGdtEntry(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // 0x10 Data segment
|
||||
setGdtEntry(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // 0x18 User mode code segment
|
||||
setGdtEntry(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // 0x20 User mode data segment
|
||||
|
||||
//TSS
|
||||
memset((uint8*)&gTss, 0, sizeof(gTss));
|
||||
gTss.debug_flag = 0x00;
|
||||
gTss.io_map = 0x00;
|
||||
gTss.esp0 = 0;//0x1FFF0;
|
||||
gTss.ss0 = 0x10;//0x18;
|
||||
|
||||
gTss.cs = 0x0B; //from ring 3 - 0x08 | 3 = 0x0B
|
||||
gTss.ss = gTss.ds = gTss.es = gTss.fs = gTss.gs = 0x13; //from ring 3 = 0x10 | 3 = 0x13
|
||||
uint32 tss_base = (uint32) &gTss;
|
||||
uint32 tss_limit = tss_base + sizeof(gTss);
|
||||
setGdtEntry(5, tss_base, tss_limit, 0xE9, 0x00);
|
||||
|
||||
flushGdt((uint32)&gGdtPointer);
|
||||
flushTss();
|
||||
}
|
||||
|
||||
// Set the value of one GDT entry.
|
||||
static void setGdtEntry(int32 num, uint32 base, uint32 limit, uint8 access, uint8 gran)
|
||||
{
|
||||
gGdtEntries[num].base_low = (base & 0xFFFF);
|
||||
gGdtEntries[num].base_middle = (base >> 16) & 0xFF;
|
||||
gGdtEntries[num].base_high = (base >> 24) & 0xFF;
|
||||
|
||||
gGdtEntries[num].limit_low = (limit & 0xFFFF);
|
||||
gGdtEntries[num].granularity = (limit >> 16) & 0x0F;
|
||||
|
||||
gGdtEntries[num].granularity |= gran & 0xF0;
|
||||
gGdtEntries[num].access = access;
|
||||
}
|
||||
|
||||
void irqTimer();
|
||||
|
||||
static void initializeIdt()
|
||||
{
|
||||
gIdtPointer.limit = sizeof(IdtEntry) * 256 -1;
|
||||
gIdtPointer.base = (uint32)&gIdtEntries;
|
||||
|
||||
memset((uint8*)&gIdtEntries, 0, sizeof(IdtEntry)*256);
|
||||
|
||||
// Remap the irq table.
|
||||
outb(0x20, 0x11);
|
||||
outb(0xA0, 0x11);
|
||||
outb(0x21, 0x20);
|
||||
outb(0xA1, 0x28);
|
||||
outb(0x21, 0x04);
|
||||
outb(0xA1, 0x02);
|
||||
outb(0x21, 0x01);
|
||||
outb(0xA1, 0x01);
|
||||
outb(0x21, 0x0);
|
||||
outb(0xA1, 0x0);
|
||||
|
||||
setIdtEntry( 0, (uint32)isr0 , 0x08, 0x8E);
|
||||
setIdtEntry( 1, (uint32)isr1 , 0x08, 0x8E);
|
||||
setIdtEntry( 2, (uint32)isr2 , 0x08, 0x8E);
|
||||
setIdtEntry( 3, (uint32)isr3 , 0x08, 0x8E);
|
||||
setIdtEntry( 4, (uint32)isr4 , 0x08, 0x8E);
|
||||
setIdtEntry( 5, (uint32)isr5 , 0x08, 0x8E);
|
||||
setIdtEntry( 6, (uint32)isr6 , 0x08, 0x8E);
|
||||
setIdtEntry( 7, (uint32)isr7 , 0x08, 0x8E);
|
||||
setIdtEntry( 8, (uint32)isr8 , 0x08, 0x8E);
|
||||
setIdtEntry( 9, (uint32)isr9 , 0x08, 0x8E);
|
||||
setIdtEntry(10, (uint32)isr10, 0x08, 0x8E);
|
||||
setIdtEntry(11, (uint32)isr11, 0x08, 0x8E);
|
||||
setIdtEntry(12, (uint32)isr12, 0x08, 0x8E);
|
||||
setIdtEntry(13, (uint32)isr13, 0x08, 0x8E);
|
||||
setIdtEntry(14, (uint32)isr14, 0x08, 0x8E);
|
||||
setIdtEntry(15, (uint32)isr15, 0x08, 0x8E);
|
||||
setIdtEntry(16, (uint32)isr16, 0x08, 0x8E);
|
||||
setIdtEntry(17, (uint32)isr17, 0x08, 0x8E);
|
||||
setIdtEntry(18, (uint32)isr18, 0x08, 0x8E);
|
||||
setIdtEntry(19, (uint32)isr19, 0x08, 0x8E);
|
||||
setIdtEntry(20, (uint32)isr20, 0x08, 0x8E);
|
||||
setIdtEntry(21, (uint32)isr21, 0x08, 0x8E);
|
||||
setIdtEntry(22, (uint32)isr22, 0x08, 0x8E);
|
||||
setIdtEntry(23, (uint32)isr23, 0x08, 0x8E);
|
||||
setIdtEntry(24, (uint32)isr24, 0x08, 0x8E);
|
||||
setIdtEntry(25, (uint32)isr25, 0x08, 0x8E);
|
||||
setIdtEntry(26, (uint32)isr26, 0x08, 0x8E);
|
||||
setIdtEntry(27, (uint32)isr27, 0x08, 0x8E);
|
||||
setIdtEntry(28, (uint32)isr28, 0x08, 0x8E);
|
||||
setIdtEntry(29, (uint32)isr29, 0x08, 0x8E);
|
||||
setIdtEntry(30, (uint32)isr30, 0x08, 0x8E);
|
||||
setIdtEntry(31, (uint32)isr31, 0x08, 0x8E);
|
||||
|
||||
setIdtEntry(32, (uint32)irqTimer, 0x08, 0x8E);
|
||||
setIdtEntry(33, (uint32)irq1, 0x08, 0x8E);
|
||||
setIdtEntry(34, (uint32)irq2, 0x08, 0x8E);
|
||||
setIdtEntry(35, (uint32)irq3, 0x08, 0x8E);
|
||||
setIdtEntry(36, (uint32)irq4, 0x08, 0x8E);
|
||||
setIdtEntry(37, (uint32)irq5, 0x08, 0x8E);
|
||||
setIdtEntry(38, (uint32)irq6, 0x08, 0x8E);
|
||||
setIdtEntry(39, (uint32)irq7, 0x08, 0x8E);
|
||||
setIdtEntry(40, (uint32)irq8, 0x08, 0x8E);
|
||||
setIdtEntry(41, (uint32)irq9, 0x08, 0x8E);
|
||||
setIdtEntry(42, (uint32)irq10, 0x08, 0x8E);
|
||||
setIdtEntry(43, (uint32)irq11, 0x08, 0x8E);
|
||||
setIdtEntry(44, (uint32)irq12, 0x08, 0x8E);
|
||||
setIdtEntry(45, (uint32)irq13, 0x08, 0x8E);
|
||||
setIdtEntry(46, (uint32)irq14, 0x08, 0x8E);
|
||||
setIdtEntry(47, (uint32)irq15, 0x08, 0x8E);
|
||||
setIdtEntry(128, (uint32)isr128, 0x08, 0x8E);
|
||||
|
||||
flushIdt((uint32)&gIdtPointer);
|
||||
}
|
||||
|
||||
static void setIdtEntry(uint8 num, uint32 base, uint16 sel, uint8 flags)
|
||||
{
|
||||
gIdtEntries[num].base_lo = base & 0xFFFF;
|
||||
gIdtEntries[num].base_hi = (base >> 16) & 0xFFFF;
|
||||
|
||||
gIdtEntries[num].sel = sel;
|
||||
gIdtEntries[num].always0 = 0;
|
||||
gIdtEntries[num].flags = flags | 0x60;
|
||||
}
|
||||
|
||||
static void handleDoubleFault(Registers *regs)
|
||||
{
|
||||
printkf("Double fault!!! Error code:%d\n", regs->errorCode);
|
||||
|
||||
PANIC("Double fault!!!");
|
||||
}
|
||||
|
||||
static void handleGeneralProtectionFault(Registers *regs)
|
||||
{
|
||||
printkf("General protection fault!!! Error code:%d - IP:%x\n", regs->errorCode, regs->eip);
|
||||
|
||||
Thread* faultingThread = getCurrentThread();
|
||||
if (NULL != faultingThread)
|
||||
{
|
||||
Thread* mainThread = getMainKernelThread();
|
||||
|
||||
if (mainThread == faultingThread)
|
||||
{
|
||||
PANIC("General protection fault in Kernel main thread!!!");
|
||||
}
|
||||
else
|
||||
{
|
||||
printkf("Faulting thread is %d\n", faultingThread->threadId);
|
||||
|
||||
if (faultingThread->userMode)
|
||||
{
|
||||
printkf("Destroying process %d\n", faultingThread->owner->pid);
|
||||
|
||||
destroyProcess(faultingThread->owner);
|
||||
}
|
||||
else
|
||||
{
|
||||
printkf("Destroying kernel thread %d\n", faultingThread->threadId);
|
||||
|
||||
destroyThread(faultingThread);
|
||||
}
|
||||
|
||||
waitForSchedule();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PANIC("General protection fault!!!");
|
||||
}
|
||||
}
|
124
kernel.soso/descriptortables.h
Normal file
124
kernel.soso/descriptortables.h
Normal file
|
@ -0,0 +1,124 @@
|
|||
#ifndef DESCRIPTORTABLES_H
|
||||
#define DESCRIPTORTABLES_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
void initializeDescriptorTables();
|
||||
|
||||
|
||||
struct GdtEntry
|
||||
{
|
||||
uint16 limit_low;
|
||||
uint16 base_low;
|
||||
uint8 base_middle;
|
||||
uint8 access;
|
||||
uint8 granularity;
|
||||
uint8 base_high;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct GdtEntry GdtEntry;
|
||||
|
||||
|
||||
struct GdtPointer
|
||||
{
|
||||
uint16 limit;
|
||||
uint32 base;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct GdtPointer GdtPointer;
|
||||
|
||||
|
||||
struct IdtEntry
|
||||
{
|
||||
uint16 base_lo;
|
||||
uint16 sel;
|
||||
uint8 always0;
|
||||
uint8 flags;
|
||||
uint16 base_hi;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct IdtEntry IdtEntry;
|
||||
|
||||
|
||||
struct IdtPointer
|
||||
{
|
||||
uint16 limit;
|
||||
uint32 base;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef struct IdtPointer IdtPointer;
|
||||
|
||||
struct Tss {
|
||||
uint16 previous_task, __previous_task_unused;
|
||||
uint32 esp0;
|
||||
uint16 ss0, __ss0_unused;
|
||||
uint32 esp1;
|
||||
uint16 ss1, __ss1_unused;
|
||||
uint32 esp2;
|
||||
uint16 ss2, __ss2_unused;
|
||||
uint32 cr3;
|
||||
uint32 eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi;
|
||||
uint16 es, __es_unused;
|
||||
uint16 cs, __cs_unused;
|
||||
uint16 ss, __ss_unused;
|
||||
uint16 ds, __ds_unused;
|
||||
uint16 fs, __fs_unused;
|
||||
uint16 gs, __gs_unused;
|
||||
uint16 ldt_selector, __ldt_sel_unused;
|
||||
uint16 debug_flag, io_map;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct Tss Tss;
|
||||
|
||||
|
||||
extern void isr0 ();
|
||||
extern void isr1 ();
|
||||
extern void isr2 ();
|
||||
extern void isr3 ();
|
||||
extern void isr4 ();
|
||||
extern void isr5 ();
|
||||
extern void isr6 ();
|
||||
extern void isr7 ();
|
||||
extern void isr8 ();
|
||||
extern void isr9 ();
|
||||
extern void isr10();
|
||||
extern void isr11();
|
||||
extern void isr12();
|
||||
extern void isr13();
|
||||
extern void isr14();
|
||||
extern void isr15();
|
||||
extern void isr16();
|
||||
extern void isr17();
|
||||
extern void isr18();
|
||||
extern void isr19();
|
||||
extern void isr20();
|
||||
extern void isr21();
|
||||
extern void isr22();
|
||||
extern void isr23();
|
||||
extern void isr24();
|
||||
extern void isr25();
|
||||
extern void isr26();
|
||||
extern void isr27();
|
||||
extern void isr28();
|
||||
extern void isr29();
|
||||
extern void isr30();
|
||||
extern void isr31();
|
||||
extern void irq0 ();
|
||||
extern void irq1 ();
|
||||
extern void irq2 ();
|
||||
extern void irq3 ();
|
||||
extern void irq4 ();
|
||||
extern void irq5 ();
|
||||
extern void irq6 ();
|
||||
extern void irq7 ();
|
||||
extern void irq8 ();
|
||||
extern void irq9 ();
|
||||
extern void irq10();
|
||||
extern void irq11();
|
||||
extern void irq12();
|
||||
extern void irq13();
|
||||
extern void irq14();
|
||||
extern void irq15();
|
||||
extern void isr128();
|
||||
|
||||
#endif //DESCRIPTORTABLES_H
|
145
kernel.soso/devfs.c
Normal file
145
kernel.soso/devfs.c
Normal file
|
@ -0,0 +1,145 @@
|
|||
#include "devfs.h"
|
||||
#include "common.h"
|
||||
#include "fs.h"
|
||||
#include "alloc.h"
|
||||
#include "device.h"
|
||||
#include "screen.h"
|
||||
#include "list.h"
|
||||
#include "spinlock.h"
|
||||
|
||||
static FileSystemNode* gDevRoot = NULL;
|
||||
|
||||
static List* gDeviceList = NULL;
|
||||
static Spinlock gDeviceListLock;
|
||||
|
||||
static BOOL devfs_open(File *node, uint32 flags);
|
||||
static FileSystemDirent *devfs_readdir(FileSystemNode *node, uint32 index);
|
||||
static FileSystemNode *devfs_finddir(FileSystemNode *node, char *name);
|
||||
|
||||
static FileSystemDirent gDirent;
|
||||
|
||||
void initializeDevFS()
|
||||
{
|
||||
gDevRoot = kmalloc(sizeof(FileSystemNode));
|
||||
memset((uint8*)gDevRoot, 0, sizeof(FileSystemNode));
|
||||
|
||||
gDevRoot->nodeType = FT_Directory;
|
||||
|
||||
FileSystemNode* rootFs = getFileSystemRootNode();
|
||||
|
||||
FileSystemNode* devNode = finddir_fs(rootFs, "dev");
|
||||
|
||||
if (devNode)
|
||||
{
|
||||
devNode->nodeType |= FT_MountPoint;
|
||||
devNode->mountPoint = gDevRoot;
|
||||
gDevRoot->parent = devNode->parent;
|
||||
strcpy(gDevRoot->name, devNode->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
PANIC("/dev does not exist!");
|
||||
}
|
||||
|
||||
gDevRoot->open = devfs_open;
|
||||
gDevRoot->finddir = devfs_finddir;
|
||||
gDevRoot->readdir = devfs_readdir;
|
||||
|
||||
gDeviceList = List_Create();
|
||||
Spinlock_Init(&gDeviceListLock);
|
||||
}
|
||||
|
||||
static BOOL devfs_open(File *node, uint32 flags)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static FileSystemDirent *devfs_readdir(FileSystemNode *node, uint32 index)
|
||||
{
|
||||
FileSystemDirent * result = NULL;
|
||||
|
||||
uint32 counter = 0;
|
||||
|
||||
Spinlock_Lock(&gDeviceListLock);
|
||||
|
||||
List_Foreach(n, gDeviceList)
|
||||
{
|
||||
if (index == counter)
|
||||
{
|
||||
FileSystemNode* deviceNode = (FileSystemNode*)n->data;
|
||||
strcpy(gDirent.name, deviceNode->name);
|
||||
gDirent.fileType = deviceNode->nodeType;
|
||||
gDirent.inode = index;
|
||||
result = &gDirent;
|
||||
break;
|
||||
}
|
||||
|
||||
++counter;
|
||||
}
|
||||
Spinlock_Unlock(&gDeviceListLock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static FileSystemNode *devfs_finddir(FileSystemNode *node, char *name)
|
||||
{
|
||||
FileSystemNode* result = NULL;
|
||||
|
||||
|
||||
Spinlock_Lock(&gDeviceListLock);
|
||||
|
||||
List_Foreach(n, gDeviceList)
|
||||
{
|
||||
FileSystemNode* deviceNode = (FileSystemNode*)n->data;
|
||||
|
||||
if (strcmp(name, deviceNode->name) == 0)
|
||||
{
|
||||
result = deviceNode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Spinlock_Unlock(&gDeviceListLock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
FileSystemNode* registerDevice(Device* device)
|
||||
{
|
||||
Spinlock_Lock(&gDeviceListLock);
|
||||
|
||||
List_Foreach(n, gDeviceList)
|
||||
{
|
||||
FileSystemNode* deviceNode = (FileSystemNode*)n->data;
|
||||
|
||||
if (strcmp(device->name, deviceNode->name) == 0)
|
||||
{
|
||||
//There is already a device with the same name
|
||||
Spinlock_Unlock(&gDeviceListLock);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
FileSystemNode* deviceNode = (FileSystemNode*)kmalloc(sizeof(FileSystemNode));
|
||||
memset((uint8*)deviceNode, 0, sizeof(FileSystemNode));
|
||||
strcpy(deviceNode->name, device->name);
|
||||
deviceNode->nodeType = device->deviceType;
|
||||
deviceNode->open = device->open;
|
||||
deviceNode->close = device->close;
|
||||
deviceNode->readBlock = device->readBlock;
|
||||
deviceNode->writeBlock = device->writeBlock;
|
||||
deviceNode->read = device->read;
|
||||
deviceNode->write = device->write;
|
||||
deviceNode->ioctl = device->ioctl;
|
||||
deviceNode->ftruncate = device->ftruncate;
|
||||
deviceNode->mmap = device->mmap;
|
||||
deviceNode->munmap = device->munmap;
|
||||
deviceNode->privateNodeData = device->privateData;
|
||||
deviceNode->parent = gDevRoot;
|
||||
|
||||
List_Append(gDeviceList, deviceNode);
|
||||
|
||||
Spinlock_Unlock(&gDeviceListLock);
|
||||
|
||||
return deviceNode;
|
||||
}
|
11
kernel.soso/devfs.h
Normal file
11
kernel.soso/devfs.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef DEVFS_H
|
||||
#define DEVFS_H
|
||||
|
||||
#include "device.h"
|
||||
#include "fs.h"
|
||||
#include "common.h"
|
||||
|
||||
void initializeDevFS();
|
||||
FileSystemNode* registerDevice(Device* device);
|
||||
|
||||
#endif // DEVFS_H
|
24
kernel.soso/device.h
Normal file
24
kernel.soso/device.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#ifndef DEVICE_H
|
||||
#define DEVICE_H
|
||||
|
||||
#include "common.h"
|
||||
#include "fs.h"
|
||||
|
||||
typedef struct Device
|
||||
{
|
||||
char name[16];
|
||||
FileType deviceType;
|
||||
ReadWriteBlockFunction readBlock;
|
||||
ReadWriteBlockFunction writeBlock;
|
||||
ReadWriteFunction read;
|
||||
ReadWriteFunction write;
|
||||
OpenFunction open;
|
||||
CloseFunction close;
|
||||
IoctlFunction ioctl;
|
||||
FtruncateFunction ftruncate;
|
||||
MmapFunction mmap;
|
||||
MunmapFunction munmap;
|
||||
void * privateData;
|
||||
} Device;
|
||||
|
||||
#endif // DEVICE_H
|
79
kernel.soso/elf.c
Normal file
79
kernel.soso/elf.c
Normal file
|
@ -0,0 +1,79 @@
|
|||
#include "elf.h"
|
||||
#include "common.h"
|
||||
#include "process.h"
|
||||
#include "screen.h"
|
||||
|
||||
BOOL isElf(char *elfData)
|
||||
{
|
||||
Elf32_Ehdr *hdr = (Elf32_Ehdr *) elfData;
|
||||
|
||||
if (hdr->e_ident[0] == 0x7f && hdr->e_ident[1] == 'E' &&
|
||||
hdr->e_ident[2] == 'L' && hdr->e_ident[3] == 'F')
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
uint32 loadElf(char *elfData)
|
||||
{
|
||||
uint32 v_begin, v_end;
|
||||
Elf32_Ehdr *hdr;
|
||||
Elf32_Phdr *p_entry;
|
||||
Elf32_Scdr *s_entry;
|
||||
|
||||
hdr = (Elf32_Ehdr *) elfData;
|
||||
p_entry = (Elf32_Phdr *) (elfData + hdr->e_phoff);
|
||||
|
||||
s_entry = (Elf32_Scdr*) (elfData + hdr->e_shoff);
|
||||
|
||||
if (isElf(elfData)==FALSE)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int pe = 0; pe < hdr->e_phnum; pe++, p_entry++)
|
||||
{
|
||||
//Read each entry
|
||||
printkf("loading p_entry %d\n", pe);
|
||||
|
||||
if (p_entry->p_type == PT_LOAD)
|
||||
{
|
||||
v_begin = p_entry->p_vaddr;
|
||||
v_end = p_entry->p_vaddr + p_entry->p_memsz;
|
||||
printkf("p_entry: %x\n", v_begin);
|
||||
if (v_begin < USER_OFFSET)
|
||||
{
|
||||
printkf("INFO: loadElf(): can't load executable below %x\n", USER_OFFSET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (v_end > USER_STACK)
|
||||
{
|
||||
printkf("INFO: loadElf(): can't load executable above %x\n", USER_STACK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//printkf("ELF: entry flags: %x (%d)\n", p_entry->p_flags, p_entry->p_flags);
|
||||
|
||||
|
||||
printkf("about to memcpy\n");
|
||||
memcpy((uint8 *) v_begin, (uint8 *) (elfData + p_entry->p_offset), p_entry->p_filesz);
|
||||
printkf("done with memcpy\n");
|
||||
if (p_entry->p_memsz > p_entry->p_filesz)
|
||||
{
|
||||
char* p = (char *) p_entry->p_vaddr;
|
||||
for (int i = p_entry->p_filesz; i < (int)(p_entry->p_memsz); i++)
|
||||
{
|
||||
p[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//entry point
|
||||
printkf("done loading ELF\n");
|
||||
return hdr->e_entry;
|
||||
}
|
||||
|
184
kernel.soso/elf.h
Normal file
184
kernel.soso/elf.h
Normal file
|
@ -0,0 +1,184 @@
|
|||
#ifndef ELF_H
|
||||
#define ELF_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
* ELF HEADER
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char e_ident[16]; /* ELF identification */
|
||||
uint16 e_type; /* 2 (exec file) */
|
||||
uint16 e_machine; /* 3 (intel architecture) */
|
||||
uint32 e_version; /* 1 */
|
||||
uint32 e_entry; /* starting point */
|
||||
uint32 e_phoff; /* program header table offset */
|
||||
uint32 e_shoff; /* section header table offset */
|
||||
uint32 e_flags; /* various flags */
|
||||
uint16 e_ehsize; /* ELF header (this) size */
|
||||
|
||||
uint16 e_phentsize; /* program header table entry size */
|
||||
uint16 e_phnum; /* number of entries */
|
||||
|
||||
uint16 e_shentsize; /* section header table entry size */
|
||||
uint16 e_shnum; /* number of entries */
|
||||
|
||||
uint16 e_shstrndx; /* index of the section name string table */
|
||||
} Elf32_Ehdr;
|
||||
|
||||
/*
|
||||
* ELF identification
|
||||
*/
|
||||
#define EI_MAG0 0
|
||||
#define EI_MAG1 1
|
||||
#define EI_MAG2 2
|
||||
#define EI_MAG3 3
|
||||
#define EI_CLASS 4
|
||||
#define EI_DATA 5
|
||||
#define EI_VERSION 6
|
||||
#define EI_PAD 7
|
||||
|
||||
/* EI_MAG */
|
||||
#define ELFMAG0 0x7f
|
||||
#define ELFMAG1 'E'
|
||||
#define ELFMAG2 'L'
|
||||
#define ELFMAG3 'F'
|
||||
|
||||
/* EI_CLASS */
|
||||
#define ELFCLASSNONE 0 /* invalid class */
|
||||
#define ELFCLASS32 1 /* 32-bit objects */
|
||||
#define ELFCLASS64 2 /* 64-bit objects */
|
||||
|
||||
/* EI_DATA */
|
||||
#define ELFDATANONE 0 /* invalide data encoding */
|
||||
#define ELFDATA2LSB 1 /* least significant byte first (0x01020304 is 0x04 0x03 0x02 0x01) */
|
||||
#define ELFDATA2MSB 2 /* most significant byte first (0x01020304 is 0x01 0x02 0x03 0x04) */
|
||||
|
||||
/* EI_VERSION */
|
||||
#define EV_CURRENT 1
|
||||
#define ELFVERSION EV_CURRENT
|
||||
|
||||
/*
|
||||
* PROGRAM HEADER
|
||||
*/
|
||||
typedef struct {
|
||||
uint32 p_type; /* type of segment */
|
||||
uint32 p_offset;
|
||||
uint32 p_vaddr;
|
||||
uint32 p_paddr;
|
||||
uint32 p_filesz;
|
||||
uint32 p_memsz;
|
||||
uint32 p_flags;
|
||||
uint32 p_align;
|
||||
} Elf32_Phdr;
|
||||
|
||||
/* p_type */
|
||||
#define PT_NULL 0
|
||||
#define PT_LOAD 1
|
||||
#define PT_DYNAMIC 2
|
||||
#define PT_INTERP 3
|
||||
#define PT_NOTE 4
|
||||
#define PT_SHLIB 5
|
||||
#define PT_PHDR 6
|
||||
#define PT_LOPROC 0x70000000
|
||||
#define PT_HIPROC 0x7fffffff
|
||||
|
||||
/* p_flags */
|
||||
#define PF_X 0x1
|
||||
#define PF_W 0x2
|
||||
#define PF_R 0x4
|
||||
|
||||
|
||||
|
||||
enum eElfSectionTypes {
|
||||
SHT_NULL, //0
|
||||
SHT_PROGBITS, //1
|
||||
SHT_SYMTAB, //2
|
||||
SHT_STRTAB, //3
|
||||
SHT_RELA, //4
|
||||
SHT_HASH, //5
|
||||
SHT_DYNAMIC, //6
|
||||
SHT_NOTE, //7
|
||||
SHT_NOBITS, //8
|
||||
SHT_REL, //9
|
||||
SHT_SHLIB, //A
|
||||
SHT_DYNSYM, //B
|
||||
SHT_LAST, //C
|
||||
SHT_LOPROC = 0x70000000,
|
||||
SHT_HIPROC = 0x7fffffff,
|
||||
SHT_LOUSER = 0x80000000,
|
||||
SHT_HIUSER = 0xffffffff
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32 name;
|
||||
uint32 type;
|
||||
uint32 flags;
|
||||
uint32 address;
|
||||
uint32 offset;
|
||||
uint32 size;
|
||||
uint32 link;
|
||||
uint32 info;
|
||||
uint32 addralign;
|
||||
uint32 entsize;
|
||||
} Elf32_Scdr;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
enum {
|
||||
R_386_NONE=0, // none
|
||||
R_386_32, // S+A
|
||||
R_386_PC32, // S+A-P
|
||||
R_386_GOT32, // G+A-P
|
||||
R_386_PLT32, // L+A-P
|
||||
R_386_COPY, // none
|
||||
R_386_GLOB_DAT, // S
|
||||
R_386_JMP_SLOT, // S
|
||||
R_386_RELATIVE, // B+A
|
||||
R_386_GOTOFF, // S+A-GOT
|
||||
R_386_GOTPC, // GOT+A-P
|
||||
R_386_LAST // none
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint16 d_tag;
|
||||
uint32 d_val; //Also d_ptr
|
||||
} Elf32_dyn;
|
||||
|
||||
|
||||
enum {
|
||||
DT_NULL, //!< Marks End of list
|
||||
DT_NEEDED, //!< Offset in strtab to needed library
|
||||
DT_PLTRELSZ, //!< Size in bytes of PLT
|
||||
DT_PLTGOT, //!< Address of PLT/GOT
|
||||
DT_HASH, //!< Address of symbol hash table
|
||||
DT_STRTAB, //!< String Table address
|
||||
DT_SYMTAB, //!< Symbol Table address
|
||||
DT_RELA, //!< Relocation table address
|
||||
DT_RELASZ, //!< Size of relocation table
|
||||
DT_RELAENT, //!< Size of entry in relocation table
|
||||
DT_STRSZ, //!< Size of string table
|
||||
DT_SYMENT, //!< Size of symbol table entry
|
||||
DT_INIT, //!< Address of initialisation function
|
||||
DT_FINI, //!< Address of termination function
|
||||
DT_SONAME, //!< String table offset of so name
|
||||
DT_RPATH, //!< String table offset of library path
|
||||
DT_SYMBOLIC,//!< Reverse order of symbol searching for library, search libs first then executable
|
||||
DT_REL, //!< Relocation Entries (Elf32_Rel instead of Elf32_Rela)
|
||||
DT_RELSZ, //!< Size of above table (bytes)
|
||||
DT_RELENT, //!< Size of entry in above table
|
||||
DT_PLTREL, //!< Relocation entry of PLT
|
||||
DT_DEBUG, //!< Debugging Entry - Unknown contents
|
||||
DT_TEXTREL, //!< Indicates that modifcations to a non-writeable segment may occur
|
||||
DT_JMPREL, //!< Address of PLT only relocation entries
|
||||
DT_LOPROC = 0x70000000, //!< Low Definable
|
||||
DT_HIPROC = 0x7FFFFFFF //!< High Definable
|
||||
};
|
||||
|
||||
BOOL isElf(char *elfData);
|
||||
uint32 loadElf(char *elfData);
|
||||
|
||||
#endif // ELF_H
|
672
kernel.soso/fatfilesystem.c
Normal file
672
kernel.soso/fatfilesystem.c
Normal file
|
@ -0,0 +1,672 @@
|
|||
#include "fatfilesystem.h"
|
||||
#include "common.h"
|
||||
#include "fs.h"
|
||||
#include "alloc.h"
|
||||
#include "fatfs_ff.h"
|
||||
#include "fatfs_diskio.h"
|
||||
#include "screen.h"
|
||||
|
||||
#define SEEK_SET 0 /* Seek from beginning of file. */
|
||||
#define SEEK_CUR 1 /* Seek from current position. */
|
||||
#define SEEK_END 2
|
||||
|
||||
#define O_RDONLY 00
|
||||
#define O_WRONLY 01
|
||||
#define O_RDWR 02
|
||||
|
||||
static BOOL mount(const char* sourcePath, const char* targetPath, uint32 flags, void *data);
|
||||
static BOOL checkMount(const char* sourcePath, const char* targetPath, uint32 flags, void *data);
|
||||
static FileSystemDirent* readdir(FileSystemNode *node, uint32 index);
|
||||
static FileSystemNode* finddir(FileSystemNode *node, char *name);
|
||||
static int32 read(File *file, uint32 size, uint8 *buffer);
|
||||
static int32 write(File *file, uint32 size, uint8 *buffer);
|
||||
static int32 lseek(File *file, int32 offset, int32 whence);
|
||||
static int32 stat(FileSystemNode *node, struct stat* buf);
|
||||
static BOOL open(File *file, uint32 flags);
|
||||
static void close(File *file);
|
||||
|
||||
static FileSystemDirent gFileSystemDirent;
|
||||
|
||||
static FileSystemNode* gMountedBlockDevices[FF_VOLUMES];
|
||||
|
||||
|
||||
void initializeFatFileSystem()
|
||||
{
|
||||
FileSystem fs;
|
||||
memset((uint8*)&fs, 0, sizeof(fs));
|
||||
strcpy(fs.name, "fat");
|
||||
fs.mount = mount;
|
||||
fs.checkMount = checkMount;
|
||||
|
||||
registerFileSystem(&fs);
|
||||
|
||||
for (int i = 0; i < FF_VOLUMES; ++i)
|
||||
{
|
||||
gMountedBlockDevices[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL mount(const char* sourcePath, const char* targetPath, uint32 flags, void *data)
|
||||
{
|
||||
printkf("fat mount source: %s\n", sourcePath);
|
||||
|
||||
FileSystemNode* node = getFileSystemNode(sourcePath);
|
||||
if (node && node->nodeType == FT_BlockDevice)
|
||||
{
|
||||
FileSystemNode* targetNode = getFileSystemNode(targetPath);
|
||||
if (targetNode)
|
||||
{
|
||||
if (targetNode->nodeType == FT_Directory)
|
||||
{
|
||||
printkf("fat mount target: %s\n", targetPath);
|
||||
|
||||
int32 volume = -1;
|
||||
for (int32 v = 0; v < FF_VOLUMES; ++v)
|
||||
{
|
||||
if (NULL == gMountedBlockDevices[v])
|
||||
{
|
||||
volume = v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (volume < 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
FileSystemNode* newNode = kmalloc(sizeof(FileSystemNode));
|
||||
|
||||
memset((uint8*)newNode, 0, sizeof(FileSystemNode));
|
||||
strcpy(newNode->name, targetNode->name);
|
||||
newNode->nodeType = FT_Directory;
|
||||
newNode->open = open;
|
||||
newNode->readdir = readdir;
|
||||
newNode->finddir = finddir;
|
||||
newNode->parent = targetNode->parent;
|
||||
newNode->mountSource = node;
|
||||
newNode->privateNodeData = (void*)volume;
|
||||
|
||||
gMountedBlockDevices[volume] = node;
|
||||
|
||||
FATFS* fatFs = (FATFS*)kmalloc(sizeof(FATFS));
|
||||
//uint8 work[512];
|
||||
//FRESULT fr = f_mkfs("", FM_FAT | FM_SFD, 512, work, 512);
|
||||
//Screen_PrintF("f_mkfs: %d\n", fr);
|
||||
char path[8];
|
||||
sprintf(path, "%d:", volume);
|
||||
FRESULT fr = f_mount(fatFs, path, 1);
|
||||
//Screen_PrintF("f_mount: fr:%d drv:%d\n", fr, fatFs->pdrv);
|
||||
|
||||
if (FR_OK == fr)
|
||||
{
|
||||
targetNode->nodeType |= FT_MountPoint;
|
||||
targetNode->mountPoint = newNode;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
kfree(newNode);
|
||||
|
||||
kfree(fatFs);
|
||||
|
||||
gMountedBlockDevices[volume] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL checkMount(const char* sourcePath, const char* targetPath, uint32 flags, void *data)
|
||||
{
|
||||
FileSystemNode* node = getFileSystemNode(sourcePath);
|
||||
if (node && node->nodeType == FT_BlockDevice)
|
||||
{
|
||||
FileSystemNode* targetNode = getFileSystemNode(targetPath);
|
||||
if (targetNode)
|
||||
{
|
||||
if (targetNode->nodeType == FT_Directory)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static FileSystemDirent* readdir(FileSystemNode *node, uint32 index)
|
||||
{
|
||||
//when node is the root of mounted filesystem,
|
||||
//node->mountSource is the source node (eg. disk partition /dev/hd1p1)
|
||||
|
||||
//Screen_PrintF("readdir1: node->name:%s\n", node->name);
|
||||
|
||||
uint8 targetPath[128];
|
||||
|
||||
FileSystemNode *n = node;
|
||||
int charIndex = 126;
|
||||
memset(targetPath, 0, 128);
|
||||
while (NULL == n->mountSource)
|
||||
{
|
||||
int length = strlen(n->name);
|
||||
|
||||
charIndex -= length;
|
||||
|
||||
if (charIndex < 2)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpyNonNull((char*)(targetPath + charIndex), n->name);
|
||||
charIndex -= 1;
|
||||
targetPath[charIndex] = '/';
|
||||
|
||||
n = n->parent;
|
||||
}
|
||||
|
||||
char number[8];
|
||||
sprintf(number, "%d", n->privateNodeData);//volume nuber
|
||||
|
||||
targetPath[charIndex] = ':';
|
||||
int length = strlen(number);
|
||||
charIndex -= length;
|
||||
if (charIndex < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpyNonNull((char*)(targetPath + charIndex), number);
|
||||
uint8* target = targetPath + charIndex;
|
||||
|
||||
//Screen_PrintF("readdir: targetpath:[%s]\n", target);
|
||||
|
||||
DIR dir;
|
||||
FRESULT fr = f_opendir(&dir, (TCHAR*)target);
|
||||
if (FR_OK == fr)
|
||||
{
|
||||
FILINFO fileInfo;
|
||||
for (int i = 0; i <= index; ++i)
|
||||
{
|
||||
memset((uint8*)&fileInfo, 0, sizeof(FILINFO));
|
||||
fr = f_readdir(&dir, &fileInfo);
|
||||
|
||||
if (strlen(fileInfo.fname) <= 0)
|
||||
{
|
||||
f_closedir(&dir);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
gFileSystemDirent.inode = 0;
|
||||
strcpy(gFileSystemDirent.name, fileInfo.fname);
|
||||
if ((fileInfo.fattrib & AM_DIR) == AM_DIR)
|
||||
{
|
||||
gFileSystemDirent.fileType = FT_Directory;
|
||||
}
|
||||
else
|
||||
{
|
||||
gFileSystemDirent.fileType = FT_File;
|
||||
}
|
||||
|
||||
f_closedir(&dir);
|
||||
|
||||
return &gFileSystemDirent;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static FileSystemNode* finddir(FileSystemNode *node, char *name)
|
||||
{
|
||||
//when node is the root of mounted filesystem,
|
||||
//node->mountSource is the source node (eg. disk partition /dev/hd1p1)
|
||||
|
||||
//Screen_PrintF("finddir1: node->name:%s name:%s\n", node->name, name);
|
||||
|
||||
FileSystemNode* child = node->firstChild;
|
||||
while (NULL != child)
|
||||
{
|
||||
if (strcmp(name, child->name) == 0)
|
||||
{
|
||||
return child;
|
||||
}
|
||||
|
||||
child = child->nextSibling;
|
||||
}
|
||||
|
||||
//If we are here, this file is accesed first time in this session.
|
||||
//So we create its node...
|
||||
|
||||
uint8 targetPath[128];
|
||||
|
||||
FileSystemNode *n = node;
|
||||
int charIndex = 126;
|
||||
memset(targetPath, 0, 128);
|
||||
int length = strlen(name);
|
||||
charIndex -= length;
|
||||
strcpyNonNull((char*)(targetPath + charIndex), name);
|
||||
charIndex -= 1;
|
||||
targetPath[charIndex] = '/';
|
||||
while (NULL == n->mountSource)
|
||||
{
|
||||
length = strlen(n->name);
|
||||
charIndex -= length;
|
||||
|
||||
if (charIndex < 2)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpyNonNull((char*)(targetPath + charIndex), n->name);
|
||||
charIndex -= 1;
|
||||
targetPath[charIndex] = '/';
|
||||
|
||||
n = n->parent;
|
||||
}
|
||||
|
||||
char number[8];
|
||||
sprintf(number, "%d", n->privateNodeData);//volume nuber
|
||||
|
||||
targetPath[charIndex] = ':';
|
||||
length = strlen(number);
|
||||
charIndex -= length;
|
||||
if (charIndex < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpyNonNull((char*)(targetPath + charIndex), number);
|
||||
uint8* target = targetPath + charIndex;
|
||||
|
||||
//Screen_PrintF("finddir: targetpath:[%s]\n", target);
|
||||
|
||||
FILINFO fileInfo;
|
||||
memset((uint8*)&fileInfo, 0, sizeof(FILINFO));
|
||||
FRESULT fr = f_stat((TCHAR*)target, &fileInfo);
|
||||
if (FR_OK == fr)
|
||||
{
|
||||
FileSystemNode* newNode = kmalloc(sizeof(FileSystemNode));
|
||||
|
||||
memset((uint8*)newNode, 0, sizeof(FileSystemNode));
|
||||
strcpy(newNode->name, name);
|
||||
newNode->parent = node;
|
||||
newNode->readdir = readdir;
|
||||
newNode->finddir = finddir;
|
||||
newNode->open = open;
|
||||
newNode->close = close;
|
||||
newNode->read = read;
|
||||
newNode->write = write;
|
||||
newNode->lseek = lseek;
|
||||
newNode->stat = stat;
|
||||
newNode->length = fileInfo.fsize;
|
||||
|
||||
if ((fileInfo.fattrib & AM_DIR) == AM_DIR)
|
||||
{
|
||||
newNode->nodeType = FT_Directory;
|
||||
}
|
||||
else
|
||||
{
|
||||
newNode->nodeType = FT_File;
|
||||
}
|
||||
|
||||
if (NULL == node->firstChild)
|
||||
{
|
||||
node->firstChild = newNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
FileSystemNode* child = node->firstChild;
|
||||
while (NULL != child->nextSibling)
|
||||
{
|
||||
child = child->nextSibling;
|
||||
}
|
||||
child->nextSibling = newNode;
|
||||
}
|
||||
|
||||
//Screen_PrintF("finddir: returning [%s]\n", name);
|
||||
return newNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Screen_PrintF("finddir error: fr: %d]\n", fr);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int32 read(File *file, uint32 size, uint8 *buffer)
|
||||
{
|
||||
if (file->privateData == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
FIL* f = (FIL*)file->privateData;
|
||||
|
||||
UINT br = 0;
|
||||
FRESULT fr = f_read(f, buffer, size, &br);
|
||||
file->offset = f->fptr;
|
||||
//Screen_PrintF("fat read: name:%s size:%d hasRead:%d, fr:%d\n", file->node->name, size, br, fr);
|
||||
if (FR_OK == fr)
|
||||
{
|
||||
return br;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int32 write(File *file, uint32 size, uint8 *buffer)
|
||||
{
|
||||
if (file->privateData == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
FIL* f = (FIL*)file->privateData;
|
||||
|
||||
UINT bw = 0;
|
||||
FRESULT fr = f_write(f, buffer, size, &bw);
|
||||
file->offset = f->fptr;
|
||||
if (FR_OK == fr)
|
||||
{
|
||||
return bw;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int32 lseek(File *file, int32 offset, int32 whence)
|
||||
{
|
||||
if (file->privateData == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
FIL* f = (FIL*)file->privateData;
|
||||
|
||||
FRESULT fr = FR_INVALID_OBJECT;
|
||||
|
||||
switch (whence)
|
||||
{
|
||||
case SEEK_SET:
|
||||
fr = f_lseek(f, offset);
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
fr = f_lseek(f, f_tell(f) + offset);
|
||||
break;
|
||||
case SEEK_END:
|
||||
fr = f_lseek(f, f_size(f) + offset);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (FR_OK == fr)
|
||||
{
|
||||
file->offset = f->fptr;
|
||||
|
||||
return file->offset;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int32 stat(FileSystemNode *node, struct stat* buf)
|
||||
{
|
||||
//Screen_PrintF("fat stat [%s]\n", node->name);
|
||||
|
||||
uint8 targetPath[128];
|
||||
|
||||
FileSystemNode *n = node;
|
||||
int charIndex = 126;
|
||||
memset(targetPath, 0, 128);
|
||||
while (NULL == n->mountSource)
|
||||
{
|
||||
int length = strlen(n->name);
|
||||
charIndex -= length;
|
||||
|
||||
if (charIndex < 2)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpyNonNull((char*)(targetPath + charIndex), n->name);
|
||||
charIndex -= 1;
|
||||
targetPath[charIndex] = '/';
|
||||
|
||||
n = n->parent;
|
||||
}
|
||||
|
||||
char number[8];
|
||||
sprintf(number, "%d", n->privateNodeData);//volume nuber
|
||||
|
||||
targetPath[charIndex] = ':';
|
||||
int length = strlen(number);
|
||||
charIndex -= length;
|
||||
if (charIndex < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpyNonNull((char*)(targetPath + charIndex), number);
|
||||
uint8* target = targetPath + charIndex;
|
||||
|
||||
//Screen_PrintF("fat stat target:[%s]\n", target);
|
||||
|
||||
FILINFO fileInfo;
|
||||
memset((uint8*)&fileInfo, 0, sizeof(FILINFO));
|
||||
FRESULT fr = f_stat((TCHAR*)target, &fileInfo);
|
||||
if (FR_OK == fr)
|
||||
{
|
||||
if ((fileInfo.fattrib & AM_DIR) == AM_DIR)
|
||||
{
|
||||
node->nodeType = FT_Directory;
|
||||
}
|
||||
else
|
||||
{
|
||||
node->nodeType = FT_File;
|
||||
}
|
||||
|
||||
node->length = fileInfo.fsize;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1; //Error
|
||||
}
|
||||
|
||||
static BOOL open(File *file, uint32 flags)
|
||||
{
|
||||
//Screen_PrintF("fat open %s\n", file->node->name);
|
||||
|
||||
FileSystemNode *node = file->node;
|
||||
|
||||
if (node->nodeType == FT_Directory)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
uint8 targetPath[128];
|
||||
|
||||
FileSystemNode *n = node;
|
||||
int charIndex = 126;
|
||||
memset(targetPath, 0, 128);
|
||||
while (NULL == n->mountSource)
|
||||
{
|
||||
int length = strlen(n->name);
|
||||
charIndex -= length;
|
||||
|
||||
if (charIndex < 2)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpyNonNull((char*)(targetPath + charIndex), n->name);
|
||||
charIndex -= 1;
|
||||
targetPath[charIndex] = '/';
|
||||
|
||||
n = n->parent;
|
||||
}
|
||||
|
||||
char number[8];
|
||||
sprintf(number, "%d", n->privateNodeData);//volume nuber
|
||||
|
||||
targetPath[charIndex] = ':';
|
||||
int length = strlen(number);
|
||||
charIndex -= length;
|
||||
if (charIndex < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpyNonNull((char*)(targetPath + charIndex), number);
|
||||
uint8* target = targetPath + charIndex;
|
||||
|
||||
//Screen_PrintF("fat open %s\n", target);
|
||||
|
||||
int fatfsMode = FA_READ;
|
||||
|
||||
switch (flags)
|
||||
{
|
||||
case O_RDONLY:
|
||||
fatfsMode = FA_READ;
|
||||
break;
|
||||
case O_WRONLY:
|
||||
fatfsMode = FA_WRITE;
|
||||
break;
|
||||
case O_RDWR:
|
||||
fatfsMode = (FA_READ | FA_WRITE);
|
||||
break;
|
||||
//TODO: append, create
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
FIL* f = (FIL*)kmalloc(sizeof(FIL));
|
||||
FRESULT fr = f_open(f, (TCHAR*)target, fatfsMode);
|
||||
if (FR_OK == fr)
|
||||
{
|
||||
file->offset = f->fptr;
|
||||
|
||||
file->privateData = f;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void close(File *file)
|
||||
{
|
||||
if (file->privateData == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FIL* f = (FIL*)file->privateData;
|
||||
|
||||
f_close(f);
|
||||
|
||||
kfree(f);
|
||||
|
||||
file->privateData = NULL;
|
||||
}
|
||||
|
||||
DSTATUS disk_initialize(
|
||||
BYTE pdrv //Physical drive nmuber
|
||||
)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
DSTATUS disk_status(BYTE pdrv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
DRESULT disk_read (
|
||||
BYTE pdrv, /* Physical drive nmuber (0) */
|
||||
BYTE *buff, /* Pointer to the data buffer to store read data */
|
||||
DWORD sector, /* Start sector number (LBA) */
|
||||
UINT count /* Number of sectors to read */
|
||||
)
|
||||
{
|
||||
//Screen_PrintF("disk_read() drv:%d sector:%d count:%d\n", pdrv, sector, count);
|
||||
|
||||
if (gMountedBlockDevices[pdrv] == NULL) return RES_NOTRDY;
|
||||
|
||||
//if (sector >= RamDiskSize) return RES_PARERR;
|
||||
|
||||
gMountedBlockDevices[pdrv]->readBlock(gMountedBlockDevices[pdrv], (uint32)sector, count, buff);
|
||||
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
DRESULT disk_write (
|
||||
BYTE pdrv, /* Physical drive nmuber (0) */
|
||||
const BYTE *buff, /* Pointer to the data to be written */
|
||||
DWORD sector, /* Start sector number (LBA) */
|
||||
UINT count /* Number of sectors to write */
|
||||
)
|
||||
{
|
||||
if (gMountedBlockDevices[pdrv] == NULL) return RES_NOTRDY;
|
||||
|
||||
//if (sector >= RamDiskSize) return RES_PARERR;
|
||||
|
||||
gMountedBlockDevices[pdrv]->writeBlock(gMountedBlockDevices[pdrv], (uint32)sector, count, (uint8*)buff);
|
||||
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
DRESULT disk_ioctl (
|
||||
BYTE pdrv, /* Physical drive nmuber (0) */
|
||||
BYTE ctrl, /* Control code */
|
||||
void* buff /* Buffer to send/receive data block */
|
||||
)
|
||||
{
|
||||
if (gMountedBlockDevices[pdrv] == NULL) return RES_ERROR;
|
||||
|
||||
DRESULT dr = RES_ERROR;
|
||||
|
||||
File* f = NULL;
|
||||
|
||||
uint32 value = 0;
|
||||
|
||||
switch (ctrl)
|
||||
{
|
||||
case CTRL_SYNC:
|
||||
dr = RES_OK;
|
||||
break;
|
||||
case GET_SECTOR_COUNT:
|
||||
f = open_fs(gMountedBlockDevices[pdrv], 0);
|
||||
if (f)
|
||||
{
|
||||
ioctl_fs(f, IC_GetSectorCount, &value);
|
||||
*(DWORD*)buff = value;
|
||||
dr = RES_OK;
|
||||
close_fs(f);
|
||||
}
|
||||
printkf("disk_ioctl GET_SECTOR_COUNT: %d\n", value);
|
||||
break;
|
||||
case GET_BLOCK_SIZE:
|
||||
f = open_fs(gMountedBlockDevices[pdrv], 0);
|
||||
if (f)
|
||||
{
|
||||
ioctl_fs(f, IC_GetSectorSizeInBytes, &value);
|
||||
*(DWORD*)buff = value;
|
||||
dr = RES_OK;
|
||||
close_fs(f);
|
||||
}
|
||||
printkf("disk_ioctl GET_BLOCK_SIZE: %d\n", value);
|
||||
*(DWORD*)buff = value;
|
||||
dr = RES_OK;
|
||||
break;
|
||||
}
|
||||
return dr;
|
||||
}
|
6
kernel.soso/fatfilesystem.h
Normal file
6
kernel.soso/fatfilesystem.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef FATFILESYSTEM_H
|
||||
#define FATFILESYSTEM_H
|
||||
|
||||
void initializeFatFileSystem();
|
||||
|
||||
#endif // FATFILESYSTEM_H
|
80
kernel.soso/fatfs_diskio.h
Normal file
80
kernel.soso/fatfs_diskio.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*-----------------------------------------------------------------------/
|
||||
/ Low level disk interface modlue include file (C)ChaN, 2014 /
|
||||
/-----------------------------------------------------------------------*/
|
||||
|
||||
#ifndef _DISKIO_DEFINED
|
||||
#define _DISKIO_DEFINED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "fatfs_integer.h"
|
||||
|
||||
|
||||
/* Status of Disk Functions */
|
||||
typedef BYTE DSTATUS;
|
||||
|
||||
/* Results of Disk Functions */
|
||||
typedef enum {
|
||||
RES_OK = 0, /* 0: Successful */
|
||||
RES_ERROR, /* 1: R/W Error */
|
||||
RES_WRPRT, /* 2: Write Protected */
|
||||
RES_NOTRDY, /* 3: Not Ready */
|
||||
RES_PARERR /* 4: Invalid Parameter */
|
||||
} DRESULT;
|
||||
|
||||
|
||||
/*---------------------------------------*/
|
||||
/* Prototypes for disk control functions */
|
||||
|
||||
|
||||
DSTATUS disk_initialize (BYTE pdrv);
|
||||
DSTATUS disk_status (BYTE pdrv);
|
||||
DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
|
||||
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
|
||||
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
|
||||
|
||||
|
||||
/* Disk Status Bits (DSTATUS) */
|
||||
|
||||
#define STA_NOINIT 0x01 /* Drive not initialized */
|
||||
#define STA_NODISK 0x02 /* No medium in the drive */
|
||||
#define STA_PROTECT 0x04 /* Write protected */
|
||||
|
||||
|
||||
/* Command code for disk_ioctrl fucntion */
|
||||
|
||||
/* Generic command (Used by FatFs) */
|
||||
#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */
|
||||
#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */
|
||||
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */
|
||||
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */
|
||||
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */
|
||||
|
||||
/* Generic command (Not used by FatFs) */
|
||||
#define CTRL_POWER 5 /* Get/Set power status */
|
||||
#define CTRL_LOCK 6 /* Lock/Unlock media removal */
|
||||
#define CTRL_EJECT 7 /* Eject media */
|
||||
#define CTRL_FORMAT 8 /* Create physical format on the media */
|
||||
|
||||
/* MMC/SDC specific ioctl command */
|
||||
#define MMC_GET_TYPE 10 /* Get card type */
|
||||
#define MMC_GET_CSD 11 /* Get CSD */
|
||||
#define MMC_GET_CID 12 /* Get CID */
|
||||
#define MMC_GET_OCR 13 /* Get OCR */
|
||||
#define MMC_GET_SDSTAT 14 /* Get SD status */
|
||||
#define ISDIO_READ 55 /* Read data form SD iSDIO register */
|
||||
#define ISDIO_WRITE 56 /* Write data to SD iSDIO register */
|
||||
#define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */
|
||||
|
||||
/* ATA/CF specific ioctl command */
|
||||
#define ATA_GET_REV 20 /* Get F/W revision */
|
||||
#define ATA_GET_MODEL 21 /* Get model name */
|
||||
#define ATA_GET_SN 22 /* Get serial number */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
6555
kernel.soso/fatfs_ff.c
Normal file
6555
kernel.soso/fatfs_ff.c
Normal file
File diff suppressed because it is too large
Load Diff
366
kernel.soso/fatfs_ff.h
Normal file
366
kernel.soso/fatfs_ff.h
Normal file
|
@ -0,0 +1,366 @@
|
|||
/*----------------------------------------------------------------------------/
|
||||
/ FatFs - Generic FAT Filesystem module R0.13a /
|
||||
/-----------------------------------------------------------------------------/
|
||||
/
|
||||
/ Copyright (C) 2017, ChaN, all right reserved.
|
||||
/
|
||||
/ FatFs module is an open source software. Redistribution and use of FatFs in
|
||||
/ source and binary forms, with or without modification, are permitted provided
|
||||
/ that the following condition is met:
|
||||
|
||||
/ 1. Redistributions of source code must retain the above copyright notice,
|
||||
/ this condition and the following disclaimer.
|
||||
/
|
||||
/ This software is provided by the copyright holder and contributors "AS IS"
|
||||
/ and any warranties related to this software are DISCLAIMED.
|
||||
/ The copyright owner or contributors be NOT LIABLE for any damages caused
|
||||
/ by use of this software.
|
||||
/
|
||||
/----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#ifndef FF_DEFINED
|
||||
#define FF_DEFINED 89352 /* Revision ID */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "fatfs_integer.h" /* Basic integer types */
|
||||
#include "fatfs_ffconf.h" /* FatFs configuration options */
|
||||
|
||||
#if FF_DEFINED != FFCONF_DEF
|
||||
#error Wrong configuration file (ffconf.h).
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Definitions of volume management */
|
||||
|
||||
#if FF_MULTI_PARTITION /* Multiple partition configuration */
|
||||
typedef struct {
|
||||
BYTE pd; /* Physical drive number */
|
||||
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
|
||||
} PARTITION;
|
||||
extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Type of path name strings on FatFs API */
|
||||
|
||||
#ifndef _INC_TCHAR
|
||||
#define _INC_TCHAR
|
||||
|
||||
#if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */
|
||||
typedef WCHAR TCHAR;
|
||||
#define _T(x) L ## x
|
||||
#define _TEXT(x) L ## x
|
||||
#elif FF_USE_LFN && FF_LFN_UNICODE == 2 /* Unicode in UTF-8 encoding */
|
||||
typedef char TCHAR;
|
||||
#define _T(x) u8 ## x
|
||||
#define _TEXT(x) u8 ## x
|
||||
#elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 2)
|
||||
#error Wrong FF_LFN_UNICODE setting
|
||||
#else /* ANSI/OEM code in SBCS/DBCS */
|
||||
typedef char TCHAR;
|
||||
#define _T(x) x
|
||||
#define _TEXT(x) x
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Type of file size variables */
|
||||
|
||||
#if FF_FS_EXFAT
|
||||
typedef QWORD FSIZE_t;
|
||||
#else
|
||||
typedef DWORD FSIZE_t;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Filesystem object structure (FATFS) */
|
||||
|
||||
typedef struct {
|
||||
BYTE fs_type; /* Filesystem type (0:N/A) */
|
||||
BYTE pdrv; /* Physical drive number */
|
||||
BYTE n_fats; /* Number of FATs (1 or 2) */
|
||||
BYTE wflag; /* win[] flag (b0:dirty) */
|
||||
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
|
||||
WORD id; /* Volume mount ID */
|
||||
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
|
||||
WORD csize; /* Cluster size [sectors] */
|
||||
#if FF_MAX_SS != FF_MIN_SS
|
||||
WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
|
||||
#endif
|
||||
#if FF_USE_LFN
|
||||
WCHAR* lfnbuf; /* LFN working buffer */
|
||||
#endif
|
||||
#if FF_FS_EXFAT
|
||||
BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */
|
||||
#endif
|
||||
#if FF_FS_REENTRANT
|
||||
FF_SYNC_t sobj; /* Identifier of sync object */
|
||||
#endif
|
||||
#if !FF_FS_READONLY
|
||||
DWORD last_clst; /* Last allocated cluster */
|
||||
DWORD free_clst; /* Number of free clusters */
|
||||
#endif
|
||||
#if FF_FS_RPATH
|
||||
DWORD cdir; /* Current directory start cluster (0:root) */
|
||||
#if FF_FS_EXFAT
|
||||
DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */
|
||||
DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */
|
||||
DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */
|
||||
#endif
|
||||
#endif
|
||||
DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */
|
||||
DWORD fsize; /* Size of an FAT [sectors] */
|
||||
DWORD volbase; /* Volume base sector */
|
||||
DWORD fatbase; /* FAT base sector */
|
||||
DWORD dirbase; /* Root directory base sector/cluster */
|
||||
DWORD database; /* Data base sector */
|
||||
DWORD winsect; /* Current sector appearing in the win[] */
|
||||
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
|
||||
} FATFS;
|
||||
|
||||
|
||||
|
||||
/* Object ID and allocation information (FFOBJID) */
|
||||
|
||||
typedef struct {
|
||||
FATFS* fs; /* Pointer to the hosting volume of this object */
|
||||
WORD id; /* Hosting volume mount ID */
|
||||
BYTE attr; /* Object attribute */
|
||||
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:flagmented in this session, b2:sub-directory stretched) */
|
||||
DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
|
||||
FSIZE_t objsize; /* Object size (valid when sclust != 0) */
|
||||
#if FF_FS_EXFAT
|
||||
DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */
|
||||
DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */
|
||||
DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */
|
||||
DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */
|
||||
DWORD c_ofs; /* Offset in the containing directory (valid when file object and sclust != 0) */
|
||||
#endif
|
||||
#if FF_FS_LOCK
|
||||
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
|
||||
#endif
|
||||
} FFOBJID;
|
||||
|
||||
|
||||
|
||||
/* File object structure (FIL) */
|
||||
|
||||
typedef struct {
|
||||
FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */
|
||||
BYTE flag; /* File status flags */
|
||||
BYTE err; /* Abort flag (error code) */
|
||||
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
|
||||
DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */
|
||||
DWORD sect; /* Sector number appearing in buf[] (0:invalid) */
|
||||
#if !FF_FS_READONLY
|
||||
DWORD dir_sect; /* Sector number containing the directory entry (not used at exFAT) */
|
||||
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */
|
||||
#endif
|
||||
#if FF_USE_FASTSEEK
|
||||
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
|
||||
#endif
|
||||
#if !FF_FS_TINY
|
||||
BYTE buf[FF_MAX_SS]; /* File private data read/write window */
|
||||
#endif
|
||||
} FIL;
|
||||
|
||||
|
||||
|
||||
/* Directory object structure (DIR) */
|
||||
|
||||
typedef struct {
|
||||
FFOBJID obj; /* Object identifier */
|
||||
DWORD dptr; /* Current read/write offset */
|
||||
DWORD clust; /* Current cluster */
|
||||
DWORD sect; /* Current sector (0:Read operation has terminated) */
|
||||
BYTE* dir; /* Pointer to the directory item in the win[] */
|
||||
BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */
|
||||
#if FF_USE_LFN
|
||||
DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
|
||||
#endif
|
||||
#if FF_USE_FIND
|
||||
const TCHAR* pat; /* Pointer to the name matching pattern */
|
||||
#endif
|
||||
} DIR;
|
||||
|
||||
|
||||
|
||||
/* File information structure (FILINFO) */
|
||||
|
||||
typedef struct {
|
||||
FSIZE_t fsize; /* File size */
|
||||
WORD fdate; /* Modified date */
|
||||
WORD ftime; /* Modified time */
|
||||
BYTE fattrib; /* File attribute */
|
||||
#if FF_USE_LFN
|
||||
TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */
|
||||
TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */
|
||||
#else
|
||||
TCHAR fname[12 + 1]; /* File name */
|
||||
#endif
|
||||
} FILINFO;
|
||||
|
||||
|
||||
|
||||
/* File function return code (FRESULT) */
|
||||
|
||||
typedef enum {
|
||||
FR_OK = 0, /* (0) Succeeded */
|
||||
FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
|
||||
FR_INT_ERR, /* (2) Assertion failed */
|
||||
FR_NOT_READY, /* (3) The physical drive cannot work */
|
||||
FR_NO_FILE, /* (4) Could not find the file */
|
||||
FR_NO_PATH, /* (5) Could not find the path */
|
||||
FR_INVALID_NAME, /* (6) The path name format is invalid */
|
||||
FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
|
||||
FR_EXIST, /* (8) Access denied due to prohibited access */
|
||||
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
|
||||
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
|
||||
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
|
||||
FR_NOT_ENABLED, /* (12) The volume has no work area */
|
||||
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
|
||||
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */
|
||||
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
|
||||
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
|
||||
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
|
||||
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */
|
||||
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
|
||||
} FRESULT;
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* FatFs module application interface */
|
||||
|
||||
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
|
||||
FRESULT f_close (FIL* fp); /* Close an open file object */
|
||||
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */
|
||||
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */
|
||||
FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */
|
||||
FRESULT f_truncate (FIL* fp); /* Truncate the file */
|
||||
FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */
|
||||
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
|
||||
FRESULT f_closedir (DIR* dp); /* Close an open directory */
|
||||
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
|
||||
FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */
|
||||
FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */
|
||||
FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
|
||||
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
|
||||
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
|
||||
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
|
||||
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */
|
||||
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */
|
||||
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
|
||||
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
|
||||
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
|
||||
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
|
||||
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
|
||||
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
|
||||
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
|
||||
FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
|
||||
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
|
||||
FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */
|
||||
FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */
|
||||
FRESULT f_setcp (WORD cp); /* Set current code page */
|
||||
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
|
||||
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
|
||||
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
|
||||
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
|
||||
|
||||
#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
|
||||
#define f_error(fp) ((fp)->err)
|
||||
#define f_tell(fp) ((fp)->fptr)
|
||||
#define f_size(fp) ((fp)->obj.objsize)
|
||||
#define f_rewind(fp) f_lseek((fp), 0)
|
||||
#define f_rewinddir(dp) f_readdir((dp), 0)
|
||||
#define f_rmdir(path) f_unlink(path)
|
||||
#define f_unmount(path) f_mount(0, path, 0)
|
||||
|
||||
#ifndef EOF
|
||||
#define EOF (-1)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Additional user defined functions */
|
||||
|
||||
/* RTC function */
|
||||
#if !FF_FS_READONLY && !FF_FS_NORTC
|
||||
DWORD get_fattime (void);
|
||||
#endif
|
||||
|
||||
/* LFN support functions */
|
||||
#if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */
|
||||
WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */
|
||||
WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */
|
||||
DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */
|
||||
#endif
|
||||
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
|
||||
void* ff_memalloc (UINT msize); /* Allocate memory block */
|
||||
void ff_memfree (void* mblock); /* Free memory block */
|
||||
#endif
|
||||
|
||||
/* Sync functions */
|
||||
#if FF_FS_REENTRANT
|
||||
int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj); /* Create a sync object */
|
||||
int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */
|
||||
void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */
|
||||
int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Flags and offset address */
|
||||
|
||||
|
||||
/* File access mode and open method flags (3rd argument of f_open) */
|
||||
#define FA_READ 0x01
|
||||
#define FA_WRITE 0x02
|
||||
#define FA_OPEN_EXISTING 0x00
|
||||
#define FA_CREATE_NEW 0x04
|
||||
#define FA_CREATE_ALWAYS 0x08
|
||||
#define FA_OPEN_ALWAYS 0x10
|
||||
#define FA_OPEN_APPEND 0x30
|
||||
|
||||
/* Fast seek controls (2nd argument of f_lseek) */
|
||||
#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
|
||||
|
||||
/* Format options (2nd argument of f_mkfs) */
|
||||
#define FM_FAT 0x01
|
||||
#define FM_FAT32 0x02
|
||||
#define FM_EXFAT 0x04
|
||||
#define FM_ANY 0x07
|
||||
#define FM_SFD 0x08
|
||||
|
||||
/* Filesystem type (FATFS.fs_type) */
|
||||
#define FS_FAT12 1
|
||||
#define FS_FAT16 2
|
||||
#define FS_FAT32 3
|
||||
#define FS_EXFAT 4
|
||||
|
||||
/* File attribute bits for directory entry (FILINFO.fattrib) */
|
||||
#define AM_RDO 0x01 /* Read only */
|
||||
#define AM_HID 0x02 /* Hidden */
|
||||
#define AM_SYS 0x04 /* System */
|
||||
#define AM_DIR 0x10 /* Directory */
|
||||
#define AM_ARC 0x20 /* Archive */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FF_DEFINED */
|
283
kernel.soso/fatfs_ffconf.h
Normal file
283
kernel.soso/fatfs_ffconf.h
Normal file
|
@ -0,0 +1,283 @@
|
|||
/*---------------------------------------------------------------------------/
|
||||
/ FatFs - Configuration file
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define FFCONF_DEF 89352 /* Revision ID */
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Function Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define FF_FS_READONLY 0
|
||||
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
|
||||
/ Read-only configuration removes writing API functions, f_write(), f_sync(),
|
||||
/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
|
||||
/ and optional writing functions as well. */
|
||||
|
||||
|
||||
#define FF_FS_MINIMIZE 0
|
||||
/* This option defines minimization level to remove some basic API functions.
|
||||
/
|
||||
/ 0: Basic functions are fully enabled.
|
||||
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()
|
||||
/ are removed.
|
||||
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
|
||||
/ 3: f_lseek() function is removed in addition to 2. */
|
||||
|
||||
|
||||
#define FF_USE_STRFUNC 0
|
||||
/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf().
|
||||
/
|
||||
/ 0: Disable string functions.
|
||||
/ 1: Enable without LF-CRLF conversion.
|
||||
/ 2: Enable with LF-CRLF conversion. */
|
||||
|
||||
|
||||
#define FF_USE_FIND 0
|
||||
/* This option switches filtered directory read functions, f_findfirst() and
|
||||
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
|
||||
|
||||
|
||||
#define FF_USE_MKFS 1
|
||||
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define FF_USE_FASTSEEK 0
|
||||
/* This option switches fast seek function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define FF_USE_EXPAND 0
|
||||
/* This option switches f_expand function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define FF_USE_CHMOD 0
|
||||
/* This option switches attribute manipulation functions, f_chmod() and f_utime().
|
||||
/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */
|
||||
|
||||
|
||||
#define FF_USE_LABEL 0
|
||||
/* This option switches volume label functions, f_getlabel() and f_setlabel().
|
||||
/ (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define FF_USE_FORWARD 0
|
||||
/* This option switches f_forward() function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Locale and Namespace Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define FF_CODE_PAGE 932
|
||||
/* This option specifies the OEM code page to be used on the target system.
|
||||
/ Incorrect code page setting can cause a file open failure.
|
||||
/
|
||||
/ 437 - U.S.
|
||||
/ 720 - Arabic
|
||||
/ 737 - Greek
|
||||
/ 771 - KBL
|
||||
/ 775 - Baltic
|
||||
/ 850 - Latin 1
|
||||
/ 852 - Latin 2
|
||||
/ 855 - Cyrillic
|
||||
/ 857 - Turkish
|
||||
/ 860 - Portuguese
|
||||
/ 861 - Icelandic
|
||||
/ 862 - Hebrew
|
||||
/ 863 - Canadian French
|
||||
/ 864 - Arabic
|
||||
/ 865 - Nordic
|
||||
/ 866 - Russian
|
||||
/ 869 - Greek 2
|
||||
/ 932 - Japanese (DBCS)
|
||||
/ 936 - Simplified Chinese (DBCS)
|
||||
/ 949 - Korean (DBCS)
|
||||
/ 950 - Traditional Chinese (DBCS)
|
||||
/ 0 - Include all code pages above and configured by f_setcp()
|
||||
*/
|
||||
|
||||
|
||||
#define FF_USE_LFN 2
|
||||
#define FF_MAX_LFN 255
|
||||
/* The FF_USE_LFN switches the support for LFN (long file name).
|
||||
/
|
||||
/ 0: Disable LFN. FF_MAX_LFN has no effect.
|
||||
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
|
||||
/ 2: Enable LFN with dynamic working buffer on the STACK.
|
||||
/ 3: Enable LFN with dynamic working buffer on the HEAP.
|
||||
/
|
||||
/ To enable the LFN, ffunicode.c needs to be added to the project. The LFN function
|
||||
/ requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and
|
||||
/ additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled.
|
||||
/ The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can
|
||||
/ be in range of 12 to 255. It is recommended to be set 255 to fully support LFN
|
||||
/ specification.
|
||||
/ When use stack for the working buffer, take care on stack overflow. When use heap
|
||||
/ memory for the working buffer, memory management functions, ff_memalloc() and
|
||||
/ ff_memfree() in ffsystem.c, need to be added to the project. */
|
||||
|
||||
|
||||
#define FF_LFN_UNICODE 0
|
||||
/* This option switches the character encoding on the API when LFN is enabled.
|
||||
/
|
||||
/ 0: ANSI/OEM in current CP (TCHAR = char)
|
||||
/ 1: Unicode in UTF-16 (TCHAR = WCHAR)
|
||||
/ 2: Unicode in UTF-8 (TCHAR = char)
|
||||
/
|
||||
/ Also behavior of string I/O functions will be affected by this option.
|
||||
/ When LFN is not enabled, this option has no effect. */
|
||||
|
||||
|
||||
#define FF_LFN_BUF 255
|
||||
#define FF_SFN_BUF 12
|
||||
/* This set of options defines size of file name members in the FILINFO structure
|
||||
/ which is used to read out directory items. These values should be suffcient for
|
||||
/ the file names to read. The maximum possible length of the read file name depends
|
||||
/ on character encoding. When LFN is not enabled, these options have no effect. */
|
||||
|
||||
|
||||
#define FF_STRF_ENCODE 3
|
||||
/* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(),
|
||||
/ f_putc(), f_puts and f_printf() convert the character encoding in it.
|
||||
/ This option selects assumption of character encoding ON THE FILE to be
|
||||
/ read/written via those functions.
|
||||
/
|
||||
/ 0: ANSI/OEM in current CP
|
||||
/ 1: Unicode in UTF-16LE
|
||||
/ 2: Unicode in UTF-16BE
|
||||
/ 3: Unicode in UTF-8
|
||||
*/
|
||||
|
||||
|
||||
#define FF_FS_RPATH 0
|
||||
/* This option configures support for relative path.
|
||||
/
|
||||
/ 0: Disable relative path and remove related functions.
|
||||
/ 1: Enable relative path. f_chdir() and f_chdrive() are available.
|
||||
/ 2: f_getcwd() function is available in addition to 1.
|
||||
*/
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Drive/Volume Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define FF_VOLUMES 10
|
||||
/* Number of volumes (logical drives) to be used. (1-10) */
|
||||
|
||||
|
||||
#define FF_STR_VOLUME_ID 0
|
||||
#define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
|
||||
/* FF_STR_VOLUME_ID switches string support for volume ID.
|
||||
/ When FF_STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
|
||||
/ number in the path name. FF_VOLUME_STRS defines the drive ID strings for each
|
||||
/ logical drives. Number of items must be equal to FF_VOLUMES. Valid characters for
|
||||
/ the drive ID strings are: A-Z and 0-9. */
|
||||
|
||||
|
||||
#define FF_MULTI_PARTITION 0
|
||||
/* This option switches support for multiple volumes on the physical drive.
|
||||
/ By default (0), each logical drive number is bound to the same physical drive
|
||||
/ number and only an FAT volume found on the physical drive will be mounted.
|
||||
/ When this function is enabled (1), each logical drive number can be bound to
|
||||
/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
|
||||
/ funciton will be available. */
|
||||
|
||||
|
||||
#define FF_MIN_SS 512
|
||||
#define FF_MAX_SS 512
|
||||
/* This set of options configures the range of sector size to be supported. (512,
|
||||
/ 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and
|
||||
/ harddisk. But a larger value may be required for on-board flash memory and some
|
||||
/ type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured
|
||||
/ for variable sector size mode and disk_ioctl() function needs to implement
|
||||
/ GET_SECTOR_SIZE command. */
|
||||
|
||||
|
||||
#define FF_USE_TRIM 0
|
||||
/* This option switches support for ATA-TRIM. (0:Disable or 1:Enable)
|
||||
/ To enable Trim function, also CTRL_TRIM command should be implemented to the
|
||||
/ disk_ioctl() function. */
|
||||
|
||||
|
||||
#define FF_FS_NOFSINFO 0
|
||||
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
|
||||
/ option, and f_getfree() function at first time after volume mount will force
|
||||
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
|
||||
/
|
||||
/ bit0=0: Use free cluster count in the FSINFO if available.
|
||||
/ bit0=1: Do not trust free cluster count in the FSINFO.
|
||||
/ bit1=0: Use last allocated cluster number in the FSINFO if available.
|
||||
/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ System Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define FF_FS_TINY 0
|
||||
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
|
||||
/ At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes.
|
||||
/ Instead of private sector buffer eliminated from the file object, common sector
|
||||
/ buffer in the filesystem object (FATFS) is used for the file data transfer. */
|
||||
|
||||
|
||||
#define FF_FS_EXFAT 0
|
||||
/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
|
||||
/ When enable exFAT, also LFN needs to be enabled.
|
||||
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
|
||||
|
||||
|
||||
#define FF_FS_NORTC 1
|
||||
#define FF_NORTC_MON 1
|
||||
#define FF_NORTC_MDAY 1
|
||||
#define FF_NORTC_YEAR 2017
|
||||
/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have
|
||||
/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable
|
||||
/ the timestamp function. All objects modified by FatFs will have a fixed timestamp
|
||||
/ defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time.
|
||||
/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be
|
||||
/ added to the project to read current time form real-time clock. FF_NORTC_MON,
|
||||
/ FF_NORTC_MDAY and FF_NORTC_YEAR have no effect.
|
||||
/ These options have no effect at read-only configuration (FF_FS_READONLY = 1). */
|
||||
|
||||
|
||||
#define FF_FS_LOCK 0
|
||||
/* The option FF_FS_LOCK switches file lock function to control duplicated file open
|
||||
/ and illegal operation to open objects. This option must be 0 when FF_FS_READONLY
|
||||
/ is 1.
|
||||
/
|
||||
/ 0: Disable file lock function. To avoid volume corruption, application program
|
||||
/ should avoid illegal open, remove and rename to the open objects.
|
||||
/ >0: Enable file lock function. The value defines how many files/sub-directories
|
||||
/ can be opened simultaneously under file lock control. Note that the file
|
||||
/ lock control is independent of re-entrancy. */
|
||||
|
||||
|
||||
#define FF_FS_REENTRANT 0
|
||||
#define FF_FS_TIMEOUT 1000
|
||||
#define FF_SYNC_t HANDLE
|
||||
/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
|
||||
/ module itself. Note that regardless of this option, file access to different
|
||||
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
|
||||
/ and f_fdisk() function, are always not re-entrant. Only file/directory access
|
||||
/ to the same volume is under control of this function.
|
||||
/
|
||||
/ 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect.
|
||||
/ 1: Enable re-entrancy. Also user provided synchronization handlers,
|
||||
/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
|
||||
/ function, must be added to the project. Samples are available in
|
||||
/ option/syscall.c.
|
||||
/
|
||||
/ The FF_FS_TIMEOUT defines timeout period in unit of time tick.
|
||||
/ The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
|
||||
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
|
||||
/ included somewhere in the scope of ff.h. */
|
||||
|
||||
/* #include <windows.h> // O/S definitions */
|
||||
|
||||
|
||||
|
||||
/*--- End of configuration options ---*/
|
15586
kernel.soso/fatfs_ffunicode.c
Normal file
15586
kernel.soso/fatfs_ffunicode.c
Normal file
File diff suppressed because it is too large
Load Diff
39
kernel.soso/fatfs_integer.h
Normal file
39
kernel.soso/fatfs_integer.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*-------------------------------------------*/
|
||||
/* Integer type definitions for FatFs module */
|
||||
/*-------------------------------------------*/
|
||||
|
||||
#ifndef FF_INTEGER
|
||||
#define FF_INTEGER
|
||||
|
||||
#undef _WIN32
|
||||
#ifdef _WIN32 /* FatFs development platform */
|
||||
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
typedef unsigned __int64 QWORD;
|
||||
|
||||
|
||||
#else /* Embedded platform */
|
||||
|
||||
/* These types MUST be 16-bit or 32-bit */
|
||||
typedef int INT;
|
||||
typedef unsigned int UINT;
|
||||
|
||||
/* This type MUST be 8-bit */
|
||||
typedef unsigned char BYTE;
|
||||
|
||||
/* These types MUST be 16-bit */
|
||||
typedef short SHORT;
|
||||
typedef unsigned short WORD;
|
||||
typedef unsigned short WCHAR;
|
||||
|
||||
/* These types MUST be 32-bit */
|
||||
typedef long LONG;
|
||||
typedef unsigned long DWORD;
|
||||
|
||||
/* This type MUST be 64-bit (Remove this for ANSI C (C89) compatibility) */
|
||||
typedef unsigned long long QWORD;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
102
kernel.soso/fifobuffer.c
Normal file
102
kernel.soso/fifobuffer.c
Normal file
|
@ -0,0 +1,102 @@
|
|||
#include "fifobuffer.h"
|
||||
#include "alloc.h"
|
||||
|
||||
FifoBuffer* FifoBuffer_create(uint32 capacity)
|
||||
{
|
||||
FifoBuffer* fifo = (FifoBuffer*)kmalloc(sizeof(FifoBuffer));
|
||||
memset((uint8*)fifo, 0, sizeof(FifoBuffer));
|
||||
fifo->data = (uint8*)kmalloc(capacity);
|
||||
memset((uint8*)fifo->data, 0, capacity);
|
||||
fifo->capacity= capacity;
|
||||
|
||||
return fifo;
|
||||
}
|
||||
|
||||
void FifoBuffer_destroy(FifoBuffer* fifoBuffer)
|
||||
{
|
||||
kfree(fifoBuffer->data);
|
||||
kfree(fifoBuffer);
|
||||
}
|
||||
|
||||
void FifoBuffer_clear(FifoBuffer* fifoBuffer)
|
||||
{
|
||||
fifoBuffer->usedBytes = 0;
|
||||
fifoBuffer->readIndex = 0;
|
||||
fifoBuffer->writeIndex = 0;
|
||||
}
|
||||
|
||||
BOOL FifoBuffer_isEmpty(FifoBuffer* fifoBuffer)
|
||||
{
|
||||
if (0 == fifoBuffer->usedBytes)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
uint32 FifoBuffer_getSize(FifoBuffer* fifoBuffer)
|
||||
{
|
||||
return fifoBuffer->usedBytes;
|
||||
}
|
||||
|
||||
uint32 FifoBuffer_getCapacity(FifoBuffer* fifoBuffer)
|
||||
{
|
||||
return fifoBuffer->capacity;
|
||||
}
|
||||
|
||||
uint32 FifoBuffer_getFree(FifoBuffer* fifoBuffer)
|
||||
{
|
||||
return fifoBuffer->capacity - fifoBuffer->usedBytes;
|
||||
}
|
||||
|
||||
int32 FifoBuffer_enqueue(FifoBuffer* fifoBuffer, uint8* data, uint32 size)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32 bytesAvailable = fifoBuffer->capacity - fifoBuffer->usedBytes;
|
||||
|
||||
if (size > bytesAvailable)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32 i = 0;
|
||||
while (fifoBuffer->usedBytes < fifoBuffer->capacity && i < size)
|
||||
{
|
||||
fifoBuffer->data[fifoBuffer->writeIndex] = data[i++];
|
||||
fifoBuffer->usedBytes++;
|
||||
fifoBuffer->writeIndex++;
|
||||
fifoBuffer->writeIndex %= fifoBuffer->capacity;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
int32 FifoBuffer_dequeue(FifoBuffer* fifoBuffer, uint8* data, uint32 size)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (0 == fifoBuffer->usedBytes)
|
||||
{
|
||||
//Buffer is empty
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 i = 0;
|
||||
while (fifoBuffer->usedBytes > 0 && i < size)
|
||||
{
|
||||
data[i++] = fifoBuffer->data[fifoBuffer->readIndex];
|
||||
fifoBuffer->usedBytes--;
|
||||
fifoBuffer->readIndex++;
|
||||
fifoBuffer->readIndex %= fifoBuffer->capacity;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
25
kernel.soso/fifobuffer.h
Normal file
25
kernel.soso/fifobuffer.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef FIFOBUFFER_H
|
||||
#define FIFOBUFFER_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
typedef struct FifoBuffer
|
||||
{
|
||||
uint8* data;
|
||||
uint32 writeIndex;
|
||||
uint32 readIndex;
|
||||
uint32 capacity;
|
||||
uint32 usedBytes;
|
||||
} FifoBuffer;
|
||||
|
||||
FifoBuffer* FifoBuffer_create(uint32 capacity);
|
||||
void FifoBuffer_destroy(FifoBuffer* fifoBuffer);
|
||||
void FifoBuffer_clear(FifoBuffer* fifoBuffer);
|
||||
BOOL FifoBuffer_isEmpty(FifoBuffer* fifoBuffer);
|
||||
uint32 FifoBuffer_getSize(FifoBuffer* fifoBuffer);
|
||||
uint32 FifoBuffer_getCapacity(FifoBuffer* fifoBuffer);
|
||||
uint32 FifoBuffer_getFree(FifoBuffer* fifoBuffer);
|
||||
int32 FifoBuffer_enqueue(FifoBuffer* fifoBuffer, uint8* data, uint32 size);
|
||||
int32 FifoBuffer_dequeue(FifoBuffer* fifoBuffer, uint8* data, uint32 size);
|
||||
|
||||
#endif // FIFOBUFFER_H
|
BIN
kernel.soso/font/font.o
Normal file
BIN
kernel.soso/font/font.o
Normal file
Binary file not shown.
BIN
kernel.soso/font/font.psf
Normal file
BIN
kernel.soso/font/font.psf
Normal file
Binary file not shown.
108
kernel.soso/framebuffer.c
Normal file
108
kernel.soso/framebuffer.c
Normal file
|
@ -0,0 +1,108 @@
|
|||
#include "devfs.h"
|
||||
#include "device.h"
|
||||
#include "common.h"
|
||||
#include "gfx.h"
|
||||
#include "framebuffer.h"
|
||||
#include "vmm.h"
|
||||
#include "process.h"
|
||||
|
||||
static BOOL fb_open(File *file, uint32 flags);
|
||||
static int32 fb_read(File *file, uint32 size, uint8 *buffer);
|
||||
static int32 fb_write(File *file, uint32 size, uint8 *buffer);
|
||||
static int32 fb_ioctl(File *node, int32 request, void * argp);
|
||||
static void* fb_mmap(File* file, uint32 size, uint32 offset, uint32 flags);
|
||||
static BOOL fb_munmap(File* file, void* address, uint32 size);
|
||||
|
||||
static uint8* gFrameBufferPhysical = 0;
|
||||
static uint8* gFrameBufferVirtual = 0;
|
||||
|
||||
void initializeFrameBuffer(uint8* p_address, uint8* v_address)
|
||||
{
|
||||
gFrameBufferPhysical = p_address;
|
||||
gFrameBufferVirtual = v_address;
|
||||
|
||||
Device device;
|
||||
memset((uint8*)&device, 0, sizeof(Device));
|
||||
strcpy(device.name, "fb0");
|
||||
device.deviceType = FT_CharacterDevice;
|
||||
device.open = fb_open;
|
||||
device.read = fb_read;
|
||||
device.write = fb_write;
|
||||
device.ioctl = fb_ioctl;
|
||||
device.mmap = fb_mmap;
|
||||
device.munmap = fb_munmap;
|
||||
|
||||
registerDevice(&device);
|
||||
}
|
||||
|
||||
static BOOL fb_open(File *file, uint32 flags)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int32 fb_read(File *file, uint32 size, uint8 *buffer)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int32 fb_write(File *file, uint32 size, uint8 *buffer)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 requestedSize = size;
|
||||
|
||||
int32 length = Gfx_GetWidth() * Gfx_GetHeight() * 4;
|
||||
|
||||
int32 availableSize = length - file->offset;
|
||||
|
||||
if (availableSize <= 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32 targetSize = MIN(requestedSize, availableSize);
|
||||
|
||||
memcpy(gFrameBufferVirtual + file->offset, buffer, targetSize);
|
||||
|
||||
file->offset += targetSize;
|
||||
|
||||
return targetSize;
|
||||
}
|
||||
|
||||
static int32 fb_ioctl(File *node, int32 request, void * argp)
|
||||
{
|
||||
int32 result = -1;
|
||||
|
||||
switch (request)
|
||||
{
|
||||
case FB_GET_WIDTH:
|
||||
result = Gfx_GetWidth();
|
||||
break;
|
||||
case FB_GET_HEIGHT:
|
||||
result = Gfx_GetHeight();
|
||||
break;
|
||||
case FB_GET_BITSPERPIXEL:
|
||||
result = 32;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void* fb_mmap(File* file, uint32 size, uint32 offset, uint32 flags)
|
||||
{
|
||||
return mapMemory(file->thread->owner, size, (uint32)(gFrameBufferPhysical + offset), NULL);
|
||||
}
|
||||
|
||||
static BOOL fb_munmap(File* file, void* address, uint32 size)
|
||||
{
|
||||
return unmapMemory(file->thread->owner, size, (uint32)address);
|
||||
}
|
15
kernel.soso/framebuffer.h
Normal file
15
kernel.soso/framebuffer.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef FRAMEBUFFER_H
|
||||
#define FRAMEBUFFER_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
enum EnFrameBuferIoctl
|
||||
{
|
||||
FB_GET_WIDTH,
|
||||
FB_GET_HEIGHT,
|
||||
FB_GET_BITSPERPIXEL
|
||||
};
|
||||
|
||||
void initializeFrameBuffer(uint8* p_address, uint8* v_address);
|
||||
|
||||
#endif // FRAMEBUFFER_H
|
634
kernel.soso/fs.c
Normal file
634
kernel.soso/fs.c
Normal file
|
@ -0,0 +1,634 @@
|
|||
#include "fs.h"
|
||||
#include "alloc.h"
|
||||
#include "screen.h"
|
||||
#include "rootfs.h"
|
||||
|
||||
FileSystemNode *gFileSystemRoot = NULL; // The root of the filesystem.
|
||||
|
||||
#define FILESYSTEM_CAPACITY 10
|
||||
|
||||
static FileSystem gRegisteredFileSystems[FILESYSTEM_CAPACITY];
|
||||
static int gNextFileSystemIndex = 0;
|
||||
|
||||
void initializeVFS()
|
||||
{
|
||||
memset((uint8*)gRegisteredFileSystems, 0, sizeof(gRegisteredFileSystems));
|
||||
|
||||
gFileSystemRoot = initializeRootFS();
|
||||
|
||||
mkdir_fs(gFileSystemRoot, "dev", 0);
|
||||
mkdir_fs(gFileSystemRoot, "initrd", 0);
|
||||
}
|
||||
|
||||
FileSystemNode* getFileSystemRootNode()
|
||||
{
|
||||
return gFileSystemRoot;
|
||||
}
|
||||
|
||||
void copyFileDescriptors(Process* fromProcess, Process* toProcess)
|
||||
{
|
||||
for (int i = 0; i < MAX_OPENED_FILES; ++i)
|
||||
{
|
||||
File* original = fromProcess->fd[i];
|
||||
|
||||
if (original)
|
||||
{
|
||||
File* file = kmalloc(sizeof(File));
|
||||
memcpy((uint8*)file, (uint8*)original, sizeof(File));
|
||||
file->process = toProcess;
|
||||
file->thread = NULL;
|
||||
|
||||
toProcess->fd[i] = file;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int getFileSystemNodePath(FileSystemNode *node, char* buffer, uint32 bufferSize)
|
||||
{
|
||||
if (node == gFileSystemRoot)
|
||||
{
|
||||
if (bufferSize > 1)
|
||||
{
|
||||
buffer[0] = '/';
|
||||
buffer[1] = '\0';
|
||||
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
char targetPath[128];
|
||||
|
||||
FileSystemNode *n = node;
|
||||
int charIndex = 127;
|
||||
targetPath[charIndex] = '\0';
|
||||
while (NULL != n)
|
||||
{
|
||||
int length = strlen(n->name);
|
||||
charIndex -= length;
|
||||
|
||||
if (charIndex < 2)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NULL != n->parent)
|
||||
{
|
||||
strcpyNonNull(targetPath + charIndex, n->name);
|
||||
charIndex -= 1;
|
||||
targetPath[charIndex] = '/';
|
||||
}
|
||||
|
||||
n = n->parent;
|
||||
}
|
||||
|
||||
int len = 127 - charIndex;
|
||||
|
||||
//Screen_PrintF("getFileSystemNodePath: len:[%s] %d\n", targetPath + charIndex, len);
|
||||
|
||||
if (bufferSize < len)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(buffer, targetPath + charIndex);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
BOOL resolvePath(const char* path, char* buffer, int bufferSize)
|
||||
{
|
||||
int lengthPath = strlen(path);
|
||||
|
||||
if (path[0] != '/')
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (bufferSize < 2)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
buffer[0] = '/';
|
||||
buffer[1] = '\0';
|
||||
int index = 0;
|
||||
int indexBuffer = 1;
|
||||
|
||||
while (index < lengthPath - 1)
|
||||
{
|
||||
while (path[++index] == '/');//eliminate successive
|
||||
|
||||
const char* current = path + index;
|
||||
int nextIndex = strFirstIndexOf(path + index, '/');
|
||||
|
||||
int lengthToken = 0;
|
||||
|
||||
if (nextIndex >= 0)
|
||||
{
|
||||
const char* next = path + index + nextIndex;
|
||||
|
||||
lengthToken = next - (path + index);
|
||||
}
|
||||
else
|
||||
{
|
||||
lengthToken = strlen(current);
|
||||
}
|
||||
|
||||
if (lengthToken > 0)
|
||||
{
|
||||
index += lengthToken;
|
||||
if (strncmp(current, "..", 2) == 0)
|
||||
{
|
||||
--indexBuffer;
|
||||
while (indexBuffer > 0)
|
||||
{
|
||||
--indexBuffer;
|
||||
|
||||
if (buffer[indexBuffer] == '/')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
buffer[indexBuffer] = '\0';
|
||||
}
|
||||
|
||||
++indexBuffer;
|
||||
continue;
|
||||
}
|
||||
else if (strncmp(current, ".", 1) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (indexBuffer + lengthToken + 2 > bufferSize)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
strncpy(buffer + indexBuffer, current, lengthToken);
|
||||
indexBuffer += lengthToken;
|
||||
|
||||
if (current[lengthToken] == '/')
|
||||
{
|
||||
buffer[indexBuffer++] = '/';
|
||||
}
|
||||
buffer[indexBuffer] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (indexBuffer > 2)
|
||||
{
|
||||
if (buffer[indexBuffer - 1] == '/')
|
||||
{
|
||||
buffer[indexBuffer - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
uint32 read_fs(File *file, uint32 size, uint8 *buffer)
|
||||
{
|
||||
if (file->node->read != 0)
|
||||
{
|
||||
return file->node->read(file, size, buffer);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32 write_fs(File *file, uint32 size, uint8 *buffer)
|
||||
{
|
||||
if (file->node->write != 0)
|
||||
{
|
||||
return file->node->write(file, size, buffer);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
File *open_fs(FileSystemNode *node, uint32 flags)
|
||||
{
|
||||
return open_fs_forProcess(getCurrentThread(), node, flags);
|
||||
}
|
||||
|
||||
File *open_fs_forProcess(Thread* thread, FileSystemNode *node, uint32 flags)
|
||||
{
|
||||
Process* process = thread->owner;
|
||||
|
||||
if ( (node->nodeType & FT_MountPoint) == FT_MountPoint && node->mountPoint != NULL )
|
||||
{
|
||||
node = node->mountPoint;
|
||||
}
|
||||
|
||||
if (node->open != NULL)
|
||||
{
|
||||
File* file = kmalloc(sizeof(File));
|
||||
memset((uint8*)file, 0, sizeof(File));
|
||||
file->node = node;
|
||||
file->process = process;
|
||||
file->thread = thread;
|
||||
|
||||
BOOL success = node->open(file, flags);
|
||||
|
||||
if (success)
|
||||
{
|
||||
//Screen_PrintF("Opened:%s\n", file->node->name);
|
||||
int32 fd = addFileToProcess(file->process, file);
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
//TODO: sett errno max files opened already
|
||||
printkf("Maxfiles opened already!!\n");
|
||||
|
||||
close_fs(file);
|
||||
file = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
kfree(file);
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void close_fs(File *file)
|
||||
{
|
||||
if (file->node->close != NULL)
|
||||
{
|
||||
file->node->close(file);
|
||||
}
|
||||
|
||||
removeFileFromProcess(file->process, file);
|
||||
|
||||
kfree(file);
|
||||
}
|
||||
|
||||
int32 ioctl_fs(File *file, int32 request, void * argp)
|
||||
{
|
||||
if (file->node->ioctl != NULL)
|
||||
{
|
||||
return file->node->ioctl(file, request, argp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 lseek_fs(File *file, int32 offset, int32 whence)
|
||||
{
|
||||
if (file->node->lseek != NULL)
|
||||
{
|
||||
return file->node->lseek(file, offset, whence);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 ftruncate_fs(File* file, int32 length)
|
||||
{
|
||||
if (file->node->ftruncate != NULL)
|
||||
{
|
||||
return file->node->ftruncate(file, length);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32 stat_fs(FileSystemNode *node, struct stat *buf)
|
||||
{
|
||||
#define __S_IFDIR 0040000 /* Directory. */
|
||||
#define __S_IFCHR 0020000 /* Character device. */
|
||||
#define __S_IFBLK 0060000 /* Block device. */
|
||||
#define __S_IFREG 0100000 /* Regular file. */
|
||||
#define __S_IFIFO 0010000 /* FIFO. */
|
||||
#define __S_IFLNK 0120000 /* Symbolic link. */
|
||||
#define __S_IFSOCK 0140000 /* Socket. */
|
||||
|
||||
if (node->stat != NULL)
|
||||
{
|
||||
int32 val = node->stat(node, buf);
|
||||
|
||||
if (val == 1)
|
||||
{
|
||||
//return value of 1 from driver means we should fill buf here.
|
||||
|
||||
if ((node->nodeType & FT_Directory) == FT_Directory)
|
||||
{
|
||||
buf->st_mode = __S_IFDIR;
|
||||
}
|
||||
else if ((node->nodeType & FT_CharacterDevice) == FT_CharacterDevice)
|
||||
{
|
||||
buf->st_mode = __S_IFCHR;
|
||||
}
|
||||
else if ((node->nodeType & FT_BlockDevice) == FT_BlockDevice)
|
||||
{
|
||||
buf->st_mode = __S_IFBLK;
|
||||
}
|
||||
else if ((node->nodeType & FT_Pipe) == FT_Pipe)
|
||||
{
|
||||
buf->st_mode = __S_IFIFO;
|
||||
}
|
||||
else if ((node->nodeType & FT_SymbolicLink) == FT_SymbolicLink)
|
||||
{
|
||||
buf->st_mode = __S_IFLNK;
|
||||
}
|
||||
else if ((node->nodeType & FT_File) == FT_File)
|
||||
{
|
||||
buf->st_mode = __S_IFREG;
|
||||
}
|
||||
|
||||
buf->st_size = node->length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
FileSystemDirent *readdir_fs(FileSystemNode *node, uint32 index)
|
||||
{
|
||||
//Screen_PrintF("readdir_fs: node->name:%s index:%d\n", node->name, index);
|
||||
|
||||
if ( (node->nodeType & FT_MountPoint) == FT_MountPoint && node->mountPoint != NULL )
|
||||
{
|
||||
if (NULL == node->mountPoint->readdir)
|
||||
{
|
||||
WARNING("mounted fs does not have readdir!\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
return node->mountPoint->readdir(node->mountPoint, index);
|
||||
}
|
||||
}
|
||||
else if ( (node->nodeType & FT_Directory) == FT_Directory && node->readdir != NULL )
|
||||
{
|
||||
return node->readdir(node, index);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FileSystemNode *finddir_fs(FileSystemNode *node, char *name)
|
||||
{
|
||||
//Screen_PrintF("finddir_fs: name:%s\n", name);
|
||||
|
||||
if ( (node->nodeType & FT_MountPoint) == FT_MountPoint && node->mountPoint != NULL )
|
||||
{
|
||||
if (NULL == node->mountPoint->finddir)
|
||||
{
|
||||
WARNING("mounted fs does not have finddir!\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
return node->mountPoint->finddir(node->mountPoint, name);
|
||||
}
|
||||
}
|
||||
else if ( (node->nodeType & FT_Directory) == FT_Directory && node->finddir != NULL )
|
||||
{
|
||||
return node->finddir(node, name);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BOOL mkdir_fs(FileSystemNode *node, const char *name, uint32 flags)
|
||||
{
|
||||
if ( (node->nodeType & FT_MountPoint) == FT_MountPoint && node->mountPoint != NULL )
|
||||
{
|
||||
if (node->mountPoint->mkdir)
|
||||
{
|
||||
return node->mountPoint->mkdir(node->mountPoint, name, flags);
|
||||
}
|
||||
}
|
||||
else if ( (node->nodeType & FT_Directory) == FT_Directory && node->mkdir != NULL )
|
||||
{
|
||||
return node->mkdir(node, name, flags);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void* mmap_fs(File* file, uint32 size, uint32 offset, uint32 flags)
|
||||
{
|
||||
if (file->node->mmap)
|
||||
{
|
||||
return file->node->mmap(file, size, offset, flags);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BOOL munmap_fs(File* file, void* address, uint32 size)
|
||||
{
|
||||
if (file->node->munmap)
|
||||
{
|
||||
return file->node->munmap(file, address, size);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
FileSystemNode *getFileSystemNode(const char *path)
|
||||
{
|
||||
//Screen_PrintF("getFileSystemNode:%s *0\n", path);
|
||||
|
||||
if (path[0] != '/')
|
||||
{
|
||||
//We require absolute path!
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
char realPath[256];
|
||||
|
||||
BOOL resolved = resolvePath(path, realPath, 256);
|
||||
|
||||
if (FALSE == resolved)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* inputPath = realPath;
|
||||
int pathLength = strlen(inputPath);
|
||||
|
||||
if (pathLength < 1)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Screen_PrintF("getFileSystemNode:%s *1\n", path);
|
||||
|
||||
FileSystemNode* root = getFileSystemRootNode();
|
||||
|
||||
if (pathLength == 1)
|
||||
{
|
||||
return root;
|
||||
}
|
||||
|
||||
int nextIndex = 0;
|
||||
|
||||
FileSystemNode* node = root;
|
||||
|
||||
//Screen_PrintF("getFileSystemNode:%s *2\n", path);
|
||||
|
||||
char buffer[64];
|
||||
|
||||
do
|
||||
{
|
||||
do_start:
|
||||
inputPath = inputPath + nextIndex + 1;
|
||||
nextIndex = strFirstIndexOf(inputPath, '/');
|
||||
|
||||
if (nextIndex == 0)
|
||||
{
|
||||
//detected successive slash
|
||||
goto do_start;
|
||||
}
|
||||
|
||||
if (nextIndex > 0)
|
||||
{
|
||||
int tokenSize = nextIndex;
|
||||
|
||||
strncpy(buffer, inputPath, tokenSize);
|
||||
buffer[tokenSize] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
//Last part
|
||||
strcpy(buffer, inputPath);
|
||||
}
|
||||
|
||||
//Screen_PrintF("getFileSystemNode:%s *3\n", path);
|
||||
|
||||
node = finddir_fs(node, buffer);
|
||||
|
||||
//Screen_PrintF("getFileSystemNode:%s *4\n", path);
|
||||
|
||||
if (NULL == node)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} while (nextIndex > 0);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
FileSystemNode* getFileSystemNodeAbsoluteOrRelative(const char* path, Process* process)
|
||||
{
|
||||
FileSystemNode* node = NULL;
|
||||
|
||||
if (process)
|
||||
{
|
||||
if ('\0' == path[0])
|
||||
{
|
||||
//empty
|
||||
}
|
||||
else if ('/' == path[0])
|
||||
{
|
||||
//absolute
|
||||
|
||||
node = getFileSystemNode(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
//relative
|
||||
|
||||
if (process->workingDirectory)
|
||||
{
|
||||
char buffer[256];
|
||||
|
||||
if (getFileSystemNodePath(process->workingDirectory, buffer, 256) >= 0)
|
||||
{
|
||||
strcat(buffer, "/");
|
||||
strcat(buffer, path);
|
||||
|
||||
//Screen_PrintF("getFileSystemNodeAbsoluteOrRelative:[%s]\n", buffer);
|
||||
|
||||
node = getFileSystemNode(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
BOOL registerFileSystem(FileSystem* fs)
|
||||
{
|
||||
if (strlen(fs->name) <= 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (int i = 0; i < gNextFileSystemIndex; ++i)
|
||||
{
|
||||
if (strcmp(gRegisteredFileSystems[i].name, fs->name) == 0)
|
||||
{
|
||||
//name is in use
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
gRegisteredFileSystems[gNextFileSystemIndex++] = *fs;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL mountFileSystem(const char *source, const char *target, const char *fsType, uint32 flags, void *data)
|
||||
{
|
||||
FileSystem* fs = NULL;
|
||||
|
||||
for (int i = 0; i < gNextFileSystemIndex; ++i)
|
||||
{
|
||||
if (strcmp(gRegisteredFileSystems[i].name, fsType) == 0)
|
||||
{
|
||||
fs = &gRegisteredFileSystems[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL == fs)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return fs->mount(source, target, flags, data);
|
||||
}
|
||||
|
||||
BOOL checkMountFileSystem(const char *source, const char *target, const char *fsType, uint32 flags, void *data)
|
||||
{
|
||||
FileSystem* fs = NULL;
|
||||
|
||||
for (int i = 0; i < gNextFileSystemIndex; ++i)
|
||||
{
|
||||
if (strcmp(gRegisteredFileSystems[i].name, fsType) == 0)
|
||||
{
|
||||
fs = &gRegisteredFileSystems[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL == fs)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return fs->checkMount(source, target, flags, data);
|
||||
}
|
155
kernel.soso/fs.h
Normal file
155
kernel.soso/fs.h
Normal file
|
@ -0,0 +1,155 @@
|
|||
#ifndef FS_H
|
||||
#define FS_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
typedef enum FileType
|
||||
{
|
||||
FT_File = 1,
|
||||
FT_CharacterDevice = 2,
|
||||
FT_BlockDevice = 3,
|
||||
FT_Pipe = 4,
|
||||
FT_SymbolicLink = 5,
|
||||
FT_Directory = 128,
|
||||
FT_MountPoint = 256
|
||||
} FileType;
|
||||
|
||||
typedef enum IoctlCommand
|
||||
{
|
||||
IC_GetSectorSizeInBytes,
|
||||
IC_GetSectorCount,
|
||||
} IoctlCommand;
|
||||
|
||||
typedef struct FileSystem FileSystem;
|
||||
typedef struct FileSystemNode FileSystemNode;
|
||||
typedef struct FileSystemDirent FileSystemDirent;
|
||||
typedef struct Process Process;
|
||||
typedef struct Thread Thread;
|
||||
typedef struct File File;
|
||||
|
||||
struct stat;
|
||||
|
||||
typedef int32 (*ReadWriteFunction)(File* file, uint32 size, uint8* buffer);
|
||||
typedef int32 (*ReadWriteBlockFunction)(FileSystemNode* node, uint32 blockNumber, uint32 count, uint8* buffer);
|
||||
typedef BOOL (*OpenFunction)(File* file, uint32 flags);
|
||||
typedef void (*CloseFunction)(File* file);
|
||||
typedef int32 (*IoctlFunction)(File *file, int32 request, void * argp);
|
||||
typedef int32 (*LseekFunction)(File *file, int32 offset, int32 whence);
|
||||
typedef int32 (*FtruncateFunction)(File *file, int32 length);
|
||||
typedef int32 (*StatFunction)(FileSystemNode *node, struct stat *buf);
|
||||
typedef FileSystemDirent * (*ReadDirFunction)(FileSystemNode*,uint32);
|
||||
typedef FileSystemNode * (*FindDirFunction)(FileSystemNode*,char *name);
|
||||
typedef BOOL (*MkDirFunction)(FileSystemNode* node, const char *name, uint32 flags);
|
||||
typedef void* (*MmapFunction)(File* file, uint32 size, uint32 offset, uint32 flags);
|
||||
typedef BOOL (*MunmapFunction)(File* file, void* address, uint32 size);
|
||||
|
||||
typedef BOOL (*MountFunction)(const char* sourcePath, const char* targetPath, uint32 flags, void *data);
|
||||
|
||||
typedef struct FileSystem
|
||||
{
|
||||
char name[32];
|
||||
MountFunction checkMount;
|
||||
MountFunction mount;
|
||||
} FileSystem;
|
||||
|
||||
typedef struct FileSystemNode
|
||||
{
|
||||
char name[128];
|
||||
uint32 mask;
|
||||
uint32 userId;
|
||||
uint32 groupId;
|
||||
uint32 nodeType;
|
||||
uint32 inode;
|
||||
uint32 length;
|
||||
ReadWriteBlockFunction readBlock;
|
||||
ReadWriteBlockFunction writeBlock;
|
||||
ReadWriteFunction read;
|
||||
ReadWriteFunction write;
|
||||
OpenFunction open;
|
||||
CloseFunction close;
|
||||
IoctlFunction ioctl;
|
||||
LseekFunction lseek;
|
||||
FtruncateFunction ftruncate;
|
||||
StatFunction stat;
|
||||
ReadDirFunction readdir;
|
||||
FindDirFunction finddir;
|
||||
MkDirFunction mkdir;
|
||||
MmapFunction mmap;
|
||||
MunmapFunction munmap;
|
||||
FileSystemNode *firstChild;
|
||||
FileSystemNode *nextSibling;
|
||||
FileSystemNode *parent;
|
||||
FileSystemNode *mountPoint;//only used in mounts
|
||||
FileSystemNode *mountSource;//only used in mounts
|
||||
void* privateNodeData;
|
||||
} FileSystemNode;
|
||||
|
||||
typedef struct FileSystemDirent
|
||||
{
|
||||
char name[128];
|
||||
FileType fileType;
|
||||
uint32 inode;
|
||||
} FileSystemDirent;
|
||||
|
||||
//Per open
|
||||
typedef struct File
|
||||
{
|
||||
FileSystemNode* node;
|
||||
Process* process;
|
||||
Thread* thread;
|
||||
int32 fd;
|
||||
int32 offset;
|
||||
void* privateData;
|
||||
} File;
|
||||
|
||||
struct stat
|
||||
{
|
||||
uint16/*dev_t */ st_dev; /* ID of device containing file */
|
||||
uint16/*ino_t */ st_ino; /* inode number */
|
||||
uint32/*mode_t */ st_mode; /* protection */
|
||||
uint16/*nlink_t */ st_nlink; /* number of hard links */
|
||||
uint16/*uid_t */ st_uid; /* user ID of owner */
|
||||
uint16/*gid_t */ st_gid; /* group ID of owner */
|
||||
uint16/*dev_t */ st_rdev; /* device ID (if special file) */
|
||||
uint32/*off_t */ st_size; /* total size, in bytes */
|
||||
|
||||
uint32/*time_t */ st_atime;
|
||||
uint32/*long */ st_spare1;
|
||||
uint32/*time_t */ st_mtime;
|
||||
uint32/*long */ st_spare2;
|
||||
uint32/*time_t */ st_ctime;
|
||||
uint32/*long */ st_spare3;
|
||||
uint32/*blksize_t */ st_blksize;
|
||||
uint32/*blkcnt_t */ st_blocks;
|
||||
uint32/*long */ st_spare4[2];
|
||||
};
|
||||
|
||||
|
||||
uint32 read_fs(File* file, uint32 size, uint8* buffer);
|
||||
uint32 write_fs(File* file, uint32 size, uint8* buffer);
|
||||
File* open_fs(FileSystemNode* node, uint32 flags);
|
||||
File* open_fs_forProcess(Thread* thread, FileSystemNode* node, uint32 flags);
|
||||
void close_fs(File* file);
|
||||
int32 ioctl_fs(File* file, int32 request, void* argp);
|
||||
int32 lseek_fs(File* file, int32 offset, int32 whence);
|
||||
int32 ftruncate_fs(File* file, int32 length);
|
||||
int32 stat_fs(FileSystemNode *node, struct stat *buf);
|
||||
FileSystemDirent* readdir_fs(FileSystemNode* node, uint32 index);
|
||||
FileSystemNode* finddir_fs(FileSystemNode* node, char* name);
|
||||
BOOL mkdir_fs(FileSystemNode *node, const char* name, uint32 flags);
|
||||
void* mmap_fs(File* file, uint32 size, uint32 offset, uint32 flags);
|
||||
BOOL munmap_fs(File* file, void* address, uint32 size);
|
||||
int getFileSystemNodePath(FileSystemNode* node, char* buffer, uint32 bufferSize);
|
||||
BOOL resolvePath(const char* path, char* buffer, int bufferSize);
|
||||
|
||||
void initializeVFS();
|
||||
FileSystemNode* getFileSystemRootNode();
|
||||
FileSystemNode* getFileSystemNode(const char* path);
|
||||
FileSystemNode* getFileSystemNodeAbsoluteOrRelative(const char* path, Process* process);
|
||||
void copyFileDescriptors(Process* fromProcess, Process* toProcess);
|
||||
|
||||
BOOL registerFileSystem(FileSystem* fs);
|
||||
BOOL mountFileSystem(const char *source, const char *target, const char *fsType, uint32 flags, void *data);
|
||||
BOOL checkMountFileSystem(const char *source, const char *target, const char *fsType, uint32 flags, void *data);
|
||||
|
||||
#endif
|
30
kernel.soso/gdt.asm
Normal file
30
kernel.soso/gdt.asm
Normal file
|
@ -0,0 +1,30 @@
|
|||
[GLOBAL flushGdt]
|
||||
|
||||
flushGdt:
|
||||
mov eax, [esp+4] ;[esp+4] is the parametered passed
|
||||
lgdt [eax]
|
||||
|
||||
mov ax, 0x10 ;0x10 is the offset to our data segment
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
mov ss, ax
|
||||
jmp 0x08:.flush ;0x08 is the offset to our code segment
|
||||
.flush:
|
||||
ret
|
||||
|
||||
[GLOBAL flushIdt]
|
||||
|
||||
flushIdt:
|
||||
mov eax, [esp+4] ;[esp+4] is the parametered passed
|
||||
lidt [eax]
|
||||
ret
|
||||
|
||||
[GLOBAL flushTss]
|
||||
|
||||
flushTss:
|
||||
mov ax, 0x2B ;index of the TSS structure is 0x28 (5*8) and OR'ing two bits in order to set RPL 3 and we get 0x2B
|
||||
|
||||
ltr ax
|
||||
ret
|
178
kernel.soso/gfx.c
Normal file
178
kernel.soso/gfx.c
Normal file
|
@ -0,0 +1,178 @@
|
|||
#include "gfx.h"
|
||||
#include "vmm.h"
|
||||
#include "serial.h"
|
||||
#include "framebuffer.h"
|
||||
#include "debugprint.h"
|
||||
|
||||
static uint32 gWidth = 0;
|
||||
static uint32 gHeight = 0;
|
||||
static uint32 gBytesPerPixel = 0;
|
||||
static uint32 gPitch = 0;
|
||||
static uint32* gPixels = NULL;
|
||||
|
||||
extern char _binary_font_psf_start;
|
||||
extern char _binary_font_psf_end;
|
||||
|
||||
uint16 *gUnicode = NULL;
|
||||
|
||||
static int gLineCount = 10;
|
||||
static int gColumnCount = 10;
|
||||
static uint16 gCurrentLine = 0;
|
||||
static uint16 gCurrentColumn = 0;
|
||||
|
||||
#define LINE_HEIGHT 16
|
||||
|
||||
void Gfx_Initialize(uint32* pixels, uint32 width, uint32 height, uint32 bytesPerPixel, uint32 pitch)
|
||||
{
|
||||
char* p_address = (char*)pixels;
|
||||
char* v_address = (char*)GFX_MEMORY;
|
||||
|
||||
//Usually physical and virtual are the same here but of course they don't have to
|
||||
|
||||
gPixels = (uint32*)v_address;
|
||||
gWidth = width;
|
||||
gHeight = height;
|
||||
gBytesPerPixel = bytesPerPixel;
|
||||
gPitch = pitch;
|
||||
|
||||
gLineCount = gHeight / LINE_HEIGHT;
|
||||
gColumnCount = gWidth / 8;
|
||||
|
||||
|
||||
BOOL success = addPageToPd(gKernelPageDirectory, v_address, p_address, 0);
|
||||
|
||||
if (success)
|
||||
{
|
||||
for (int y = 0; y < gHeight; ++y)
|
||||
{
|
||||
for (int x = 0; x < gWidth; ++x)
|
||||
{
|
||||
gPixels[x + y * gWidth] = 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug_PrintF("Gfx initialization failed!\n");
|
||||
}
|
||||
|
||||
initializeFrameBuffer((uint8*)p_address, (uint8*)v_address);
|
||||
}
|
||||
|
||||
#define PSF_FONT_MAGIC 0x864ab572
|
||||
|
||||
typedef struct {
|
||||
uint32 magic; /* magic bytes to identify PSF */
|
||||
uint32 version; /* zero */
|
||||
uint32 headersize; /* offset of bitmaps in file, 32 */
|
||||
uint32 flags; /* 0 if there's no unicode table */
|
||||
uint32 numglyph; /* number of glyphs */
|
||||
uint32 bytesperglyph; /* size of each glyph */
|
||||
uint32 height; /* height in pixels */
|
||||
uint32 width; /* width in pixels */
|
||||
} PSF_font;
|
||||
|
||||
//From Osdev PC Screen Font (The font used here is free to use)
|
||||
void Gfx_PutCharAt(
|
||||
/* note that this is int, not char as it's a unicode character */
|
||||
unsigned short int c,
|
||||
/* cursor position on screen, in characters not in pixels */
|
||||
int cx, int cy,
|
||||
/* foreground and background colors, say 0xFFFFFF and 0x000000 */
|
||||
uint32 fg, uint32 bg)
|
||||
{
|
||||
/* cast the address to PSF header struct */
|
||||
PSF_font *font = (PSF_font*)&_binary_font_psf_start;
|
||||
/* we need to know how many bytes encode one row */
|
||||
int bytesperline=(font->width+7)/8;
|
||||
/* unicode translation */
|
||||
if(gUnicode != NULL) {
|
||||
c = gUnicode[c];
|
||||
}
|
||||
/* get the glyph for the character. If there's no
|
||||
glyph for a given character, we'll display the first glyph. */
|
||||
unsigned char *glyph =
|
||||
(unsigned char*)&_binary_font_psf_start +
|
||||
font->headersize +
|
||||
(c>0&&c<font->numglyph?c:0)*font->bytesperglyph;
|
||||
/* calculate the upper left corner on screen where we want to display.
|
||||
we only do this once, and adjust the offset later. This is faster. */
|
||||
int offs =
|
||||
(cy * font->height * gPitch) +
|
||||
(cx * (font->width+1) * 4);
|
||||
/* finally display pixels according to the bitmap */
|
||||
int x,y, line,mask;
|
||||
for(y=0;y<font->height;y++){
|
||||
/* save the starting position of the line */
|
||||
line=offs;
|
||||
mask=1<<(font->width-1);
|
||||
/* display a row */
|
||||
for(x=0;x<font->width;x++)
|
||||
{
|
||||
if (c == 0)
|
||||
{
|
||||
*((uint32*)((uint8*)gPixels + line)) = bg;
|
||||
}
|
||||
else
|
||||
{
|
||||
*((uint32*)((uint8*)gPixels + line)) = ((int)*glyph) & (mask) ? fg : bg;
|
||||
}
|
||||
|
||||
/* adjust to the next pixel */
|
||||
mask >>= 1;
|
||||
line += 4;
|
||||
}
|
||||
/* adjust to the next line */
|
||||
glyph += bytesperline;
|
||||
offs += gPitch;
|
||||
}
|
||||
}
|
||||
|
||||
void Gfx_FlushFromTty(Tty* tty)
|
||||
{
|
||||
for (uint32 r = 0; r < tty->lineCount; ++r)
|
||||
{
|
||||
for (uint32 c = 0; c < tty->columnCount; ++c)
|
||||
{
|
||||
uint8* ttyPos = tty->buffer + (r * tty->columnCount + c) * 2;
|
||||
|
||||
uint8 chr = ttyPos[0];
|
||||
uint8 color = ttyPos[1];
|
||||
|
||||
Gfx_PutCharAt(chr, c, r, 0, 0xFFFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
//Screen_MoveCursor(tty->currentLine, tty->currentColumn);
|
||||
}
|
||||
|
||||
uint8* Gfx_GetVideoMemory()
|
||||
{
|
||||
return (uint8*)gPixels;
|
||||
}
|
||||
|
||||
uint16 Gfx_GetWidth()
|
||||
{
|
||||
return gWidth;
|
||||
}
|
||||
|
||||
uint16 Gfx_GetHeight()
|
||||
{
|
||||
return gHeight;
|
||||
}
|
||||
|
||||
uint16 Gfx_GetBytesPerPixel()
|
||||
{
|
||||
return gBytesPerPixel;
|
||||
}
|
||||
|
||||
void Gfx_Fill(uint32 color)
|
||||
{
|
||||
for (uint32 y = 0; y < gHeight; ++y)
|
||||
{
|
||||
for (uint32 x = 0; x < gWidth; ++x)
|
||||
{
|
||||
gPixels[x + y * gWidth] = color;
|
||||
}
|
||||
}
|
||||
}
|
25
kernel.soso/gfx.h
Normal file
25
kernel.soso/gfx.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef GFX_H
|
||||
#define GFX_H
|
||||
|
||||
#include "common.h"
|
||||
#include "tty.h"
|
||||
|
||||
void Gfx_Initialize(uint32* pixels, uint32 width, uint32 height, uint32 bytesPerPixel, uint32 pitch);
|
||||
|
||||
void Gfx_PutCharAt(
|
||||
/* note that this is int, not char as it's a unicode character */
|
||||
unsigned short int c,
|
||||
/* cursor position on screen, in characters not in pixels */
|
||||
int cx, int cy,
|
||||
/* foreground and background colors, say 0xFFFFFF and 0x000000 */
|
||||
uint32 fg, uint32 bg);
|
||||
|
||||
void Gfx_FlushFromTty(Tty* tty);
|
||||
|
||||
uint8* Gfx_GetVideoMemory();
|
||||
uint16 Gfx_GetWidth();
|
||||
uint16 Gfx_GetHeight();
|
||||
uint16 Gfx_GetBytesPerPixel();
|
||||
void Gfx_Fill(uint32 color);
|
||||
|
||||
#endif // GFX_H
|
18
kernel.soso/grub.cfg
Normal file
18
kernel.soso/grub.cfg
Normal file
|
@ -0,0 +1,18 @@
|
|||
insmod vbe
|
||||
insmod vga
|
||||
|
||||
menuentry "SOSO DISK" {
|
||||
set root=(hd0,1)
|
||||
multiboot /boot/kernel.bin
|
||||
module /boot/initrd.fat
|
||||
set gfxpayload=1024x768x32
|
||||
boot
|
||||
}
|
||||
|
||||
menuentry "SOSO CD" {
|
||||
set root=(cd)
|
||||
multiboot /boot/kernel.bin
|
||||
module /boot/initrd.fat
|
||||
set gfxpayload=1024x768x32
|
||||
boot
|
||||
}
|
132
kernel.soso/hashtable.c
Normal file
132
kernel.soso/hashtable.c
Normal file
|
@ -0,0 +1,132 @@
|
|||
#include "hashtable.h"
|
||||
#include "alloc.h"
|
||||
|
||||
typedef struct DataItem
|
||||
{
|
||||
uint32 data;
|
||||
uint32 key;
|
||||
uint8 used;
|
||||
} DataItem;
|
||||
|
||||
typedef struct HashTable
|
||||
{
|
||||
DataItem* items;
|
||||
uint32 capacity;
|
||||
} HashTable;
|
||||
|
||||
static uint32 hashCode(HashTable* hashTable, uint32 key)
|
||||
{
|
||||
return key % hashTable->capacity;
|
||||
}
|
||||
|
||||
HashTable* HashTable_create(uint32 capacity)
|
||||
{
|
||||
HashTable* hashTable = kmalloc(sizeof(HashTable));
|
||||
memset((uint8*)hashTable, 0, sizeof(HashTable));
|
||||
hashTable->capacity = capacity;
|
||||
hashTable->items = kmalloc(sizeof(DataItem) * capacity);
|
||||
|
||||
return hashTable;
|
||||
}
|
||||
|
||||
void HashTable_destroy(HashTable* hashTable)
|
||||
{
|
||||
kfree(hashTable->items);
|
||||
kfree(hashTable);
|
||||
}
|
||||
|
||||
DataItem* HashTable_search_internal(HashTable* hashTable, uint32 key)
|
||||
{
|
||||
//get the hash
|
||||
uint32 hashIndex = hashCode(hashTable, key);
|
||||
|
||||
uint32 counter = 0;
|
||||
while(counter < hashTable->capacity)
|
||||
{
|
||||
if(hashTable->items[hashIndex].key == key)
|
||||
{
|
||||
if(hashTable->items[hashIndex].used == TRUE)
|
||||
{
|
||||
return &(hashTable->items[hashIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
//go to next cell
|
||||
++hashIndex;
|
||||
|
||||
//wrap around the table
|
||||
hashIndex %= hashTable->capacity;
|
||||
|
||||
++counter;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BOOL HashTable_search(HashTable* hashTable, uint32 key, uint32* value)
|
||||
{
|
||||
DataItem* existing = HashTable_search_internal(hashTable, key);
|
||||
|
||||
if (existing)
|
||||
{
|
||||
*value = existing->data;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL HashTable_insert(HashTable* hashTable, uint32 key, uint32 data)
|
||||
{
|
||||
DataItem* existing = HashTable_search_internal(hashTable, key);
|
||||
|
||||
if (existing)
|
||||
{
|
||||
existing->data = data;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//get the hash
|
||||
uint32 hashIndex = hashCode(hashTable, key);
|
||||
|
||||
uint32 counter = 0;
|
||||
//move in array until an empty or deleted cell
|
||||
while(counter < hashTable->capacity)
|
||||
{
|
||||
if (hashTable->items[hashIndex].used == FALSE)
|
||||
{
|
||||
hashTable->items[hashIndex].key = key;
|
||||
hashTable->items[hashIndex].data = data;
|
||||
hashTable->items[hashIndex].used = TRUE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//go to next cell
|
||||
++hashIndex;
|
||||
|
||||
//wrap around the table
|
||||
hashIndex %= hashTable->capacity;
|
||||
|
||||
++counter;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL HashTable_remove(HashTable* hashTable, uint32 key)
|
||||
{
|
||||
DataItem* existing = HashTable_search_internal(hashTable, key);
|
||||
|
||||
if (existing)
|
||||
{
|
||||
existing->used = FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
14
kernel.soso/hashtable.h
Normal file
14
kernel.soso/hashtable.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#ifndef HASHTABLE_H
|
||||
#define HASHTABLE_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
typedef struct HashTable HashTable;
|
||||
|
||||
HashTable* HashTable_create(uint32 capacity);
|
||||
void HashTable_destroy(HashTable* hashTable);
|
||||
BOOL HashTable_search(HashTable* hashTable, uint32 key, uint32* value);
|
||||
BOOL HashTable_insert(HashTable* hashTable, uint32 key, uint32 data);
|
||||
BOOL HashTable_remove(HashTable* hashTable, uint32 key);
|
||||
|
||||
#endif // HASHTABLE_H
|
133
kernel.soso/interrupt.asm
Normal file
133
kernel.soso/interrupt.asm
Normal file
|
@ -0,0 +1,133 @@
|
|||
; NASM macro
|
||||
%macro ISR_ERROR_CODE 1
|
||||
global isr%1
|
||||
isr%1:
|
||||
push dword %1 ; push the interrupt number
|
||||
jmp handleISRCommon
|
||||
%endmacro
|
||||
|
||||
; NASM macro
|
||||
%macro ISR_NO_ERROR_CODE 1
|
||||
global isr%1
|
||||
isr%1:
|
||||
push dword 0 ; push a dummy error code just because to keep struct Registers the same as the above macro
|
||||
push dword %1 ; push the interrupt number
|
||||
jmp handleISRCommon
|
||||
%endmacro
|
||||
|
||||
|
||||
; NASM macro
|
||||
%macro IRQ 2
|
||||
global irq%1
|
||||
irq%1:
|
||||
push dword 0 ; push a dummy error code just because to keep struct Registers the same again
|
||||
push dword %2
|
||||
jmp handleIRQCommon
|
||||
%endmacro
|
||||
|
||||
ISR_NO_ERROR_CODE 0
|
||||
ISR_NO_ERROR_CODE 1
|
||||
ISR_NO_ERROR_CODE 2
|
||||
ISR_NO_ERROR_CODE 3
|
||||
ISR_NO_ERROR_CODE 4
|
||||
ISR_NO_ERROR_CODE 5
|
||||
ISR_NO_ERROR_CODE 6
|
||||
ISR_NO_ERROR_CODE 7
|
||||
ISR_ERROR_CODE 8
|
||||
ISR_NO_ERROR_CODE 9
|
||||
ISR_ERROR_CODE 10
|
||||
ISR_ERROR_CODE 11
|
||||
ISR_ERROR_CODE 12
|
||||
ISR_ERROR_CODE 13
|
||||
ISR_ERROR_CODE 14
|
||||
ISR_NO_ERROR_CODE 15
|
||||
ISR_NO_ERROR_CODE 16
|
||||
ISR_NO_ERROR_CODE 17
|
||||
ISR_NO_ERROR_CODE 18
|
||||
ISR_NO_ERROR_CODE 19
|
||||
ISR_NO_ERROR_CODE 20
|
||||
ISR_NO_ERROR_CODE 21
|
||||
ISR_NO_ERROR_CODE 22
|
||||
ISR_NO_ERROR_CODE 23
|
||||
ISR_NO_ERROR_CODE 24
|
||||
ISR_NO_ERROR_CODE 25
|
||||
ISR_NO_ERROR_CODE 26
|
||||
ISR_NO_ERROR_CODE 27
|
||||
ISR_NO_ERROR_CODE 28
|
||||
ISR_NO_ERROR_CODE 29
|
||||
ISR_NO_ERROR_CODE 30
|
||||
ISR_NO_ERROR_CODE 31
|
||||
ISR_NO_ERROR_CODE 128
|
||||
|
||||
; IRQ0 is handled by irqTimer below
|
||||
|
||||
IRQ 1, 33
|
||||
IRQ 2, 34
|
||||
IRQ 3, 35
|
||||
IRQ 4, 36
|
||||
IRQ 5, 37
|
||||
IRQ 6, 38
|
||||
IRQ 7, 39
|
||||
IRQ 8, 40
|
||||
IRQ 9, 41
|
||||
IRQ 10, 42
|
||||
IRQ 11, 43
|
||||
IRQ 12, 44
|
||||
IRQ 13, 45
|
||||
IRQ 14, 46
|
||||
IRQ 15, 47
|
||||
|
||||
%macro SAVE_REGS 0
|
||||
pushad
|
||||
push ds ;those registers are 16 bit but they are pushed as 32 bits here
|
||||
push es
|
||||
push fs
|
||||
push gs
|
||||
|
||||
push ebx
|
||||
mov bx, 0x10 ; load the kernel data segment descriptor
|
||||
mov ds, bx
|
||||
mov es, bx
|
||||
mov fs, bx
|
||||
mov gs, bx
|
||||
pop ebx
|
||||
%endmacro
|
||||
|
||||
%macro RESTORE_REGS 0
|
||||
pop gs
|
||||
pop fs
|
||||
pop es
|
||||
pop ds
|
||||
popad
|
||||
%endmacro
|
||||
|
||||
|
||||
extern handleISR
|
||||
|
||||
handleISRCommon:
|
||||
SAVE_REGS
|
||||
call handleISR
|
||||
RESTORE_REGS
|
||||
add esp, 8 ; deallocate the error code and the interrupt number
|
||||
iret ; pops CS, EIP, EFLAGS and also SS, and ESP if privilege change occurs
|
||||
|
||||
extern handleIRQ
|
||||
|
||||
|
||||
handleIRQCommon:
|
||||
SAVE_REGS
|
||||
call handleIRQ
|
||||
RESTORE_REGS
|
||||
add esp, 8 ; deallocate the error code and the interrupt number
|
||||
iret ; pops CS, EIP, EFLAGS and also SS, and ESP if privilege change occurs
|
||||
|
||||
extern handleTimerIRQ
|
||||
global irqTimer
|
||||
irqTimer: ; this does not have int no and error code in the stack, so there is no "add esp, 8"
|
||||
SAVE_REGS
|
||||
call handleTimerIRQ
|
||||
mov al,0x20
|
||||
out 0x20,al
|
||||
RESTORE_REGS
|
||||
iret
|
||||
|
51
kernel.soso/isr.c
Normal file
51
kernel.soso/isr.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
#include "common.h"
|
||||
#include "isr.h"
|
||||
#include "screen.h"
|
||||
|
||||
IsrFunction gInterruptHandlers[256];
|
||||
|
||||
extern uint32 gSystemTickCount;
|
||||
|
||||
void registerInterruptHandler(uint8 n, IsrFunction handler)
|
||||
{
|
||||
gInterruptHandlers[n] = handler;
|
||||
}
|
||||
|
||||
void handleISR(Registers regs)
|
||||
{
|
||||
//Screen_PrintF("handleISR interrupt no:%d\n", regs.int_no);
|
||||
|
||||
uint8 int_no = regs.interruptNumber & 0xFF;
|
||||
|
||||
if (gInterruptHandlers[int_no] != 0)
|
||||
{
|
||||
IsrFunction handler = gInterruptHandlers[int_no];
|
||||
handler(®s);
|
||||
}
|
||||
else
|
||||
{
|
||||
printkf("unhandled interrupt: %d\n", int_no);
|
||||
printkf("Tick: %d\n", gSystemTickCount);
|
||||
PANIC("unhandled interrupt");
|
||||
}
|
||||
}
|
||||
|
||||
void handleIRQ(Registers regs)
|
||||
{
|
||||
// end of interrupt message
|
||||
if (regs.interruptNumber >= 40)
|
||||
{
|
||||
//slave PIC
|
||||
outb(0xA0, 0x20);
|
||||
}
|
||||
|
||||
outb(0x20, 0x20);
|
||||
|
||||
//Screen_PrintF("irq: %d\n", regs.int_no);
|
||||
|
||||
if (gInterruptHandlers[regs.interruptNumber] != 0)
|
||||
{
|
||||
IsrFunction handler = gInterruptHandlers[regs.interruptNumber];
|
||||
handler(®s);
|
||||
}
|
||||
}
|
37
kernel.soso/isr.h
Normal file
37
kernel.soso/isr.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef ISR_H
|
||||
#define ISR_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define IRQ0 32
|
||||
#define IRQ1 33
|
||||
#define IRQ2 34
|
||||
#define IRQ3 35
|
||||
#define IRQ4 36
|
||||
#define IRQ5 37
|
||||
#define IRQ6 38
|
||||
#define IRQ7 39
|
||||
#define IRQ8 40
|
||||
#define IRQ9 41
|
||||
#define IRQ10 42
|
||||
#define IRQ11 43
|
||||
#define IRQ12 44
|
||||
#define IRQ13 45
|
||||
#define IRQ14 46
|
||||
#define IRQ15 47
|
||||
|
||||
typedef struct Registers
|
||||
{
|
||||
uint32 gs;
|
||||
uint32 fs;
|
||||
uint32 es;
|
||||
uint32 ds;
|
||||
uint32 edi, esi, ebp, esp, ebx, edx, ecx, eax; //pushed by pusha
|
||||
uint32 interruptNumber, errorCode; //if applicable
|
||||
uint32 eip, cs, eflags, userEsp, ss; //pushed by the CPU
|
||||
} Registers;
|
||||
|
||||
typedef void (*IsrFunction)(Registers*);
|
||||
void registerInterruptHandler(uint8 n, IsrFunction handler);
|
||||
|
||||
#endif //ISR_H
|
184
kernel.soso/keyboard.c
Normal file
184
kernel.soso/keyboard.c
Normal file
|
@ -0,0 +1,184 @@
|
|||
#include "keyboard.h"
|
||||
#include "isr.h"
|
||||
#include "common.h"
|
||||
#include "screen.h"
|
||||
#include "ttydriver.h"
|
||||
#include "fs.h"
|
||||
#include "device.h"
|
||||
#include "alloc.h"
|
||||
#include "devfs.h"
|
||||
#include "list.h"
|
||||
|
||||
static uint8* gKeyBuffer = NULL;
|
||||
static uint32 gKeyBufferWriteIndex = 0;
|
||||
static uint32 gKeyBufferReadIndex = 0;
|
||||
|
||||
#define KEYBUFFER_SIZE 128
|
||||
|
||||
static BOOL keyboard_open(File *file, uint32 flags);
|
||||
static void keyboard_close(File *file);
|
||||
static int32 keyboard_read(File *file, uint32 size, uint8 *buffer);
|
||||
static int32 keyboard_ioctl(File *file, int32 request, void * argp);
|
||||
|
||||
typedef enum ReadMode
|
||||
{
|
||||
Blocking = 0,
|
||||
NonBlocking = 1
|
||||
} ReadMode;
|
||||
|
||||
typedef struct Reader
|
||||
{
|
||||
uint32 readIndex;
|
||||
ReadMode readMode;
|
||||
} Reader;
|
||||
|
||||
static List* gReaders = NULL;
|
||||
|
||||
static void handleKeyboardInterrupt(Registers *regs);
|
||||
|
||||
void initializeKeyboard()
|
||||
{
|
||||
Device device;
|
||||
memset((uint8*)&device, 0, sizeof(Device));
|
||||
strcpy(device.name, "keyboard");
|
||||
device.deviceType = FT_CharacterDevice;
|
||||
device.open = keyboard_open;
|
||||
device.close = keyboard_close;
|
||||
device.read = keyboard_read;
|
||||
device.ioctl = keyboard_ioctl;
|
||||
|
||||
gKeyBuffer = kmalloc(KEYBUFFER_SIZE);
|
||||
memset((uint8*)gKeyBuffer, 0, KEYBUFFER_SIZE);
|
||||
|
||||
gReaders = List_Create();
|
||||
|
||||
registerDevice(&device);
|
||||
|
||||
registerInterruptHandler(IRQ1, handleKeyboardInterrupt);
|
||||
}
|
||||
|
||||
static BOOL keyboard_open(File *file, uint32 flags)
|
||||
{
|
||||
Reader* reader = (Reader*)kmalloc(sizeof(Reader));
|
||||
reader->readIndex = 0;
|
||||
reader->readMode = Blocking;
|
||||
|
||||
if (gKeyBufferWriteIndex > 0)
|
||||
{
|
||||
reader->readIndex = gKeyBufferWriteIndex;
|
||||
}
|
||||
file->privateData = (void*)reader;
|
||||
|
||||
List_Append(gReaders, file);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void keyboard_close(File *file)
|
||||
{
|
||||
//Screen_PrintF("keyboard_close\n");
|
||||
|
||||
Reader* reader = (Reader*)file->privateData;
|
||||
|
||||
kfree(reader);
|
||||
|
||||
List_RemoveFirstOccurrence(gReaders, file);
|
||||
}
|
||||
|
||||
static int32 keyboard_read(File *file, uint32 size, uint8 *buffer)
|
||||
{
|
||||
Reader* reader = (Reader*)file->privateData;
|
||||
|
||||
uint32 readIndex = reader->readIndex;
|
||||
|
||||
if (reader->readMode == Blocking)
|
||||
{
|
||||
while (readIndex == gKeyBufferWriteIndex)
|
||||
{
|
||||
file->thread->state = TS_WAITIO;
|
||||
file->thread->state_privateData = keyboard_read;
|
||||
enableInterrupts();
|
||||
halt();
|
||||
}
|
||||
}
|
||||
|
||||
disableInterrupts();
|
||||
|
||||
if (readIndex == gKeyBufferWriteIndex)
|
||||
{
|
||||
//non-blocking return here
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffer[0] = gKeyBuffer[readIndex];
|
||||
readIndex++;
|
||||
readIndex %= KEYBUFFER_SIZE;
|
||||
|
||||
reader->readIndex = readIndex;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int32 keyboard_ioctl(File *file, int32 request, void * argp)
|
||||
{
|
||||
Reader* reader = (Reader*)file->privateData;
|
||||
|
||||
int cmd = (int)argp;
|
||||
|
||||
switch (request)
|
||||
{
|
||||
case 0: //get
|
||||
*(int*)argp = (int)reader->readMode;
|
||||
return 0;
|
||||
break;
|
||||
case 1: //set
|
||||
if (cmd == 0)
|
||||
{
|
||||
reader->readMode = Blocking;
|
||||
|
||||
return 0;
|
||||
}
|
||||
else if (cmd == 1)
|
||||
{
|
||||
reader->readMode = NonBlocking;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void handleKeyboardInterrupt(Registers *regs)
|
||||
{
|
||||
uint8 scancode = 0;
|
||||
do
|
||||
{
|
||||
scancode = inb(0x64);
|
||||
} while ((scancode & 0x01) == 0);
|
||||
|
||||
scancode = inb(0x60);
|
||||
|
||||
gKeyBuffer[gKeyBufferWriteIndex] = scancode;
|
||||
gKeyBufferWriteIndex++;
|
||||
gKeyBufferWriteIndex %= KEYBUFFER_SIZE;
|
||||
|
||||
//Wake readers
|
||||
List_Foreach(n, gReaders)
|
||||
{
|
||||
File* file = n->data;
|
||||
|
||||
if (file->thread->state == TS_WAITIO)
|
||||
{
|
||||
if (file->thread->state_privateData == keyboard_read)
|
||||
{
|
||||
file->thread->state = TS_RUN;
|
||||
file->thread->state_privateData = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sendKeyInputToTTY(getActiveTTY(), scancode);
|
||||
}
|
6
kernel.soso/keyboard.h
Normal file
6
kernel.soso/keyboard.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef KEYBOARD_H
|
||||
#define KEYBOARD_H
|
||||
|
||||
void initializeKeyboard();
|
||||
|
||||
#endif // KEYBOARD_H
|
34
kernel.soso/link.ld
Normal file
34
kernel.soso/link.ld
Normal file
|
@ -0,0 +1,34 @@
|
|||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 1M;
|
||||
|
||||
/* Code. */
|
||||
.text BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.multiboot)
|
||||
*(.text)
|
||||
}
|
||||
|
||||
/* Read-only data. */
|
||||
.rodata BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.rodata)
|
||||
}
|
||||
|
||||
/* Read-write data (initialized) */
|
||||
.data BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(.data)
|
||||
}
|
||||
|
||||
/* Read-write data (uninitialized) and stack */
|
||||
.bss BLOCK(4K) : ALIGN(4K)
|
||||
{
|
||||
*(COMMON)
|
||||
*(.bss)
|
||||
}
|
||||
|
||||
_end = .;
|
||||
}
|
304
kernel.soso/list.c
Normal file
304
kernel.soso/list.c
Normal file
|
@ -0,0 +1,304 @@
|
|||
#include "alloc.h"
|
||||
#include "common.h"
|
||||
#include "list.h"
|
||||
|
||||
List* List_Create()
|
||||
{
|
||||
List* list = (List*)kmalloc(sizeof(List));
|
||||
|
||||
memset((uint8*)list, 0, sizeof(List));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void List_Clear(List* list)
|
||||
{
|
||||
ListNode* listNode = list->head;
|
||||
|
||||
while (NULL != listNode)
|
||||
{
|
||||
ListNode* next = listNode->next;
|
||||
|
||||
kfree(listNode);
|
||||
|
||||
listNode = next;
|
||||
}
|
||||
|
||||
list->head = NULL;
|
||||
list->tail = NULL;
|
||||
}
|
||||
|
||||
void List_Destroy(List* list)
|
||||
{
|
||||
List_Clear(list);
|
||||
|
||||
kfree(list);
|
||||
}
|
||||
|
||||
List* List_CreateClone(List* list)
|
||||
{
|
||||
List* newList = List_Create();
|
||||
|
||||
List_Foreach(n, list)
|
||||
{
|
||||
List_Append(newList, n->data);
|
||||
}
|
||||
|
||||
return newList;
|
||||
}
|
||||
|
||||
BOOL List_IsEmpty(List* list)
|
||||
{
|
||||
//At empty state, both head and tail are null!
|
||||
return list->head == NULL;
|
||||
}
|
||||
|
||||
void List_Append(List* list, void* data)
|
||||
{
|
||||
ListNode* node = (ListNode*)kmalloc(sizeof(ListNode));
|
||||
|
||||
memset((uint8*)node, 0, sizeof(ListNode));
|
||||
node->data = data;
|
||||
|
||||
//At empty state, both head and tail are null!
|
||||
if (NULL == list->tail)
|
||||
{
|
||||
list->head = node;
|
||||
|
||||
list->tail = node;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
node->previous = list->tail;
|
||||
node->previous->next = node;
|
||||
list->tail = node;
|
||||
}
|
||||
|
||||
void List_Prepend(List* list, void* data)
|
||||
{
|
||||
ListNode* node = (ListNode*)kmalloc(sizeof(ListNode));
|
||||
|
||||
memset((uint8*)node, 0, sizeof(ListNode));
|
||||
node->data = data;
|
||||
|
||||
//At empty state, both head and tail are null!
|
||||
if (NULL == list->tail)
|
||||
{
|
||||
list->head = node;
|
||||
|
||||
list->tail = node;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
node->next = list->head;
|
||||
node->next->previous = node;
|
||||
list->head = node;
|
||||
}
|
||||
|
||||
ListNode* List_GetFirstNode(List* list)
|
||||
{
|
||||
return list->head;
|
||||
}
|
||||
|
||||
ListNode* List_GetLastNode(List* list)
|
||||
{
|
||||
return list->tail;
|
||||
}
|
||||
|
||||
ListNode* List_FindFirstOccurrence(List* list, void* data)
|
||||
{
|
||||
List_Foreach(n, list)
|
||||
{
|
||||
if (n->data == data)
|
||||
{
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int List_FindFirstOccurrenceIndex(List* list, void* data)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
List_Foreach(n, list)
|
||||
{
|
||||
if (n->data == data)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
++result;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int List_GetCount(List* list)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
List_Foreach(n, list)
|
||||
{
|
||||
++result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void List_RemoveNode(List* list, ListNode* node)
|
||||
{
|
||||
if (NULL == node)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (NULL != node->previous)
|
||||
{
|
||||
node->previous->next = node->next;
|
||||
}
|
||||
|
||||
if (NULL != node->next)
|
||||
{
|
||||
node->next->previous = node->previous;
|
||||
}
|
||||
|
||||
if (node == list->head)
|
||||
{
|
||||
list->head = node->next;
|
||||
}
|
||||
|
||||
if (node == list->tail)
|
||||
{
|
||||
list->tail = node->previous;
|
||||
}
|
||||
|
||||
kfree(node);
|
||||
}
|
||||
|
||||
void List_RemoveFirstNode(List* list)
|
||||
{
|
||||
if (NULL != list->head)
|
||||
{
|
||||
List_RemoveNode(list, list->head);
|
||||
}
|
||||
}
|
||||
|
||||
void List_RemoveLastNode(List* list)
|
||||
{
|
||||
if (NULL != list->tail)
|
||||
{
|
||||
List_RemoveNode(list, list->tail);
|
||||
}
|
||||
}
|
||||
|
||||
void List_RemoveFirstOccurrence(List* list, void* data)
|
||||
{
|
||||
ListNode* node = List_FindFirstOccurrence(list, data);
|
||||
|
||||
if (NULL != node)
|
||||
{
|
||||
List_RemoveNode(list, node);
|
||||
}
|
||||
}
|
||||
|
||||
Stack* Stack_Create()
|
||||
{
|
||||
Stack* stack = (Stack*)kmalloc(sizeof(Stack));
|
||||
|
||||
memset((uint8*)stack, 0, sizeof(Stack));
|
||||
|
||||
stack->list = List_Create();
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
void Stack_Clear(Stack* stack)
|
||||
{
|
||||
List_Clear(stack->list);
|
||||
}
|
||||
|
||||
void Stack_Destroy(Stack* stack)
|
||||
{
|
||||
List_Destroy(stack->list);
|
||||
|
||||
kfree(stack);
|
||||
}
|
||||
|
||||
BOOL Stack_IsEmpty(Stack* stack)
|
||||
{
|
||||
return List_IsEmpty(stack->list);
|
||||
}
|
||||
|
||||
void Stack_Push(Stack* stack, void* data)
|
||||
{
|
||||
List_Prepend(stack->list, data);
|
||||
}
|
||||
|
||||
void* Stack_Pop(Stack* stack)
|
||||
{
|
||||
void* result = NULL;
|
||||
|
||||
ListNode* node = List_GetFirstNode(stack->list);
|
||||
|
||||
if (NULL != node)
|
||||
{
|
||||
result = node->data;
|
||||
|
||||
List_RemoveNode(stack->list, node);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Queue* Queue_Create()
|
||||
{
|
||||
Queue* queue = (Queue*)kmalloc(sizeof(Queue));
|
||||
|
||||
memset((uint8*)queue, 0, sizeof(Queue));
|
||||
|
||||
queue->list = List_Create();
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
void Queue_Clear(Queue* queue)
|
||||
{
|
||||
List_Clear(queue->list);
|
||||
}
|
||||
|
||||
void Queue_Destroy(Queue* queue)
|
||||
{
|
||||
List_Destroy(queue->list);
|
||||
|
||||
kfree(queue);
|
||||
}
|
||||
|
||||
BOOL Queue_IsEmpty(Queue* queue)
|
||||
{
|
||||
return List_IsEmpty(queue->list);
|
||||
}
|
||||
|
||||
void Queue_Enqueue(Queue* queue, void* data)
|
||||
{
|
||||
List_Append(queue->list, data);
|
||||
}
|
||||
|
||||
void* Queue_Dequeue(Queue* stack)
|
||||
{
|
||||
void* result = NULL;
|
||||
|
||||
ListNode* node = List_GetFirstNode(stack->list);
|
||||
|
||||
if (NULL != node)
|
||||
{
|
||||
result = node->data;
|
||||
|
||||
List_RemoveNode(stack->list, node);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
62
kernel.soso/list.h
Normal file
62
kernel.soso/list.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
#ifndef LIST_H
|
||||
#define LIST_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define List_Foreach(listNode, list) for (ListNode* listNode = list->head; NULL != listNode ; listNode = listNode->next)
|
||||
|
||||
typedef struct ListNode
|
||||
{
|
||||
struct ListNode* previous;
|
||||
struct ListNode* next;
|
||||
void* data;
|
||||
} ListNode;
|
||||
|
||||
typedef struct List
|
||||
{
|
||||
struct ListNode* head;
|
||||
struct ListNode* tail;
|
||||
} List;
|
||||
|
||||
List* List_Create();
|
||||
void List_Clear(List* list);
|
||||
void List_Destroy(List* list);
|
||||
List* List_CreateClone(List* list);
|
||||
BOOL List_IsEmpty(List* list);
|
||||
void List_Append(List* list, void* data);
|
||||
void List_Prepend(List* list, void* data);
|
||||
ListNode* List_GetFirstNode(List* list);
|
||||
ListNode* List_GetLastNode(List* list);
|
||||
ListNode* List_FindFirstOccurrence(List* list, void* data);
|
||||
int List_FindFirstOccurrenceIndex(List* list, void* data);
|
||||
int List_GetCount(List* list);
|
||||
void List_RemoveNode(List* list, ListNode* node);
|
||||
void List_RemoveFirstNode(List* list);
|
||||
void List_RemoveLastNode(List* list);
|
||||
void List_RemoveFirstOccurrence(List* list, void* data);
|
||||
|
||||
typedef struct Stack
|
||||
{
|
||||
List* list;
|
||||
} Stack;
|
||||
|
||||
Stack* Stack_Create();
|
||||
void Stack_Clear(Stack* stack);
|
||||
void Stack_Destroy(Stack* stack);
|
||||
BOOL Stack_IsEmpty(Stack* stack);
|
||||
void Stack_Push(Stack* stack, void* data);
|
||||
void* Stack_Pop(Stack* stack);
|
||||
|
||||
typedef struct Queue
|
||||
{
|
||||
List* list;
|
||||
} Queue;
|
||||
|
||||
Queue* Queue_Create();
|
||||
void Queue_Clear(Queue* queue);
|
||||
void Queue_Destroy(Queue* queue);
|
||||
BOOL Queue_IsEmpty(Queue* queue);
|
||||
void Queue_Enqueue(Queue* queue, void* data);
|
||||
void* Queue_Dequeue(Queue* stack);
|
||||
|
||||
#endif // LIST_H
|
234
kernel.soso/main.c
Normal file
234
kernel.soso/main.c
Normal file
|
@ -0,0 +1,234 @@
|
|||
#include "screen.h"
|
||||
#include "descriptortables.h"
|
||||
#include "timer.h"
|
||||
#include "multiboot.h"
|
||||
#include "fs.h"
|
||||
#include "syscalls.h"
|
||||
#include "serial.h"
|
||||
#include "isr.h"
|
||||
#include "vmm.h"
|
||||
#include "alloc.h"
|
||||
#include "process.h"
|
||||
#include "keyboard.h"
|
||||
#include "ttydriver.h"
|
||||
#include "devfs.h"
|
||||
#include "systemfs.h"
|
||||
#include "pipe.h"
|
||||
#include "sharedmemory.h"
|
||||
#include "random.h"
|
||||
#include "null.h"
|
||||
#include "elf.h"
|
||||
#include "debugprint.h"
|
||||
#include "ramdisk.h"
|
||||
#include "fatfilesystem.h"
|
||||
#include "vbe.h"
|
||||
#include "fifobuffer.h"
|
||||
#include "gfx.h"
|
||||
#include "mouse.h"
|
||||
#include "sleep.h"
|
||||
|
||||
extern uint32 _start;
|
||||
extern uint32 _end;
|
||||
uint32 gPhysicalKernelStartAddress = (uint32)&_start;
|
||||
uint32 gPhysicalKernelEndAddress = (uint32)&_end;
|
||||
|
||||
static void* locateInitrd(struct Multiboot *mbi, uint32* size)
|
||||
{
|
||||
if (mbi->mods_count > 0)
|
||||
{
|
||||
uint32 startLocation = *((uint32*)mbi->mods_addr);
|
||||
uint32 endLocation = *(uint32*)(mbi->mods_addr + 4);
|
||||
|
||||
*size = endLocation - startLocation;
|
||||
|
||||
return (void*)startLocation;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void printUsageInfo()
|
||||
{
|
||||
char buffer[164];
|
||||
|
||||
sprintf(buffer, "Used kheap:%d", getKernelHeapUsed());
|
||||
Screen_Print(0, 60, buffer);
|
||||
|
||||
sprintf(buffer, "Pages:%d/%d ", getUsedPageCount(), getTotalPageCount());
|
||||
Screen_Print(1, 60, buffer);
|
||||
|
||||
sprintf(buffer, "Uptime:%d sec ", getUptimeSeconds());
|
||||
Screen_Print(2, 60, buffer);
|
||||
|
||||
Thread* p = getMainKernelThread();
|
||||
|
||||
int line = 3;
|
||||
sprintf(buffer, "[idle] cs:%d ", p->totalContextSwitchCount);
|
||||
Screen_Print(line++, 60, buffer);
|
||||
p = p->next;
|
||||
while (p != NULL)
|
||||
{
|
||||
sprintf(buffer, "thread:%d cs:%d ", p->threadId, p->totalContextSwitchCount);
|
||||
|
||||
Screen_Print(line++, 60, buffer);
|
||||
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
||||
int executeFile(const char *path, char *const argv[], char *const envp[], FileSystemNode* tty)
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
Process* process = getCurrentThread()->owner;
|
||||
if (process)
|
||||
{
|
||||
FileSystemNode* node = getFileSystemNodeAbsoluteOrRelative(path, process);
|
||||
if (node)
|
||||
{
|
||||
File* f = open_fs(node, 0);
|
||||
if (f)
|
||||
{
|
||||
void* image = kmalloc(node->length);
|
||||
|
||||
int32 bytesRead = read_fs(f, node->length, image);
|
||||
|
||||
if (bytesRead > 0)
|
||||
{
|
||||
Process* newProcess = createUserProcessFromElfData("userProcess", image, argv, envp, process, tty);
|
||||
|
||||
if (newProcess)
|
||||
{
|
||||
result = newProcess->pid;
|
||||
}
|
||||
}
|
||||
close_fs(f);
|
||||
|
||||
kfree(image);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void printAsciiArt()
|
||||
{
|
||||
printkf(" ________ ________ ________ ________ \n");
|
||||
printkf(" |\\ ____\\ |\\ __ \\ |\\ ____\\ |\\ __ \\ \n");
|
||||
printkf(" \\ \\ \\___|_ \\ \\ \\|\\ \\ \\ \\ \\___|_ \\ \\ \\|\\ \\ \n");
|
||||
printkf(" \\ \\_____ \\ \\ \\ \\\\\\ \\ \\ \\_____ \\ \\ \\ \\\\\\ \\ \n");
|
||||
printkf(" \\|____|\\ \\ \\ \\ \\\\\\ \\ \\|____|\\ \\ \\ \\ \\\\\\ \\ \n");
|
||||
printkf(" ____\\_\\ \\ \\ \\_______\\ ____\\_\\ \\ \\ \\_______\\\n");
|
||||
printkf(" |\\_________\\ \\|_______| |\\_________\\ \\|_______|\n");
|
||||
printkf(" \\|_________| \\|_________| \n");
|
||||
printkf("\n");
|
||||
}
|
||||
|
||||
int kmain(struct Multiboot *mboot_ptr)
|
||||
{
|
||||
int stack = 5;
|
||||
|
||||
initializeDescriptorTables();
|
||||
|
||||
initializeSerial();
|
||||
|
||||
uint32 memoryKb = mboot_ptr->mem_upper;//96*1024;
|
||||
initializeMemory(memoryKb);
|
||||
|
||||
initializeVFS();
|
||||
initializeDevFS();
|
||||
|
||||
if (MULTIBOOT_FRAMEBUFFER_TYPE_RGB == mboot_ptr->framebuffer_type)
|
||||
{
|
||||
Gfx_Initialize((uint32*)(uint32)mboot_ptr->framebuffer_addr, mboot_ptr->framebuffer_width, mboot_ptr->framebuffer_height, mboot_ptr->framebuffer_bpp / 32, mboot_ptr->framebuffer_pitch);
|
||||
|
||||
initializeTTYs(TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
initializeTTYs(FALSE);
|
||||
}
|
||||
//printkf works after TTY initialization
|
||||
|
||||
printAsciiArt();
|
||||
|
||||
printkf("Lower Memory: %d KB\n", mboot_ptr->mem_lower);
|
||||
printkf("Upper Memory: %d KB\n", mboot_ptr->mem_upper);
|
||||
printkf("Memory initialized for %d MB\n", memoryKb / 1024);
|
||||
printkf("Kernel start: %x - end:%x\n", gPhysicalKernelStartAddress, gPhysicalKernelEndAddress);
|
||||
printkf("Initial stack: %x\n", &stack);
|
||||
printkf("Video: %dx%dx%d Pitch:%d\n", mboot_ptr->framebuffer_width, mboot_ptr->framebuffer_height, mboot_ptr->framebuffer_bpp, mboot_ptr->framebuffer_pitch);
|
||||
|
||||
initializeSystemFS();
|
||||
initializePipes();
|
||||
initializeSharedMemory();
|
||||
|
||||
initializeTasking();
|
||||
|
||||
initialiseSyscalls();
|
||||
|
||||
initializeTimer();
|
||||
|
||||
initializeKeyboard();
|
||||
initializeMouse();
|
||||
|
||||
if (0 != mboot_ptr->cmdline)
|
||||
{
|
||||
printkf("Kernel cmdline:%s\n", (char*)mboot_ptr->cmdline);
|
||||
}
|
||||
|
||||
Debug_initialize("/dev/tty9");
|
||||
|
||||
Serial_PrintF("pitch:%d\n", mboot_ptr->framebuffer_pitch);
|
||||
|
||||
initializeRandom();
|
||||
initializeNull();
|
||||
|
||||
createRamdisk("ramdisk1", 20*1024*1024);
|
||||
|
||||
initializeFatFileSystem();
|
||||
|
||||
printkf("System started!\n");
|
||||
|
||||
char* argv[] = {"shell", NULL};
|
||||
char* envp[] = {"HOME=/", "PATH=/initrd", NULL};
|
||||
|
||||
uint32 initrdSize = 0;
|
||||
uint8* initrdLocation = locateInitrd(mboot_ptr, &initrdSize);
|
||||
if (initrdLocation == NULL)
|
||||
{
|
||||
PANIC("Initrd not found!\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printkf("Initrd found at %x (%d bytes)\n", initrdLocation, initrdSize);
|
||||
memcpy((uint8*)*(uint32*)getFileSystemNode("/dev/ramdisk1")->privateNodeData, initrdLocation, initrdSize);
|
||||
BOOL mountSuccess = mountFileSystem("/dev/ramdisk1", "/initrd", "fat", 0, 0);
|
||||
|
||||
if (mountSuccess)
|
||||
{
|
||||
printkf("Starting shell on TTYs\n");
|
||||
|
||||
executeFile("/initrd/init", argv, envp, getFileSystemNode("/dev/tty1"));
|
||||
}
|
||||
else
|
||||
{
|
||||
printkf("Mounting initrd failed!\n");
|
||||
}
|
||||
}
|
||||
|
||||
enableScheduler();
|
||||
|
||||
enableInterrupts();
|
||||
|
||||
while(TRUE)
|
||||
{
|
||||
//Idle thread
|
||||
|
||||
halt();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
51
kernel.soso/message.c
Normal file
51
kernel.soso/message.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
#include "message.h"
|
||||
#include "process.h"
|
||||
#include "fifobuffer.h"
|
||||
|
||||
|
||||
void sendMesage(Thread* thread, SosoMessage* message)
|
||||
{
|
||||
Spinlock_Lock(&(thread->messageQueueLock));
|
||||
|
||||
FifoBuffer_enqueue(thread->messageQueue, (uint8*)message, sizeof(SosoMessage));
|
||||
|
||||
Spinlock_Unlock(&(thread->messageQueueLock));
|
||||
}
|
||||
|
||||
uint32 getMessageQueueCount(Thread* thread)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
Spinlock_Lock(&(thread->messageQueueLock));
|
||||
|
||||
result = FifoBuffer_getSize(thread->messageQueue) / sizeof(SosoMessage);
|
||||
|
||||
Spinlock_Unlock(&(thread->messageQueueLock));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//returns remaining message count
|
||||
int32 getNextMessage(Thread* thread, SosoMessage* message)
|
||||
{
|
||||
uint32 result = -1;
|
||||
|
||||
Spinlock_Lock(&(thread->messageQueueLock));
|
||||
|
||||
result = FifoBuffer_getSize(thread->messageQueue) / sizeof(SosoMessage);
|
||||
|
||||
if (result > 0)
|
||||
{
|
||||
FifoBuffer_dequeue(thread->messageQueue, (uint8*)message, sizeof(SosoMessage));
|
||||
|
||||
--result;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = -1;
|
||||
}
|
||||
|
||||
Spinlock_Unlock(&(thread->messageQueueLock));
|
||||
|
||||
return result;
|
||||
}
|
16
kernel.soso/message.h
Normal file
16
kernel.soso/message.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef MESSAGE_H
|
||||
#define MESSAGE_H
|
||||
|
||||
#include "common.h"
|
||||
#include "commonuser.h"
|
||||
|
||||
typedef struct Thread Thread;
|
||||
|
||||
void sendMesage(Thread* thread, SosoMessage* message);
|
||||
|
||||
uint32 getMessageQueueCount(Thread* thread);
|
||||
|
||||
//returns remaining message count
|
||||
int32 getNextMessage(Thread* thread, SosoMessage* message);
|
||||
|
||||
#endif // MESSAGE_H
|
203
kernel.soso/mouse.c
Normal file
203
kernel.soso/mouse.c
Normal file
|
@ -0,0 +1,203 @@
|
|||
#include "mouse.h"
|
||||
#include "isr.h"
|
||||
#include "common.h"
|
||||
#include "device.h"
|
||||
#include "alloc.h"
|
||||
#include "devfs.h"
|
||||
#include "list.h"
|
||||
#include "fifobuffer.h"
|
||||
#include "spinlock.h"
|
||||
|
||||
static void handleMouseInterrupt(Registers *regs);
|
||||
|
||||
static uint8 gMouseByteCounter = 0;
|
||||
|
||||
static void prepareForRead();
|
||||
static void prepareForWrite();
|
||||
static void writeMouse(uint8 data);
|
||||
static void handleMouseInterrupt(Registers *regs);
|
||||
|
||||
static BOOL mouse_open(File *file, uint32 flags);
|
||||
static void mouse_close(File *file);
|
||||
static int32 mouse_read(File *file, uint32 size, uint8 *buffer);
|
||||
|
||||
#define MOUSE_PACKET_SIZE 3
|
||||
|
||||
uint8 gMousePacket[MOUSE_PACKET_SIZE];
|
||||
|
||||
static List* gReaders = NULL;
|
||||
|
||||
static Spinlock gReadersLock;
|
||||
|
||||
void initializeMouse()
|
||||
{
|
||||
Device device;
|
||||
memset((uint8*)&device, 0, sizeof(Device));
|
||||
strcpy(device.name, "psaux");
|
||||
device.deviceType = FT_CharacterDevice;
|
||||
device.open = mouse_open;
|
||||
device.close = mouse_close;
|
||||
device.read = mouse_read;
|
||||
registerInterruptHandler(IRQ12, handleMouseInterrupt);
|
||||
|
||||
registerDevice(&device);
|
||||
|
||||
memset(gMousePacket, 0, MOUSE_PACKET_SIZE);
|
||||
|
||||
gReaders = List_Create();
|
||||
|
||||
Spinlock_Init(&gReadersLock);
|
||||
|
||||
prepareForWrite();
|
||||
|
||||
outb(0x64, 0x20); //get status command
|
||||
|
||||
uint8 status = inb(0x60);
|
||||
status = status | 2; //enable IRQ12
|
||||
|
||||
outb(0x64, 0x60); //set status command
|
||||
outb(0x60, status);
|
||||
|
||||
outb(0x64, 0xA8); //enable Auxiliary Device command
|
||||
|
||||
writeMouse(0xF4); //0xF4: Enable Packet Streaming
|
||||
}
|
||||
|
||||
static BOOL mouse_open(File *file, uint32 flags)
|
||||
{
|
||||
FifoBuffer* fifo = FifoBuffer_create(60);
|
||||
|
||||
file->privateData = (void*)fifo;
|
||||
|
||||
Spinlock_Lock(&gReadersLock);
|
||||
|
||||
List_Append(gReaders, file);
|
||||
|
||||
Spinlock_Unlock(&gReadersLock);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void mouse_close(File *file)
|
||||
{
|
||||
Spinlock_Lock(&gReadersLock);
|
||||
|
||||
List_RemoveFirstOccurrence(gReaders, file);
|
||||
|
||||
Spinlock_Unlock(&gReadersLock);
|
||||
|
||||
FifoBuffer* fifo = (FifoBuffer*)file->privateData;
|
||||
|
||||
FifoBuffer_destroy(fifo);
|
||||
}
|
||||
|
||||
static int32 mouse_read(File *file, uint32 size, uint8 *buffer)
|
||||
{
|
||||
FifoBuffer* fifo = (FifoBuffer*)file->privateData;
|
||||
|
||||
while (FifoBuffer_getSize(fifo) < MOUSE_PACKET_SIZE)
|
||||
{
|
||||
file->thread->state = TS_WAITIO;
|
||||
file->thread->state_privateData = mouse_read;
|
||||
enableInterrupts();
|
||||
halt();
|
||||
}
|
||||
|
||||
disableInterrupts();
|
||||
|
||||
|
||||
uint32 available = FifoBuffer_getSize(fifo);
|
||||
uint32 smaller = MIN(available, size);
|
||||
|
||||
FifoBuffer_dequeue(fifo, buffer, smaller);
|
||||
|
||||
return smaller;
|
||||
}
|
||||
|
||||
static void prepareForRead()
|
||||
{
|
||||
//https://wiki.osdev.org/Mouse_Input
|
||||
//Bytes cannot be read from port 0x60 until bit 0 (value=1) of port 0x64 is set
|
||||
|
||||
int32 tryCount = 1000;
|
||||
|
||||
uint8 data = 0;
|
||||
do
|
||||
{
|
||||
data = inb(0x64);
|
||||
} while (((data & 0x01) == 0) && --tryCount > 0);
|
||||
}
|
||||
|
||||
static void prepareForWrite()
|
||||
{
|
||||
//https://wiki.osdev.org/Mouse_Input
|
||||
//All output to port 0x60 or 0x64 must be preceded by waiting for bit 1 (value=2) of port 0x64 to become clear
|
||||
|
||||
int32 tryCount = 1000;
|
||||
|
||||
uint8 data = 0;
|
||||
do
|
||||
{
|
||||
data = inb(0x64);
|
||||
} while (((data & 0x02) != 0) && --tryCount > 0);
|
||||
}
|
||||
|
||||
static void writeMouse(uint8 data)
|
||||
{
|
||||
prepareForWrite();
|
||||
|
||||
outb(0x64, 0xD4);
|
||||
|
||||
prepareForWrite();
|
||||
|
||||
outb(0x60, data);
|
||||
}
|
||||
|
||||
static void handleMouseInterrupt(Registers *regs)
|
||||
{
|
||||
uint8 status = 0;
|
||||
//0x20 (5th bit is mouse bit)
|
||||
//read from 0x64, if its mouse bit is 1 then data is available at 0x60!
|
||||
|
||||
int32 tryCount = 1000;
|
||||
do
|
||||
{
|
||||
status = inb(0x64);
|
||||
} while (((status & 0x20) == 0) && --tryCount > 0);
|
||||
|
||||
uint8 data = inb(0x60);
|
||||
|
||||
gMousePacket[gMouseByteCounter] = data;
|
||||
|
||||
gMouseByteCounter += 1;
|
||||
|
||||
if (gMouseByteCounter == MOUSE_PACKET_SIZE)
|
||||
{
|
||||
gMouseByteCounter = 0;
|
||||
|
||||
Spinlock_Lock(&gReadersLock);
|
||||
|
||||
//Wake readers
|
||||
List_Foreach(n, gReaders)
|
||||
{
|
||||
File* file = n->data;
|
||||
|
||||
FifoBuffer* fifo = (FifoBuffer*)file->privateData;
|
||||
|
||||
FifoBuffer_enqueue(fifo, gMousePacket, MOUSE_PACKET_SIZE);
|
||||
|
||||
if (file->thread->state == TS_WAITIO)
|
||||
{
|
||||
if (file->thread->state_privateData == mouse_read)
|
||||
{
|
||||
file->thread->state = TS_RUN;
|
||||
file->thread->state_privateData = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spinlock_Unlock(&gReadersLock);
|
||||
}
|
||||
|
||||
//printkf("mouse:%d\n", data);
|
||||
}
|
6
kernel.soso/mouse.h
Normal file
6
kernel.soso/mouse.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef MOUSE_H
|
||||
#define MOUSE_H
|
||||
|
||||
void initializeMouse();
|
||||
|
||||
#endif // MOUSE_H
|
45
kernel.soso/multiboot.h
Normal file
45
kernel.soso/multiboot.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
#ifndef MULTIBOOT_H
|
||||
#define MULTIBOOT_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
|
||||
#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1
|
||||
#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2
|
||||
|
||||
struct Multiboot
|
||||
{
|
||||
uint32 flags;
|
||||
uint32 mem_lower;
|
||||
uint32 mem_upper;
|
||||
uint32 boot_device;
|
||||
uint32 cmdline;
|
||||
uint32 mods_count;
|
||||
uint32 mods_addr;
|
||||
uint32 num;
|
||||
uint32 size;
|
||||
uint32 addr;
|
||||
uint32 shndx;
|
||||
uint32 mmap_length;
|
||||
uint32 mmap_addr;
|
||||
uint32 drives_length;
|
||||
uint32 drives_addr;
|
||||
uint32 config_table;
|
||||
uint32 boot_loader_name;
|
||||
uint32 apm_table;
|
||||
uint32 vbe_control_info;
|
||||
uint32 vbe_mode_info;
|
||||
uint16 vbe_mode;
|
||||
uint16 vbe_interface_seg;
|
||||
uint16 vbe_interface_off;
|
||||
uint16 vbe_interface_len;
|
||||
|
||||
uint64 framebuffer_addr;
|
||||
uint32 framebuffer_pitch;
|
||||
uint32 framebuffer_width;
|
||||
uint32 framebuffer_height;
|
||||
uint8 framebuffer_bpp;
|
||||
uint8 framebuffer_type;
|
||||
} __attribute__((packed));
|
||||
|
||||
#endif
|
22
kernel.soso/null.c
Normal file
22
kernel.soso/null.c
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include "null.h"
|
||||
#include "devfs.h"
|
||||
#include "device.h"
|
||||
#include "common.h"
|
||||
|
||||
static BOOL null_open(File *file, uint32 flags);
|
||||
|
||||
void initializeNull()
|
||||
{
|
||||
Device device;
|
||||
memset((uint8*)&device, 0, sizeof(Device));
|
||||
strcpy(device.name, "null");
|
||||
device.deviceType = FT_CharacterDevice;
|
||||
device.open = null_open;
|
||||
|
||||
registerDevice(&device);
|
||||
}
|
||||
|
||||
static BOOL null_open(File *file, uint32 flags)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
6
kernel.soso/null.h
Normal file
6
kernel.soso/null.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef NULL_H
|
||||
#define NULL_H
|
||||
|
||||
void initializeNull();
|
||||
|
||||
#endif // NULL_H
|
258
kernel.soso/pipe.c
Normal file
258
kernel.soso/pipe.c
Normal file
|
@ -0,0 +1,258 @@
|
|||
#include "list.h"
|
||||
#include "pipe.h"
|
||||
#include "fs.h"
|
||||
#include "alloc.h"
|
||||
#include "fifobuffer.h"
|
||||
|
||||
static List* gPipeList = NULL;
|
||||
|
||||
static FileSystemNode* gPipesRoot = NULL;
|
||||
|
||||
static FileSystemDirent gDirent;
|
||||
|
||||
typedef struct Pipe
|
||||
{
|
||||
char name[32];
|
||||
FifoBuffer* buffer;
|
||||
FileSystemNode* fsNode;
|
||||
List* accessingThreads;
|
||||
} Pipe;
|
||||
|
||||
static BOOL pipes_open(File *file, uint32 flags);
|
||||
static FileSystemDirent *pipes_readdir(FileSystemNode *node, uint32 index);
|
||||
static FileSystemNode *pipes_finddir(FileSystemNode *node, char *name);
|
||||
|
||||
void initializePipes()
|
||||
{
|
||||
gPipeList = List_Create();
|
||||
|
||||
gPipesRoot = getFileSystemNode("/system/pipes");
|
||||
|
||||
if (NULL == gPipesRoot)
|
||||
{
|
||||
WARNING("/system/pipes not found!!");
|
||||
}
|
||||
else
|
||||
{
|
||||
gPipesRoot->open = pipes_open;
|
||||
gPipesRoot->finddir = pipes_finddir;
|
||||
gPipesRoot->readdir = pipes_readdir;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL pipes_open(File *file, uint32 flags)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static FileSystemDirent *pipes_readdir(FileSystemNode *node, uint32 index)
|
||||
{
|
||||
int counter = 0;
|
||||
|
||||
List_Foreach (n, gPipeList)
|
||||
{
|
||||
Pipe* p = (Pipe*)n->data;
|
||||
|
||||
if (counter == index)
|
||||
{
|
||||
strcpy(gDirent.name, p->name);
|
||||
gDirent.fileType = FT_Pipe;
|
||||
|
||||
return &gDirent;
|
||||
}
|
||||
++counter;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static FileSystemNode *pipes_finddir(FileSystemNode *node, char *name)
|
||||
{
|
||||
List_Foreach (n, gPipeList)
|
||||
{
|
||||
Pipe* p = (Pipe*)n->data;
|
||||
|
||||
if (strcmp(name, p->name) == 0)
|
||||
{
|
||||
return p->fsNode;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static BOOL pipe_open(File *file, uint32 flags)
|
||||
{
|
||||
beginCriticalSection();
|
||||
|
||||
Pipe* pipe = file->node->privateNodeData;
|
||||
|
||||
List_Append(pipe->accessingThreads, file->thread);
|
||||
|
||||
endCriticalSection();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void pipe_close(File *file)
|
||||
{
|
||||
beginCriticalSection();
|
||||
|
||||
Pipe* pipe = file->node->privateNodeData;
|
||||
|
||||
List_RemoveFirstOccurrence(pipe->accessingThreads, file->thread);
|
||||
|
||||
endCriticalSection();
|
||||
}
|
||||
|
||||
static void blockAccessingThreads(Pipe* pipe)
|
||||
{
|
||||
disableInterrupts();
|
||||
|
||||
List_Foreach (n, pipe->accessingThreads)
|
||||
{
|
||||
Thread* reader = n->data;
|
||||
|
||||
reader->state = TS_WAITIO;
|
||||
|
||||
reader->state_privateData = pipe;
|
||||
}
|
||||
|
||||
enableInterrupts();
|
||||
|
||||
halt();
|
||||
}
|
||||
|
||||
static void wakeupAccessingThreads(Pipe* pipe)
|
||||
{
|
||||
beginCriticalSection();
|
||||
|
||||
List_Foreach (n, pipe->accessingThreads)
|
||||
{
|
||||
Thread* reader = n->data;
|
||||
|
||||
if (reader->state == TS_WAITIO)
|
||||
{
|
||||
if (reader->state_privateData == pipe)
|
||||
{
|
||||
reader->state = TS_RUN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
endCriticalSection();
|
||||
}
|
||||
|
||||
static int32 pipe_read(File *file, uint32 size, uint8 *buffer)
|
||||
{
|
||||
if (0 == size || NULL == buffer)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
Pipe* pipe = file->node->privateNodeData;
|
||||
|
||||
uint32 used = 0;
|
||||
while ((used = FifoBuffer_getSize(pipe->buffer)) < size)
|
||||
{
|
||||
blockAccessingThreads(pipe);
|
||||
}
|
||||
|
||||
disableInterrupts();
|
||||
|
||||
int32 readBytes = FifoBuffer_dequeue(pipe->buffer, buffer, size);
|
||||
|
||||
wakeupAccessingThreads(pipe);
|
||||
|
||||
return readBytes;
|
||||
}
|
||||
|
||||
static int32 pipe_write(File *file, uint32 size, uint8 *buffer)
|
||||
{
|
||||
if (0 == size || NULL == buffer)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
Pipe* pipe = file->node->privateNodeData;
|
||||
|
||||
uint32 free = 0;
|
||||
while ((free = FifoBuffer_getFree(pipe->buffer)) < size)
|
||||
{
|
||||
blockAccessingThreads(pipe);
|
||||
}
|
||||
|
||||
disableInterrupts();
|
||||
|
||||
int32 bytesWritten = FifoBuffer_enqueue(pipe->buffer, buffer, size);
|
||||
|
||||
wakeupAccessingThreads(pipe);
|
||||
|
||||
return bytesWritten;
|
||||
}
|
||||
|
||||
BOOL createPipe(const char* name, uint32 bufferSize)
|
||||
{
|
||||
List_Foreach (n, gPipeList)
|
||||
{
|
||||
Pipe* p = (Pipe*)n->data;
|
||||
if (strcmp(name, p->name) == 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
Pipe* pipe = (Pipe*)kmalloc(sizeof(Pipe));
|
||||
memset((uint8*)pipe, 0, sizeof(Pipe));
|
||||
|
||||
strcpy(pipe->name, name);
|
||||
pipe->buffer = FifoBuffer_create(bufferSize);
|
||||
|
||||
pipe->accessingThreads = List_Create();
|
||||
|
||||
pipe->fsNode = (FileSystemNode*)kmalloc(sizeof(FileSystemNode));
|
||||
memset((uint8*)pipe->fsNode, 0, sizeof(FileSystemNode));
|
||||
pipe->fsNode->privateNodeData = pipe;
|
||||
pipe->fsNode->open = pipe_open;
|
||||
pipe->fsNode->close = pipe_close;
|
||||
pipe->fsNode->read = pipe_read;
|
||||
pipe->fsNode->write = pipe_write;
|
||||
|
||||
List_Append(gPipeList, pipe);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL destroyPipe(const char* name)
|
||||
{
|
||||
List_Foreach (n, gPipeList)
|
||||
{
|
||||
Pipe* p = (Pipe*)n->data;
|
||||
if (strcmp(name, p->name) == 0)
|
||||
{
|
||||
List_RemoveFirstOccurrence(gPipeList, p);
|
||||
FifoBuffer_destroy(p->buffer);
|
||||
List_Destroy(p->accessingThreads);
|
||||
kfree(p->fsNode);
|
||||
kfree(p);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL existsPipe(const char* name)
|
||||
{
|
||||
List_Foreach (n, gPipeList)
|
||||
{
|
||||
Pipe* p = (Pipe*)n->data;
|
||||
if (strcmp(name, p->name) == 0)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
11
kernel.soso/pipe.h
Normal file
11
kernel.soso/pipe.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef PIPE_H
|
||||
#define PIPE_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
void initializePipes();
|
||||
BOOL createPipe(const char* name, uint32 bufferSize);
|
||||
BOOL destroyPipe(const char* name);
|
||||
BOOL existsPipe(const char* name);
|
||||
|
||||
#endif // PIPE_H
|
812
kernel.soso/process.c
Normal file
812
kernel.soso/process.c
Normal file
|
@ -0,0 +1,812 @@
|
|||
#include "process.h"
|
||||
#include "common.h"
|
||||
#include "alloc.h"
|
||||
#include "vmm.h"
|
||||
#include "descriptortables.h"
|
||||
#include "elf.h"
|
||||
#include "screen.h"
|
||||
#include "debugprint.h"
|
||||
#include "isr.h"
|
||||
#include "timer.h"
|
||||
#include "message.h"
|
||||
|
||||
#define MESSAGE_QUEUE_SIZE 64
|
||||
|
||||
Process* gKernelProcess = NULL;
|
||||
|
||||
Thread* gFirstThread = NULL;
|
||||
Thread* gCurrentThread = NULL;
|
||||
|
||||
Thread* gDestroyedThread = NULL;
|
||||
|
||||
uint32 gProcessIdGenerator = 0;
|
||||
uint32 gThreadIdGenerator = 0;
|
||||
|
||||
uint32 gSystemContextSwitchCount = 0;
|
||||
uint32 gLastUptimeSeconds = 0;
|
||||
|
||||
extern Tss gTss;
|
||||
|
||||
uint32 generateProcessId()
|
||||
{
|
||||
return gProcessIdGenerator++;
|
||||
}
|
||||
|
||||
uint32 generateThreadId()
|
||||
{
|
||||
return gThreadIdGenerator++;
|
||||
}
|
||||
|
||||
uint32 getSystemContextSwitchCount()
|
||||
{
|
||||
return gSystemContextSwitchCount;
|
||||
}
|
||||
|
||||
void initializeTasking()
|
||||
{
|
||||
Process* process = (Process*)kmalloc(sizeof(Process));
|
||||
memset((uint8*)process, 0, sizeof(Process));
|
||||
strcpy(process->name, "[kernel]");
|
||||
process->pid = generateProcessId();
|
||||
process->pd = (uint32*) KERN_PAGE_DIRECTORY;
|
||||
process->workingDirectory = getFileSystemRootNode();
|
||||
|
||||
gKernelProcess = process;
|
||||
|
||||
|
||||
Thread* thread = (Thread*)kmalloc(sizeof(Thread));
|
||||
memset((uint8*)thread, 0, sizeof(Thread));
|
||||
|
||||
thread->owner = gKernelProcess;
|
||||
|
||||
thread->threadId = generateThreadId();
|
||||
|
||||
thread->userMode = 0;
|
||||
thread->state = TS_RUN;
|
||||
thread->messageQueue = FifoBuffer_create(sizeof(SosoMessage) * MESSAGE_QUEUE_SIZE);
|
||||
Spinlock_Init(&(thread->messageQueueLock));
|
||||
thread->regs.cr3 = (uint32) process->pd;
|
||||
|
||||
uint32 selector = 0x10;
|
||||
|
||||
thread->regs.ss = selector;
|
||||
thread->regs.eflags = 0x0;
|
||||
thread->regs.cs = 0x08;
|
||||
thread->regs.eip = NULL;
|
||||
thread->regs.ds = selector;
|
||||
thread->regs.es = selector;
|
||||
thread->regs.fs = selector;
|
||||
thread->regs.gs = selector;
|
||||
|
||||
thread->regs.esp = 0; //no need because this is already main kernel thread. ESP will written to this in first schedule.
|
||||
|
||||
thread->kstack.ss0 = 0x10;
|
||||
thread->kstack.esp0 = 0;//For kernel threads, this is not required
|
||||
|
||||
|
||||
gFirstThread = thread;
|
||||
gCurrentThread = thread;
|
||||
}
|
||||
|
||||
static int getStringArrayItemCount(char *const array[])
|
||||
{
|
||||
if (NULL == array)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
const char* a = array[0];
|
||||
while (NULL != a)
|
||||
{
|
||||
a = array[++i];
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static char** cloneStringArray(char *const array[])
|
||||
{
|
||||
int itemCount = getStringArrayItemCount(array);
|
||||
|
||||
char** newArray = kmalloc(sizeof(char*) * (itemCount + 1));
|
||||
|
||||
for (int i = 0; i < itemCount; ++i)
|
||||
{
|
||||
const char* str = array[i];
|
||||
int len = strlen(str);
|
||||
|
||||
char* newStr = kmalloc(len + 1);
|
||||
strcpy(newStr, str);
|
||||
|
||||
newArray[i] = newStr;
|
||||
}
|
||||
|
||||
newArray[itemCount] = NULL;
|
||||
|
||||
return newArray;
|
||||
}
|
||||
|
||||
static void destroyStringArray(char** array)
|
||||
{
|
||||
char* a = array[0];
|
||||
|
||||
int i = 0;
|
||||
|
||||
while (NULL != a)
|
||||
{
|
||||
kfree(a);
|
||||
|
||||
a = array[++i];
|
||||
}
|
||||
|
||||
kfree(array);
|
||||
}
|
||||
|
||||
//This function must be called within the correct page directory for target process
|
||||
static void copyArgvEnvToProcess(char *const argv[], char *const envp[])
|
||||
{
|
||||
char** destination = (char**)USER_ARGV_ENV_LOC;
|
||||
int destinationIndex = 0;
|
||||
|
||||
//Screen_PrintF("ARGVENV: destination:%x\n", destination);
|
||||
|
||||
int argvCount = getStringArrayItemCount(argv);
|
||||
int envpCount = getStringArrayItemCount(envp);
|
||||
|
||||
//Screen_PrintF("ARGVENV: argvCount:%d envpCount:%d\n", argvCount, envpCount);
|
||||
|
||||
char* stringTable = (char*)USER_ARGV_ENV_LOC + sizeof(char*) * (argvCount + envpCount + 2);
|
||||
|
||||
//Screen_PrintF("ARGVENV: stringTable:%x\n", stringTable);
|
||||
|
||||
for (int i = 0; i < argvCount; ++i)
|
||||
{
|
||||
strcpy(stringTable, argv[i]);
|
||||
|
||||
destination[destinationIndex] = stringTable;
|
||||
|
||||
stringTable += strlen(argv[i]) + 2;
|
||||
|
||||
destinationIndex++;
|
||||
}
|
||||
|
||||
destination[destinationIndex++] = NULL;
|
||||
|
||||
for (int i = 0; i < envpCount; ++i)
|
||||
{
|
||||
strcpy(stringTable, envp[i]);
|
||||
|
||||
destination[destinationIndex] = stringTable;
|
||||
|
||||
stringTable += strlen(envp[i]) + 2;
|
||||
|
||||
destinationIndex++;
|
||||
}
|
||||
|
||||
destination[destinationIndex++] = NULL;
|
||||
}
|
||||
|
||||
Process* createUserProcessFromElfData(const char* name, uint8* elfData, char *const argv[], char *const envp[], Process* parent, FileSystemNode* tty)
|
||||
{
|
||||
return createUserProcessEx(name, generateProcessId(), generateThreadId(), NULL, elfData, argv, envp, parent, tty);
|
||||
}
|
||||
|
||||
Process* createUserProcessEx(const char* name, uint32 processId, uint32 threadId, Function0 func, uint8* elfData, char *const argv[], char *const envp[], Process* parent, FileSystemNode* tty)
|
||||
{
|
||||
printkf("createUserProcessEx: %s %d %d\n", name, processId, threadId);
|
||||
if (0 == processId)
|
||||
{
|
||||
processId = generateProcessId();
|
||||
}
|
||||
|
||||
if (0 == threadId)
|
||||
{
|
||||
threadId = generateThreadId();
|
||||
}
|
||||
|
||||
Process* process = (Process*)kmalloc(sizeof(Process));
|
||||
memset((uint8*)process, 0, sizeof(Process));
|
||||
strcpy(process->name, name);
|
||||
process->pid = processId;
|
||||
process->pd = createPd();//our page directories are identity mapped so this is also a physical address.
|
||||
process->workingDirectory = getFileSystemRootNode();
|
||||
|
||||
Thread* thread = (Thread*)kmalloc(sizeof(Thread));
|
||||
memset((uint8*)thread, 0, sizeof(Thread));
|
||||
|
||||
thread->owner = process;
|
||||
|
||||
thread->threadId = threadId;
|
||||
|
||||
thread->userMode = 1;
|
||||
|
||||
thread->state = TS_RUN;
|
||||
|
||||
thread->messageQueue = FifoBuffer_create(sizeof(SosoMessage) * MESSAGE_QUEUE_SIZE);
|
||||
Spinlock_Init(&(thread->messageQueueLock));
|
||||
|
||||
thread->regs.cr3 = (uint32) process->pd;
|
||||
|
||||
//Since stack grows backwards, we must allocate previous page. So lets substract a small amount.
|
||||
uint32 stackp = USER_STACK-4;
|
||||
|
||||
if (parent)
|
||||
{
|
||||
process->parent = parent;
|
||||
|
||||
process->workingDirectory = parent->workingDirectory;
|
||||
|
||||
process->tty = parent->tty;
|
||||
}
|
||||
|
||||
if (tty)
|
||||
{
|
||||
process->tty = tty;
|
||||
}
|
||||
|
||||
char** newArgv = cloneStringArray(argv);
|
||||
char** newEnvp = cloneStringArray(envp);
|
||||
|
||||
//Change memory view (page directory)
|
||||
asm("mov %0, %%eax; mov %%eax, %%cr3"::"m"(process->pd));
|
||||
|
||||
initializeProcessHeap(process);
|
||||
|
||||
initializeProcessMmap(process);
|
||||
|
||||
copyArgvEnvToProcess(newArgv, newEnvp);
|
||||
|
||||
destroyStringArray(newArgv);
|
||||
destroyStringArray(newEnvp);
|
||||
|
||||
uint32 selector = 0x23;
|
||||
|
||||
thread->regs.ss = selector;
|
||||
thread->regs.eflags = 0x0;
|
||||
thread->regs.cs = 0x1B;
|
||||
thread->regs.eip = (uint32)func;
|
||||
thread->regs.ds = selector;
|
||||
thread->regs.es = selector;
|
||||
thread->regs.fs = selector;
|
||||
thread->regs.gs = selector;
|
||||
|
||||
thread->regs.esp = stackp;
|
||||
|
||||
char* p_addr = getPageFrame4M();
|
||||
char* v_addr = (char *) (USER_STACK - PAGESIZE_4M);
|
||||
addPageToPd(process->pd, v_addr, p_addr, PG_USER);
|
||||
|
||||
thread->kstack.ss0 = 0x10;
|
||||
uint8* stack = (uint8*)kmalloc(KERN_STACK_SIZE);
|
||||
thread->kstack.esp0 = (uint32)(stack + KERN_STACK_SIZE - 4);
|
||||
thread->kstack.stackStart = (uint32)stack;
|
||||
|
||||
Thread* p = gCurrentThread;
|
||||
|
||||
while (p->next != NULL)
|
||||
{
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
p->next = thread;
|
||||
|
||||
if (elfData)
|
||||
{
|
||||
printkf("about to load ELF data\n");
|
||||
uint32 startLocation = loadElf((char*)elfData);
|
||||
|
||||
if (startLocation > 0)
|
||||
{
|
||||
thread->regs.eip = startLocation;
|
||||
}
|
||||
}
|
||||
|
||||
//Restore memory view (page directory)
|
||||
asm("mov %0, %%eax ;mov %%eax, %%cr3":: "m"(gCurrentThread->regs.cr3));
|
||||
|
||||
open_fs_forProcess(thread, process->tty, 0);//0: standard input
|
||||
open_fs_forProcess(thread, process->tty, 0);//1: standard output
|
||||
open_fs_forProcess(thread, process->tty, 0);//2: standard error
|
||||
|
||||
printkf("running process %d\n", process->pid);
|
||||
return process;
|
||||
}
|
||||
|
||||
//This function should be called in interrupts disabled state
|
||||
void destroyThread(Thread* thread)
|
||||
{
|
||||
Spinlock_Lock(&(thread->messageQueueLock));
|
||||
|
||||
//TODO: signal the process somehow
|
||||
Thread* previousThread = getPreviousThread(thread);
|
||||
if (NULL != previousThread)
|
||||
{
|
||||
previousThread->next = thread->next;
|
||||
|
||||
kfree((void*)thread->kstack.stackStart);
|
||||
|
||||
FifoBuffer_destroy(thread->messageQueue);
|
||||
|
||||
Debug_PrintF("destroying thread %d\n", thread->threadId);
|
||||
|
||||
kfree(thread);
|
||||
|
||||
if (thread == gCurrentThread)
|
||||
{
|
||||
gCurrentThread = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printkf("Could not find previous thread for thread %d\n", thread->threadId);
|
||||
PANIC("This should not be happened!\n");
|
||||
}
|
||||
}
|
||||
|
||||
//This function should be called in interrupts disabled state
|
||||
void destroyProcess(Process* process)
|
||||
{
|
||||
Thread* thread = gFirstThread;
|
||||
Thread* previous = NULL;
|
||||
while (thread)
|
||||
{
|
||||
if (process == thread->owner)
|
||||
{
|
||||
if (NULL != previous)
|
||||
{
|
||||
previous->next = thread->next;
|
||||
|
||||
kfree((void*)thread->kstack.stackStart);
|
||||
|
||||
Spinlock_Lock(&(thread->messageQueueLock));
|
||||
FifoBuffer_destroy(thread->messageQueue);
|
||||
|
||||
Debug_PrintF("destroying thread id:%d (owner process %d)\n", thread->threadId, process->pid);
|
||||
|
||||
kfree(thread);
|
||||
|
||||
if (thread == gCurrentThread)
|
||||
{
|
||||
gCurrentThread = NULL;
|
||||
}
|
||||
|
||||
thread = previous->next;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
previous = thread;
|
||||
thread = thread->next;
|
||||
}
|
||||
|
||||
//Cleanup opened files
|
||||
for (int i = 0; i < MAX_OPENED_FILES; ++i)
|
||||
{
|
||||
if (process->fd[i] != NULL)
|
||||
{
|
||||
close_fs(process->fd[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (process->parent)
|
||||
{
|
||||
thread = gFirstThread;
|
||||
while (thread)
|
||||
{
|
||||
if (process->parent == thread->owner)
|
||||
{
|
||||
if (thread->state == TS_WAITCHILD)
|
||||
{
|
||||
thread->state = TS_RUN;
|
||||
}
|
||||
}
|
||||
|
||||
thread = thread->next;
|
||||
}
|
||||
}
|
||||
|
||||
Debug_PrintF("destroying process %d\n", process->pid);
|
||||
|
||||
destroyPd(process->pd);
|
||||
kfree(process);
|
||||
}
|
||||
|
||||
void threadStateToString(ThreadState state, uint8* buffer, uint32 bufferSize)
|
||||
{
|
||||
if (bufferSize < 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
buffer[0] = '\0';
|
||||
|
||||
if (bufferSize < 10)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case TS_RUN:
|
||||
strcpy((char*)buffer, "run");
|
||||
break;
|
||||
case TS_SLEEP:
|
||||
strcpy((char*)buffer, "sleep");
|
||||
break;
|
||||
case TS_SUSPEND:
|
||||
strcpy((char*)buffer, "suspend");
|
||||
break;
|
||||
case TS_WAITCHILD:
|
||||
strcpy((char*)buffer, "waitchild");
|
||||
break;
|
||||
case TS_WAITIO:
|
||||
strcpy((char*)buffer, "waitio");
|
||||
break;
|
||||
case TS_YIELD:
|
||||
strcpy((char*)buffer, "yield");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void waitForSchedule()
|
||||
{
|
||||
//Screen_PrintF("Waiting for a schedule()\n");
|
||||
|
||||
enableInterrupts();
|
||||
while (TRUE)
|
||||
{
|
||||
halt();
|
||||
}
|
||||
disableInterrupts();
|
||||
PANIC("waitForSchedule(): Should not be reached here!!!\n");
|
||||
}
|
||||
|
||||
void yield(uint32 count)
|
||||
{
|
||||
gCurrentThread->yield = count;
|
||||
gCurrentThread->state = TS_YIELD;
|
||||
enableInterrupts();
|
||||
while (gCurrentThread->yield > 0)
|
||||
{
|
||||
halt();
|
||||
}
|
||||
disableInterrupts();
|
||||
}
|
||||
|
||||
int32 getEmptyFd(Process* process)
|
||||
{
|
||||
int32 result = -1;
|
||||
|
||||
beginCriticalSection();
|
||||
|
||||
for (int i = 0; i < MAX_OPENED_FILES; ++i)
|
||||
{
|
||||
if (process->fd[i] == NULL)
|
||||
{
|
||||
result = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
endCriticalSection();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int32 addFileToProcess(Process* process, File* file)
|
||||
{
|
||||
int32 result = -1;
|
||||
|
||||
beginCriticalSection();
|
||||
|
||||
//Screen_PrintF("addFileToProcess: pid:%d\n", process->pid);
|
||||
|
||||
for (int i = 0; i < MAX_OPENED_FILES; ++i)
|
||||
{
|
||||
//Screen_PrintF("addFileToProcess: i:%d fd[%d]:%x\n", i, i, process->fd[i]);
|
||||
if (process->fd[i] == NULL)
|
||||
{
|
||||
result = i;
|
||||
file->fd = i;
|
||||
process->fd[i] = file;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
endCriticalSection();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int32 removeFileFromProcess(Process* process, File* file)
|
||||
{
|
||||
int32 result = -1;
|
||||
|
||||
beginCriticalSection();
|
||||
|
||||
for (int i = 0; i < MAX_OPENED_FILES; ++i)
|
||||
{
|
||||
if (process->fd[i] == file)
|
||||
{
|
||||
result = i;
|
||||
process->fd[i] = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
endCriticalSection();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Thread* getThreadById(uint32 threadId)
|
||||
{
|
||||
Thread* p = gFirstThread;
|
||||
|
||||
while (p != NULL)
|
||||
{
|
||||
if (p->threadId == threadId)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Thread* getPreviousThread(Thread* thread)
|
||||
{
|
||||
Thread* t = gFirstThread;
|
||||
|
||||
while (t->next != NULL)
|
||||
{
|
||||
if (t->next == thread)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
t = t->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Thread* getMainKernelThread()
|
||||
{
|
||||
return gFirstThread;
|
||||
}
|
||||
|
||||
Thread* getCurrentThread()
|
||||
{
|
||||
return gCurrentThread;
|
||||
}
|
||||
|
||||
BOOL isThreadValid(Thread* thread)
|
||||
{
|
||||
Thread* p = gFirstThread;
|
||||
|
||||
while (p != NULL)
|
||||
{
|
||||
if (p == thread)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL isProcessValid(Process* process)
|
||||
{
|
||||
Thread* p = gFirstThread;
|
||||
|
||||
while (p != NULL)
|
||||
{
|
||||
if (p->owner == process)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void switchToTask(Thread* current, int mode);
|
||||
|
||||
static void updateMetrics(Thread* thread)
|
||||
{
|
||||
uint32 seconds = getUptimeSeconds();
|
||||
|
||||
if (seconds > gLastUptimeSeconds)
|
||||
{
|
||||
gLastUptimeSeconds = seconds;
|
||||
|
||||
Thread* t = gFirstThread;
|
||||
|
||||
while (t != NULL)
|
||||
{
|
||||
t->contextSwitchCount = t->totalContextSwitchCount - t->totalContextSwitchCountPrevious;
|
||||
t->totalContextSwitchCountPrevious = t->totalContextSwitchCount;
|
||||
|
||||
t = t->next;
|
||||
}
|
||||
}
|
||||
|
||||
++gSystemContextSwitchCount;
|
||||
|
||||
++thread->totalContextSwitchCount;
|
||||
}
|
||||
|
||||
void schedule(TimerInt_Registers* registers)
|
||||
{
|
||||
Thread* current = gCurrentThread;
|
||||
|
||||
if (NULL != current)
|
||||
{
|
||||
if (current->next == NULL && current == gFirstThread)
|
||||
{
|
||||
//We are the only process, no need to schedule
|
||||
return;
|
||||
}
|
||||
|
||||
current->regs.eflags = registers->eflags;
|
||||
current->regs.cs = registers->cs;
|
||||
current->regs.eip = registers->eip;
|
||||
current->regs.eax = registers->eax;
|
||||
current->regs.ecx = registers->ecx;
|
||||
current->regs.edx = registers->edx;
|
||||
current->regs.ebx = registers->ebx;
|
||||
current->regs.ebp = registers->ebp;
|
||||
current->regs.esi = registers->esi;
|
||||
current->regs.edi = registers->edi;
|
||||
current->regs.ds = registers->ds;
|
||||
current->regs.es = registers->es;
|
||||
current->regs.fs = registers->fs;
|
||||
current->regs.gs = registers->gs;
|
||||
|
||||
if (current->regs.cs != 0x08)
|
||||
{
|
||||
//Debug_PrintF("schedule() - 2.1\n");
|
||||
current->regs.esp = registers->esp_if_privilege_change;
|
||||
current->regs.ss = registers->ss_if_privilege_change;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Debug_PrintF("schedule() - 2.2\n");
|
||||
current->regs.esp = registers->esp + 12;
|
||||
current->regs.ss = gTss.ss0;
|
||||
}
|
||||
|
||||
//Save the TSS from the old process
|
||||
current->kstack.ss0 = gTss.ss0;
|
||||
current->kstack.esp0 = gTss.esp0;
|
||||
|
||||
current = current->next;
|
||||
while (NULL != current)
|
||||
{
|
||||
if (current->state == TS_YIELD)
|
||||
{
|
||||
if (current->yield > 0)
|
||||
{
|
||||
--current->yield;
|
||||
}
|
||||
|
||||
if (current->yield == 0)
|
||||
{
|
||||
current->state = TS_RUN;
|
||||
}
|
||||
}
|
||||
|
||||
if (current->state == TS_SLEEP)
|
||||
{
|
||||
uint32 uptime = getUptimeMilliseconds();
|
||||
uint32 target = (uint32)current->state_privateData;
|
||||
|
||||
if (uptime >= target)
|
||||
{
|
||||
current->state = TS_RUN;
|
||||
current->state_privateData = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (current->state == TS_RUN)
|
||||
{
|
||||
break;
|
||||
}
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
if (current == NULL)
|
||||
{
|
||||
//reached last process returning to first
|
||||
current = gFirstThread;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//current is NULL. This means thread is destroyed, so start from the begining
|
||||
|
||||
current = gFirstThread;
|
||||
}
|
||||
|
||||
gCurrentThread = current;//Now gCurrentThread is the thread we are about to schedule to
|
||||
|
||||
/*
|
||||
if (gCurrentThread->threadId == 5)
|
||||
{
|
||||
Screen_PrintF("I am scheduling to %d and its EIP is %x\n", gCurrentThread->threadId, gCurrentThread->regs.eip);
|
||||
}
|
||||
*/
|
||||
|
||||
updateMetrics(current);
|
||||
|
||||
if (current->regs.cs != 0x08)
|
||||
{
|
||||
switchToTask(current, USERMODE);
|
||||
}
|
||||
else
|
||||
{
|
||||
switchToTask(current, KERNELMODE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//The mode indicates whether this process was in user mode or kernel mode
|
||||
//When it was previously interrupted by the scheduler.
|
||||
static void switchToTask(Thread* current, int mode)
|
||||
{
|
||||
uint32 kesp, eflags;
|
||||
uint16 kss, ss, cs;
|
||||
|
||||
//Set TSS values
|
||||
gTss.ss0 = current->kstack.ss0;
|
||||
gTss.esp0 = current->kstack.esp0;
|
||||
|
||||
ss = current->regs.ss;
|
||||
cs = current->regs.cs;
|
||||
eflags = (current->regs.eflags | 0x200) & 0xFFFFBFFF;
|
||||
|
||||
if (mode == USERMODE)
|
||||
{
|
||||
kss = current->kstack.ss0;
|
||||
kesp = current->kstack.esp0;
|
||||
}
|
||||
else
|
||||
{
|
||||
kss = current->regs.ss;
|
||||
kesp = current->regs.esp;
|
||||
}
|
||||
|
||||
//switchTask is in task.asm
|
||||
|
||||
asm(" mov %0, %%ss; \
|
||||
mov %1, %%esp; \
|
||||
cmpl %[KMODE], %[mode]; \
|
||||
je nextt; \
|
||||
push %2; \
|
||||
push %3; \
|
||||
nextt: \
|
||||
push %4; \
|
||||
push %5; \
|
||||
push %6; \
|
||||
push %7; \
|
||||
ljmp $0x08, $switchTask"
|
||||
:: \
|
||||
"m"(kss), \
|
||||
"m"(kesp), \
|
||||
"m"(ss), \
|
||||
"m"(current->regs.esp), \
|
||||
"m"(eflags), \
|
||||
"m"(cs), \
|
||||
"m"(current->regs.eip), \
|
||||
"m"(current), \
|
||||
[KMODE] "i"(KERNELMODE), \
|
||||
[mode] "g"(mode)
|
||||
);
|
||||
}
|
138
kernel.soso/process.h
Normal file
138
kernel.soso/process.h
Normal file
|
@ -0,0 +1,138 @@
|
|||
#ifndef PROCESS_H
|
||||
#define PROCESS_H
|
||||
|
||||
#define KERNELMODE 0
|
||||
#define USERMODE 1
|
||||
|
||||
#define MAX_OPENED_FILES 20
|
||||
|
||||
#include "common.h"
|
||||
#include "fs.h"
|
||||
#include "fifobuffer.h"
|
||||
#include "spinlock.h"
|
||||
|
||||
typedef enum ThreadState
|
||||
{
|
||||
TS_RUN,
|
||||
TS_WAITIO,
|
||||
TS_WAITCHILD,
|
||||
TS_SLEEP,
|
||||
TS_SUSPEND,
|
||||
TS_YIELD
|
||||
} ThreadState;
|
||||
|
||||
struct Process
|
||||
{
|
||||
char name[32];
|
||||
|
||||
uint32 pid;
|
||||
|
||||
|
||||
uint32 *pd;
|
||||
|
||||
uint32 b_exec;
|
||||
uint32 e_exec;
|
||||
uint32 b_bss;
|
||||
uint32 e_bss;
|
||||
|
||||
char *heapBegin;
|
||||
char *heapEnd;
|
||||
char *heapNextUnallocatedPageBegin;
|
||||
|
||||
uint8 mmappedVirtualMemory[RAM_AS_4M_PAGES / 8];
|
||||
|
||||
uint32 signal;
|
||||
void* sigfn[32];
|
||||
|
||||
FileSystemNode* tty;
|
||||
|
||||
FileSystemNode* workingDirectory;
|
||||
|
||||
//Thread* mainThread;
|
||||
|
||||
Process* parent;
|
||||
|
||||
// Save exit status of child process that most recently performed exit().
|
||||
int32 childExitStatusPresent; // boolean
|
||||
int32 childExitStatus;
|
||||
|
||||
File* fd[MAX_OPENED_FILES];
|
||||
|
||||
} __attribute__ ((packed));
|
||||
|
||||
typedef struct Process Process;
|
||||
|
||||
struct Thread
|
||||
{
|
||||
uint32 threadId;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 eax, ecx, edx, ebx;
|
||||
uint32 esp, ebp, esi, edi;
|
||||
uint32 eip, eflags;
|
||||
uint32 cs:16, ss:16, ds:16, es:16, fs:16, gs:16;
|
||||
uint32 cr3;
|
||||
} regs __attribute__ ((packed));
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 esp0;
|
||||
uint16 ss0;
|
||||
uint32 stackStart;
|
||||
} kstack __attribute__ ((packed));
|
||||
|
||||
|
||||
uint32 userMode;
|
||||
|
||||
ThreadState state;
|
||||
|
||||
Process* owner;
|
||||
|
||||
uint32 yield;
|
||||
|
||||
uint32 contextSwitchCount;
|
||||
uint32 totalContextSwitchCount;
|
||||
uint32 totalContextSwitchCountPrevious;
|
||||
|
||||
void* state_privateData;
|
||||
|
||||
FifoBuffer* messageQueue;
|
||||
Spinlock messageQueueLock;
|
||||
|
||||
struct Thread* next;
|
||||
|
||||
};
|
||||
|
||||
typedef struct Thread Thread;
|
||||
|
||||
typedef struct TimerInt_Registers
|
||||
{
|
||||
uint32 gs, fs, es, ds;
|
||||
uint32 edi, esi, ebp, esp, ebx, edx, ecx, eax; //pushed by pushad
|
||||
uint32 eip, cs, eflags, esp_if_privilege_change, ss_if_privilege_change; //pushed by the CPU
|
||||
} TimerInt_Registers;
|
||||
|
||||
typedef void (*Function0)();
|
||||
|
||||
void initializeTasking();
|
||||
Process* createUserProcessFromElfData(const char* name, uint8* elfData, char *const argv[], char *const envp[], Process* parent, FileSystemNode* tty);
|
||||
Process* createUserProcessEx(const char* name, uint32 processId, uint32 threadId, Function0 func, uint8* elfData, char *const argv[], char *const envp[], Process* parent, FileSystemNode* tty);
|
||||
void destroyThread(Thread* thread);
|
||||
void destroyProcess(Process* process);
|
||||
void threadStateToString(ThreadState state, uint8* buffer, uint32 bufferSize);
|
||||
void waitForSchedule();
|
||||
void yield(uint32 count);
|
||||
int32 getEmptyFd(Process* process);
|
||||
int32 addFileToProcess(Process* process, File* file);
|
||||
int32 removeFileFromProcess(Process* process, File* file);
|
||||
Thread* getThreadById(uint32 threadId);
|
||||
Thread* getPreviousThread(Thread* thread);
|
||||
Thread* getMainKernelThread();
|
||||
Thread* getCurrentThread();
|
||||
void schedule(TimerInt_Registers* registers);
|
||||
BOOL isThreadValid(Thread* thread);
|
||||
BOOL isProcessValid(Process* process);
|
||||
uint32 getSystemContextSwitchCount();
|
||||
|
||||
#endif // PROCESS_H
|
120
kernel.soso/ramdisk.c
Normal file
120
kernel.soso/ramdisk.c
Normal file
|
@ -0,0 +1,120 @@
|
|||
#include "ramdisk.h"
|
||||
#include "alloc.h"
|
||||
#include "fs.h"
|
||||
#include "devfs.h"
|
||||
|
||||
typedef struct Ramdisk
|
||||
{
|
||||
uint8* buffer;
|
||||
uint32 size;
|
||||
} Ramdisk;
|
||||
|
||||
#define RAMDISK_BLOCKSIZE 512
|
||||
|
||||
static BOOL open(File *file, uint32 flags);
|
||||
static void close(File *file);
|
||||
static int32 readBlock(FileSystemNode* node, uint32 blockNumber, uint32 count, uint8* buffer);
|
||||
static int32 writeBlock(FileSystemNode* node, uint32 blockNumber, uint32 count, uint8* buffer);
|
||||
static int32 ioctl(File *node, int32 request, void * argp);
|
||||
|
||||
BOOL createRamdisk(const char* devName, uint32 size)
|
||||
{
|
||||
Ramdisk* ramdisk = kmalloc(sizeof(Ramdisk));
|
||||
ramdisk->size = size;
|
||||
ramdisk->buffer = kmalloc(size);
|
||||
|
||||
Device device;
|
||||
memset((uint8*)&device, 0, sizeof(device));
|
||||
strcpy(device.name, devName);
|
||||
device.deviceType = FT_BlockDevice;
|
||||
device.open = open;
|
||||
device.close = close;
|
||||
device.readBlock = readBlock;
|
||||
device.writeBlock = writeBlock;
|
||||
device.ioctl = ioctl;
|
||||
device.privateData = ramdisk;
|
||||
|
||||
if (registerDevice(&device))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
kfree(ramdisk->buffer);
|
||||
kfree(ramdisk);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL open(File *file, uint32 flags)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void close(File *file)
|
||||
{
|
||||
}
|
||||
|
||||
static int32 readBlock(FileSystemNode* node, uint32 blockNumber, uint32 count, uint8* buffer)
|
||||
{
|
||||
Ramdisk* ramdisk = (Ramdisk*)node->privateNodeData;
|
||||
|
||||
uint32 location = blockNumber * RAMDISK_BLOCKSIZE;
|
||||
uint32 size = count * RAMDISK_BLOCKSIZE;
|
||||
|
||||
if (location + size > ramdisk->size)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
beginCriticalSection();
|
||||
|
||||
memcpy(buffer, ramdisk->buffer + location, size);
|
||||
|
||||
endCriticalSection();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32 writeBlock(FileSystemNode* node, uint32 blockNumber, uint32 count, uint8* buffer)
|
||||
{
|
||||
Ramdisk* ramdisk = (Ramdisk*)node->privateNodeData;
|
||||
|
||||
uint32 location = blockNumber * RAMDISK_BLOCKSIZE;
|
||||
uint32 size = count * RAMDISK_BLOCKSIZE;
|
||||
|
||||
if (location + size > ramdisk->size)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
beginCriticalSection();
|
||||
|
||||
memcpy(ramdisk->buffer + location, buffer, size);
|
||||
|
||||
endCriticalSection();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32 ioctl(File *node, int32 request, void * argp)
|
||||
{
|
||||
Ramdisk* ramdisk = (Ramdisk*)node->node->privateNodeData;
|
||||
|
||||
uint32* result = (uint32*)argp;
|
||||
|
||||
switch (request)
|
||||
{
|
||||
case IC_GetSectorCount:
|
||||
*result = ramdisk->size / RAMDISK_BLOCKSIZE;
|
||||
return 0;
|
||||
break;
|
||||
case IC_GetSectorSizeInBytes:
|
||||
*result = RAMDISK_BLOCKSIZE;
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
8
kernel.soso/ramdisk.h
Normal file
8
kernel.soso/ramdisk.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#ifndef RAMDISK_H
|
||||
#define RAMDISK_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
BOOL createRamdisk(const char* devName, uint32 size);
|
||||
|
||||
#endif // RAMDISK_H
|
62
kernel.soso/random.c
Normal file
62
kernel.soso/random.c
Normal file
|
@ -0,0 +1,62 @@
|
|||
#include "random.h"
|
||||
#include "devfs.h"
|
||||
#include "device.h"
|
||||
#include "common.h"
|
||||
#include "process.h"
|
||||
#include "sleep.h"
|
||||
|
||||
static BOOL random_open(File *file, uint32 flags);
|
||||
static int32 random_read(File *file, uint32 size, uint8 *buffer);
|
||||
|
||||
void initializeRandom()
|
||||
{
|
||||
Device device;
|
||||
memset((uint8*)&device, 0, sizeof(Device));
|
||||
strcpy(device.name, "random");
|
||||
device.deviceType = FT_CharacterDevice;
|
||||
device.open = random_open;
|
||||
device.read = random_read;
|
||||
|
||||
registerDevice(&device);
|
||||
}
|
||||
|
||||
static BOOL random_open(File *file, uint32 flags)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int32 random_read(File *file, uint32 size, uint8 *buffer)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Screen_PrintF("random_read: calling sleep\n");
|
||||
|
||||
//sleep(10000);
|
||||
|
||||
//Screen_PrintF("random_read: returned from sleep\n");
|
||||
|
||||
uint32 number = rand();
|
||||
|
||||
if (size == 1)
|
||||
{
|
||||
*buffer = (uint8)number;
|
||||
return 1;
|
||||
}
|
||||
else if (size == 2 || size == 3)
|
||||
{
|
||||
*((uint16*)buffer) = (uint16)number;
|
||||
return 2;
|
||||
}
|
||||
else if (size >= 4)
|
||||
{
|
||||
//Screen_PrintF("random_read: buffer is %x, writing %x to buffer\n", buffer, number);
|
||||
|
||||
*((uint32*)buffer) = number;
|
||||
return 4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
6
kernel.soso/random.h
Normal file
6
kernel.soso/random.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef RANDOM_H
|
||||
#define RANDOM_H
|
||||
|
||||
void initializeRandom();
|
||||
|
||||
#endif // RANDOM_H
|
111
kernel.soso/rootfs.c
Normal file
111
kernel.soso/rootfs.c
Normal file
|
@ -0,0 +1,111 @@
|
|||
#include "rootfs.h"
|
||||
#include "alloc.h"
|
||||
|
||||
static BOOL rootfs_open(File *node, uint32 flags);
|
||||
static void rootfs_close(File *file);
|
||||
static FileSystemNode *rootfs_finddir(FileSystemNode *node, char *name);
|
||||
static struct FileSystemDirent *rootfs_readdir(FileSystemNode *node, uint32 index);
|
||||
static BOOL rootfs_mkdir(FileSystemNode *node, const char *name, uint32 flags);
|
||||
|
||||
FileSystemNode* initializeRootFS()
|
||||
{
|
||||
FileSystemNode* root = (FileSystemNode*)kmalloc(sizeof(FileSystemNode));
|
||||
memset((uint8*)root, 0, sizeof(FileSystemNode));
|
||||
root->nodeType = FT_Directory;
|
||||
root->open = rootfs_open;
|
||||
root->close = rootfs_close;
|
||||
root->readdir = rootfs_readdir;
|
||||
root->finddir = rootfs_finddir;
|
||||
root->mkdir = rootfs_mkdir;
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
static FileSystemDirent gDirent;
|
||||
|
||||
static BOOL rootfs_open(File *node, uint32 flags)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void rootfs_close(File *file)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static struct FileSystemDirent *rootfs_readdir(FileSystemNode *node, uint32 index)
|
||||
{
|
||||
FileSystemNode *n = node->firstChild;
|
||||
uint32 i = 0;
|
||||
while (NULL != n)
|
||||
{
|
||||
if (index == i)
|
||||
{
|
||||
gDirent.fileType = n->nodeType;
|
||||
gDirent.inode = n->inode;
|
||||
strcpy(gDirent.name, n->name);
|
||||
|
||||
return &gDirent;
|
||||
}
|
||||
n = n->nextSibling;
|
||||
++i;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static FileSystemNode *rootfs_finddir(FileSystemNode *node, char *name)
|
||||
{
|
||||
FileSystemNode *n = node->firstChild;
|
||||
while (NULL != n)
|
||||
{
|
||||
if (strcmp(name, n->name) == 0)
|
||||
{
|
||||
return n;
|
||||
}
|
||||
n = n->nextSibling;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static BOOL rootfs_mkdir(FileSystemNode *node, const char *name, uint32 flags)
|
||||
{
|
||||
FileSystemNode *n = node->firstChild;
|
||||
while (NULL != n)
|
||||
{
|
||||
if (strcmp(name, n->name) == 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
n = n->nextSibling;
|
||||
}
|
||||
|
||||
FileSystemNode* newNode = (FileSystemNode*)kmalloc(sizeof(FileSystemNode));
|
||||
memset((uint8*)newNode, 0, sizeof(FileSystemNode));
|
||||
strcpy(newNode->name, name);
|
||||
newNode->nodeType = FT_Directory;
|
||||
newNode->open = rootfs_open;
|
||||
newNode->close = rootfs_close;
|
||||
newNode->readdir = rootfs_readdir;
|
||||
newNode->finddir = rootfs_finddir;
|
||||
newNode->mkdir = rootfs_mkdir;
|
||||
newNode->parent = node;
|
||||
|
||||
if (node->firstChild == NULL)
|
||||
{
|
||||
node->firstChild = newNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
FileSystemNode *n = node->firstChild;
|
||||
while (NULL != n->nextSibling)
|
||||
{
|
||||
n = n->nextSibling;
|
||||
}
|
||||
n->nextSibling = newNode;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
8
kernel.soso/rootfs.h
Normal file
8
kernel.soso/rootfs.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#ifndef ROOTFS_H
|
||||
#define ROOTFS_H
|
||||
|
||||
#include "fs.h"
|
||||
|
||||
FileSystemNode* initializeRootFS();
|
||||
|
||||
#endif // ROOTFS_H
|
99
kernel.soso/screen.c
Normal file
99
kernel.soso/screen.c
Normal file
|
@ -0,0 +1,99 @@
|
|||
#include "screen.h"
|
||||
#include "common.h"
|
||||
#include "serial.h"
|
||||
|
||||
#define SCREEN_LINE_COUNT 25
|
||||
#define SCREEN_COLUMN_COUNT 80
|
||||
|
||||
static unsigned char *videoStart = (unsigned char*)0xB8000;
|
||||
|
||||
static uint16 gCurrentLine = 0;
|
||||
static uint16 gCurrentColumn = 0;
|
||||
static uint8 gColor = 0x0A;
|
||||
|
||||
void Screen_FlushFromTty(Tty* tty)
|
||||
{
|
||||
memcpy(videoStart, tty->buffer, SCREEN_LINE_COUNT * SCREEN_COLUMN_COUNT * 2);
|
||||
|
||||
Screen_MoveCursor(tty->currentLine, tty->currentColumn);
|
||||
}
|
||||
|
||||
void Screen_Print(int row, int column, const char* text)
|
||||
{
|
||||
unsigned char * video = videoStart;
|
||||
|
||||
video += (row * SCREEN_COLUMN_COUNT + column) * 2;
|
||||
while(*text != 0)
|
||||
{
|
||||
*video++ = *text++;
|
||||
*video++ = gColor;
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_SetActiveColor(uint8 color)
|
||||
{
|
||||
gColor = color;
|
||||
}
|
||||
|
||||
void Screen_ApplyColor(uint8 color)
|
||||
{
|
||||
gColor = color;
|
||||
|
||||
unsigned char * video = videoStart;
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < SCREEN_LINE_COUNT * SCREEN_COLUMN_COUNT; ++i)
|
||||
{
|
||||
video++;
|
||||
*video++ = gColor;
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_Clear()
|
||||
{
|
||||
unsigned char * video = videoStart;
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < SCREEN_LINE_COUNT * SCREEN_COLUMN_COUNT; ++i)
|
||||
{
|
||||
*video++ = 0;
|
||||
*video++ = gColor;
|
||||
}
|
||||
|
||||
gCurrentLine = 0;
|
||||
gCurrentColumn = 0;
|
||||
}
|
||||
|
||||
void Screen_MoveCursor(uint16 line, uint16 column)
|
||||
{
|
||||
// The screen is 80 characters wide...
|
||||
uint16 cursorLocation = line * SCREEN_COLUMN_COUNT + column;
|
||||
outb(0x3D4, 14); // Tell the VGA board we are setting the high cursor byte.
|
||||
outb(0x3D5, cursorLocation >> 8); // Send the high cursor byte.
|
||||
outb(0x3D4, 15); // Tell the VGA board we are setting the low cursor byte.
|
||||
outb(0x3D5, cursorLocation); // Send the low cursor byte.
|
||||
|
||||
gCurrentColumn = column;
|
||||
gCurrentLine = line;
|
||||
}
|
||||
|
||||
void Screen_SetCursorVisible(BOOL visible)
|
||||
{
|
||||
uint8 cursor = inb(0x3d5);
|
||||
|
||||
if (visible)
|
||||
{
|
||||
cursor &= ~0x20;//5th bit cleared when cursor visible
|
||||
}
|
||||
else
|
||||
{
|
||||
cursor |= 0x20;//5th bit set when cursor invisible
|
||||
}
|
||||
outb(0x3D5, cursor);
|
||||
}
|
||||
|
||||
void Screen_GetCursor(uint16* line, uint16* column)
|
||||
{
|
||||
*line = gCurrentLine;
|
||||
*column = gCurrentColumn;
|
||||
}
|
16
kernel.soso/screen.h
Normal file
16
kernel.soso/screen.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef SCREEN_H
|
||||
#define SCREEN_H
|
||||
|
||||
#include "common.h"
|
||||
#include "tty.h"
|
||||
|
||||
void Screen_FlushFromTty(Tty* tty);
|
||||
void Screen_Print(int row, int column, const char* text);
|
||||
void Screen_SetActiveColor(uint8 color);
|
||||
void Screen_ApplyColor(uint8 color);
|
||||
void Screen_Clear();
|
||||
void Screen_SetCursorVisible(BOOL visible);
|
||||
void Screen_MoveCursor(uint16 line, uint16 column);
|
||||
void Screen_GetCursor(uint16* line, uint16* column);
|
||||
|
||||
#endif //SCREEN_H
|
97
kernel.soso/serial.c
Normal file
97
kernel.soso/serial.c
Normal file
|
@ -0,0 +1,97 @@
|
|||
#include "common.h"
|
||||
#include "serial.h"
|
||||
|
||||
#define PORT 0x3f8 //COM1
|
||||
|
||||
void initializeSerial()
|
||||
{
|
||||
outb(PORT + 1, 0x00); // Disable all interrupts
|
||||
outb(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
|
||||
outb(PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud
|
||||
outb(PORT + 1, 0x00); // (hi byte)
|
||||
outb(PORT + 3, 0x03); // 8 bits, no parity, one stop bit
|
||||
outb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
|
||||
outb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
|
||||
}
|
||||
|
||||
int serialReceived()
|
||||
{
|
||||
return inb(PORT + 5) & 1;
|
||||
}
|
||||
|
||||
char readSerial()
|
||||
{
|
||||
while (serialReceived() == 0);
|
||||
|
||||
return inb(PORT);
|
||||
}
|
||||
|
||||
int isTransmitEmpty()
|
||||
{
|
||||
return inb(PORT + 5) & 0x20;
|
||||
}
|
||||
|
||||
void writeSerial(char a)
|
||||
{
|
||||
while (isTransmitEmpty() == 0);
|
||||
|
||||
outb(PORT,a);
|
||||
}
|
||||
|
||||
void Serial_PrintF(const char *format, ...)
|
||||
{
|
||||
char **arg = (char **) &format;
|
||||
char c;
|
||||
char buf[20];
|
||||
|
||||
//arg++;
|
||||
__builtin_va_list vl;
|
||||
__builtin_va_start(vl, format);
|
||||
|
||||
while ((c = *format++) != 0)
|
||||
{
|
||||
if (c != '%')
|
||||
writeSerial(c);
|
||||
else
|
||||
{
|
||||
char *p;
|
||||
|
||||
c = *format++;
|
||||
switch (c)
|
||||
{
|
||||
case 'x':
|
||||
buf[0] = '0';
|
||||
buf[1] = 'x';
|
||||
//itoa (buf + 2, c, *((int *) arg++));
|
||||
itoa (buf + 2, c, __builtin_va_arg(vl, int));
|
||||
p = buf;
|
||||
goto string;
|
||||
break;
|
||||
case 'd':
|
||||
case 'u':
|
||||
//itoa (buf, c, *((int *) arg++));
|
||||
itoa (buf, c, __builtin_va_arg(vl, int));
|
||||
p = buf;
|
||||
goto string;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
//p = *arg++;
|
||||
p = __builtin_va_arg(vl, char*);
|
||||
if (! p)
|
||||
p = "(null)";
|
||||
|
||||
string:
|
||||
while (*p)
|
||||
writeSerial(*p++);
|
||||
break;
|
||||
|
||||
default:
|
||||
//writeSerial(*((int *) arg++));
|
||||
writeSerial(__builtin_va_arg(vl, int));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
__builtin_va_end(vl);
|
||||
}
|
8
kernel.soso/serial.h
Normal file
8
kernel.soso/serial.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#ifndef SERIAL_H
|
||||
#define SERIAL_H
|
||||
|
||||
void initializeSerial();
|
||||
void writeSerial(char a);
|
||||
void Serial_PrintF(const char *format, ...);
|
||||
|
||||
#endif // SERIAL_H
|
252
kernel.soso/sharedmemory.c
Normal file
252
kernel.soso/sharedmemory.c
Normal file
|
@ -0,0 +1,252 @@
|
|||
#include "fs.h"
|
||||
#include "common.h"
|
||||
#include "list.h"
|
||||
#include "alloc.h"
|
||||
#include "spinlock.h"
|
||||
#include "vmm.h"
|
||||
#include "sharedmemory.h"
|
||||
|
||||
static List* gShmList = NULL;
|
||||
static Spinlock gShmListLock;
|
||||
|
||||
static FileSystemNode* gShmRoot = NULL;
|
||||
|
||||
static FileSystemDirent gDirent;
|
||||
|
||||
static BOOL sharedmemorydir_open(File *file, uint32 flags);
|
||||
static FileSystemDirent *sharedmemorydir_readdir(FileSystemNode *node, uint32 index);
|
||||
static FileSystemNode *sharedmemorydir_finddir(FileSystemNode *node, char *name);
|
||||
|
||||
typedef struct SharedMemory
|
||||
{
|
||||
FileSystemNode* node;
|
||||
List* physicalAddressList;
|
||||
Spinlock physicalAddressListLock;
|
||||
//TODO: permissions
|
||||
} SharedMemory;
|
||||
|
||||
void initializeSharedMemory()
|
||||
{
|
||||
Spinlock_Init(&gShmListLock);
|
||||
|
||||
gShmList = List_Create();
|
||||
|
||||
gShmRoot = getFileSystemNode("/system/shm");
|
||||
|
||||
if (NULL == gShmRoot)
|
||||
{
|
||||
WARNING("/system/shm not found!!");
|
||||
}
|
||||
else
|
||||
{
|
||||
gShmRoot->open = sharedmemorydir_open;
|
||||
gShmRoot->finddir = sharedmemorydir_finddir;
|
||||
gShmRoot->readdir = sharedmemorydir_readdir;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL sharedmemorydir_open(File *file, uint32 flags)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static FileSystemDirent *sharedmemorydir_readdir(FileSystemNode *node, uint32 index)
|
||||
{
|
||||
FileSystemDirent* result = NULL;
|
||||
|
||||
int counter = 0;
|
||||
|
||||
Spinlock_Lock(&gShmListLock);
|
||||
|
||||
List_Foreach (n, gShmList)
|
||||
{
|
||||
SharedMemory* p = (SharedMemory*)n->data;
|
||||
|
||||
if (counter == index)
|
||||
{
|
||||
strcpy(gDirent.name, p->node->name);
|
||||
gDirent.fileType = p->node->nodeType;
|
||||
|
||||
result = &gDirent;
|
||||
|
||||
break;
|
||||
}
|
||||
++counter;
|
||||
}
|
||||
|
||||
Spinlock_Unlock(&gShmListLock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static FileSystemNode *sharedmemorydir_finddir(FileSystemNode *node, char *name)
|
||||
{
|
||||
FileSystemNode* result = NULL;
|
||||
|
||||
Spinlock_Lock(&gShmListLock);
|
||||
|
||||
List_Foreach (n, gShmList)
|
||||
{
|
||||
SharedMemory* p = (SharedMemory*)n->data;
|
||||
|
||||
if (strcmp(name, p->node->name) == 0)
|
||||
{
|
||||
result = p->node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Spinlock_Unlock(&gShmListLock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static BOOL sharedmemory_open(File *file, uint32 flags)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void sharedmemory_unlink(File *file)
|
||||
{
|
||||
destroySharedMemory(file->node->name);
|
||||
}
|
||||
|
||||
static int32 sharedmemory_ftruncate(File *file, int32 length)
|
||||
{
|
||||
if (length <= 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
SharedMemory* sharedMem = (SharedMemory*)file->node->privateNodeData;
|
||||
|
||||
if (0 != file->node->length)
|
||||
{
|
||||
//already set
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pageCount = (length / PAGESIZE_4M) + 1;
|
||||
|
||||
Spinlock_Lock(&sharedMem->physicalAddressListLock);
|
||||
|
||||
for (int i = 0; i < pageCount; ++i)
|
||||
{
|
||||
char* pAddress = getPageFrame4M();
|
||||
|
||||
List_Append(sharedMem->physicalAddressList, pAddress);
|
||||
}
|
||||
|
||||
file->node->length = length;
|
||||
|
||||
Spinlock_Unlock(&sharedMem->physicalAddressListLock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void* sharedmemory_mmap(File* file, uint32 size, uint32 offset, uint32 flags)
|
||||
{
|
||||
void* result = NULL;
|
||||
|
||||
SharedMemory* sharedMem = (SharedMemory*)file->node->privateNodeData;
|
||||
|
||||
Spinlock_Lock(&sharedMem->physicalAddressListLock);
|
||||
|
||||
if (List_GetCount(sharedMem->physicalAddressList) > 0)
|
||||
{
|
||||
result = mapMemory(file->thread->owner, size, 0, sharedMem->physicalAddressList);
|
||||
}
|
||||
|
||||
Spinlock_Unlock(&sharedMem->physicalAddressListLock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
FileSystemNode* getSharedMemoryNode(const char* name)
|
||||
{
|
||||
FileSystemNode* result = NULL;
|
||||
|
||||
Spinlock_Lock(&gShmListLock);
|
||||
|
||||
List_Foreach (n, gShmList)
|
||||
{
|
||||
SharedMemory* p = (SharedMemory*)n->data;
|
||||
|
||||
if (strcmp(name, p->node->name) == 0)
|
||||
{
|
||||
result = p->node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Spinlock_Unlock(&gShmListLock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
FileSystemNode* createSharedMemory(const char* name)
|
||||
{
|
||||
if (getSharedMemoryNode(name) != NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SharedMemory* sharedMem = (SharedMemory*)kmalloc(sizeof(SharedMemory));
|
||||
memset((uint8*)sharedMem, 0, sizeof(SharedMemory));
|
||||
|
||||
FileSystemNode* node = (FileSystemNode*)kmalloc(sizeof(FileSystemNode));
|
||||
memset((uint8*)node, 0, sizeof(FileSystemNode));
|
||||
|
||||
strcpy(node->name, name);
|
||||
node->nodeType = FT_CharacterDevice;
|
||||
node->open = sharedmemory_open;
|
||||
//TODO: node->shm_unlink = sharedmemory_unlink;
|
||||
node->ftruncate = sharedmemory_ftruncate;
|
||||
node->mmap = sharedmemory_mmap;
|
||||
node->privateNodeData = sharedMem;
|
||||
|
||||
sharedMem->node = node;
|
||||
sharedMem->physicalAddressList = List_Create();
|
||||
Spinlock_Init(&sharedMem->physicalAddressListLock);
|
||||
|
||||
Spinlock_Lock(&gShmListLock);
|
||||
List_Append(gShmList, sharedMem);
|
||||
Spinlock_Unlock(&gShmListLock);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void destroySharedMemory(const char* name)
|
||||
{
|
||||
SharedMemory* sharedMem = NULL;
|
||||
|
||||
Spinlock_Lock(&gShmListLock);
|
||||
|
||||
List_Foreach (n, gShmList)
|
||||
{
|
||||
SharedMemory* p = (SharedMemory*)n->data;
|
||||
|
||||
if (strcmp(name, p->node->name) == 0)
|
||||
{
|
||||
sharedMem = (SharedMemory*)p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sharedMem)
|
||||
{
|
||||
Spinlock_Lock(&sharedMem->physicalAddressListLock);
|
||||
|
||||
kfree(sharedMem->node);
|
||||
|
||||
List_Destroy(sharedMem->physicalAddressList);
|
||||
|
||||
List_RemoveFirstOccurrence(gShmList, sharedMem);
|
||||
|
||||
Spinlock_Unlock(&sharedMem->physicalAddressListLock);
|
||||
|
||||
kfree(sharedMem);
|
||||
}
|
||||
|
||||
Spinlock_Unlock(&gShmListLock);
|
||||
}
|
12
kernel.soso/sharedmemory.h
Normal file
12
kernel.soso/sharedmemory.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef SHAREDMEMORY_H
|
||||
#define SHAREDMEMORY_H
|
||||
|
||||
#include "common.h"
|
||||
#include "fs.h"
|
||||
|
||||
void initializeSharedMemory();
|
||||
FileSystemNode* createSharedMemory(const char* name);
|
||||
void destroySharedMemory(const char* name);
|
||||
FileSystemNode* getSharedMemoryNode(const char* name);
|
||||
|
||||
#endif // SHAREDMEMORY_H
|
17
kernel.soso/sleep.c
Normal file
17
kernel.soso/sleep.c
Normal file
|
@ -0,0 +1,17 @@
|
|||
#include "sleep.h"
|
||||
#include "timer.h"
|
||||
|
||||
void sleepMilliseconds(Thread* thread, uint32 ms)
|
||||
{
|
||||
uint32 uptime = getUptimeMilliseconds();
|
||||
|
||||
//target uptime to wakeup
|
||||
uint32 target = uptime + ms;
|
||||
|
||||
thread->state = TS_SLEEP;
|
||||
thread->state_privateData = (void*)target;
|
||||
|
||||
enableInterrupts();
|
||||
|
||||
halt();
|
||||
}
|
9
kernel.soso/sleep.h
Normal file
9
kernel.soso/sleep.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef SLEEP_H
|
||||
#define SLEEP_H
|
||||
|
||||
#include "common.h"
|
||||
#include "process.h"
|
||||
|
||||
void sleepMilliseconds(Thread* thread, uint32 ms);
|
||||
|
||||
#endif // SLEEP_H
|
30
kernel.soso/spinlock.c
Normal file
30
kernel.soso/spinlock.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
#include "spinlock.h"
|
||||
|
||||
static inline int32 exchangeAtomic(volatile int32* oldValueAddress, int32 newValue)
|
||||
{
|
||||
//no need to use lock instruction on xchg
|
||||
|
||||
asm volatile ("xchgl %0, %1"
|
||||
: "=r"(newValue)
|
||||
: "m"(*oldValueAddress), "0"(newValue)
|
||||
: "memory");
|
||||
return newValue;
|
||||
}
|
||||
|
||||
void Spinlock_Init(Spinlock* spinlock)
|
||||
{
|
||||
*spinlock = 0;
|
||||
}
|
||||
|
||||
void Spinlock_Lock(Spinlock* spinlock)
|
||||
{
|
||||
while (exchangeAtomic((int32*)spinlock, 1))
|
||||
{
|
||||
halt();
|
||||
}
|
||||
}
|
||||
|
||||
void Spinlock_Unlock(Spinlock* spinlock)
|
||||
{
|
||||
*spinlock = 0;
|
||||
}
|
12
kernel.soso/spinlock.h
Normal file
12
kernel.soso/spinlock.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef SPINLOCK_H
|
||||
#define SPINLOCK_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
typedef int32 Spinlock;
|
||||
|
||||
void Spinlock_Init(Spinlock* spinlock);
|
||||
void Spinlock_Lock(Spinlock* spinlock);
|
||||
void Spinlock_Unlock(Spinlock* spinlock);
|
||||
|
||||
#endif // SPINLOCK_H
|
1163
kernel.soso/syscalls.c
Normal file
1163
kernel.soso/syscalls.c
Normal file
File diff suppressed because it is too large
Load Diff
6
kernel.soso/syscalls.h
Normal file
6
kernel.soso/syscalls.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef SYSCALLS_H
|
||||
#define SYSCALLS_H
|
||||
|
||||
void initialiseSyscalls();
|
||||
|
||||
#endif // SYSCALLS_H
|
51
kernel.soso/syscalltable.h
Normal file
51
kernel.soso/syscalltable.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
#ifndef SYSCALLTABLE_H
|
||||
#define SYSCALLTABLE_H
|
||||
|
||||
//This file will also be included by C library.
|
||||
enum
|
||||
{
|
||||
SYS_open, // 0
|
||||
SYS_close, // 1
|
||||
SYS_read, // 2
|
||||
SYS_write, // 3
|
||||
SYS_lseek, // 4
|
||||
SYS_stat, // 5
|
||||
SYS_fstat, // 6
|
||||
SYS_ioctl, // 7
|
||||
SYS_exit, // 8
|
||||
SYS_sbrk, // 9
|
||||
SYS_fork, // 10
|
||||
SYS_getpid, // 11
|
||||
|
||||
//non-posix
|
||||
SYS_execute, // 12
|
||||
SYS_execve, // 13
|
||||
SYS_wait, // 14
|
||||
SYS_kill, // 15
|
||||
SYS_mount, // 16
|
||||
SYS_unmount, // 17
|
||||
SYS_mkdir, // 18
|
||||
SYS_rmdir, // 19
|
||||
SYS_getdents, // 20
|
||||
SYS_getWorkingDirectory, // 21
|
||||
SYS_setWorkingDirectory, // 22
|
||||
SYS_managePipe, // 23
|
||||
SYS_readDir, // 24
|
||||
SYS_getUptimeMilliseconds, // 25
|
||||
SYS_sleepMilliseconds, // 26
|
||||
SYS_executeOnTTY, // 27
|
||||
SYS_manageMessage, // 28
|
||||
SYS_UNUSED, // 29
|
||||
|
||||
SYS_mmap, // 30
|
||||
SYS_munmap, // 31
|
||||
SYS_shm_open, // 32
|
||||
SYS_shm_unlink, // 33
|
||||
SYS_ftruncate, // 34
|
||||
SYS_posix_openpt, // 35
|
||||
SYS_ptsname_r, // 36
|
||||
|
||||
SYSCALL_COUNT // 37
|
||||
};
|
||||
|
||||
#endif // SYSCALLTABLE_H
|
344
kernel.soso/systemfs.c
Normal file
344
kernel.soso/systemfs.c
Normal file
|
@ -0,0 +1,344 @@
|
|||
#include "systemfs.h"
|
||||
#include "common.h"
|
||||
#include "fs.h"
|
||||
#include "alloc.h"
|
||||
#include "device.h"
|
||||
#include "screen.h"
|
||||
#include "vmm.h"
|
||||
#include "process.h"
|
||||
|
||||
static FileSystemNode* gSystemFsRoot = NULL;
|
||||
|
||||
|
||||
static BOOL systemfs_open(File *file, uint32 flags);
|
||||
static FileSystemDirent *systemfs_readdir(FileSystemNode *node, uint32 index);
|
||||
static FileSystemNode *systemfs_finddir(FileSystemNode *node, char *name);
|
||||
|
||||
static void createNodes();
|
||||
|
||||
static FileSystemDirent gDirent;
|
||||
|
||||
static int32 systemfs_read_meminfo_totalpages(File *file, uint32 size, uint8 *buffer);
|
||||
static int32 systemfs_read_meminfo_usedpages(File *file, uint32 size, uint8 *buffer);
|
||||
static BOOL systemfs_open_threads_dir(File *file, uint32 flags);
|
||||
static void systemfs_close_threads_dir(File *file);
|
||||
|
||||
void initializeSystemFS()
|
||||
{
|
||||
gSystemFsRoot = kmalloc(sizeof(FileSystemNode));
|
||||
memset((uint8*)gSystemFsRoot, 0, sizeof(FileSystemNode));
|
||||
|
||||
gSystemFsRoot->nodeType = FT_Directory;
|
||||
|
||||
FileSystemNode* rootFs = getFileSystemRootNode();
|
||||
|
||||
mkdir_fs(rootFs, "system", 0);
|
||||
|
||||
FileSystemNode* systemNode = finddir_fs(rootFs, "system");
|
||||
|
||||
if (systemNode)
|
||||
{
|
||||
systemNode->nodeType |= FT_MountPoint;
|
||||
systemNode->mountPoint = gSystemFsRoot;
|
||||
gSystemFsRoot->parent = systemNode->parent;
|
||||
strcpy(gSystemFsRoot->name, systemNode->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
PANIC("Could not create /system !");
|
||||
}
|
||||
|
||||
gSystemFsRoot->open = systemfs_open;
|
||||
gSystemFsRoot->finddir = systemfs_finddir;
|
||||
gSystemFsRoot->readdir = systemfs_readdir;
|
||||
|
||||
createNodes();
|
||||
}
|
||||
|
||||
static void createNodes()
|
||||
{
|
||||
FileSystemNode* nodeMemInfo = kmalloc(sizeof(FileSystemNode));
|
||||
|
||||
memset((uint8*)nodeMemInfo, 0, sizeof(FileSystemNode));
|
||||
|
||||
strcpy(nodeMemInfo->name, "meminfo");
|
||||
nodeMemInfo->nodeType = FT_Directory;
|
||||
nodeMemInfo->open = systemfs_open;
|
||||
nodeMemInfo->finddir = systemfs_finddir;
|
||||
nodeMemInfo->readdir = systemfs_readdir;
|
||||
nodeMemInfo->parent = gSystemFsRoot;
|
||||
|
||||
gSystemFsRoot->firstChild = nodeMemInfo;
|
||||
|
||||
FileSystemNode* nodeMemInfoTotalPages = kmalloc(sizeof(FileSystemNode));
|
||||
memset((uint8*)nodeMemInfoTotalPages, 0, sizeof(FileSystemNode));
|
||||
strcpy(nodeMemInfoTotalPages->name, "totalpages");
|
||||
nodeMemInfoTotalPages->nodeType = FT_File;
|
||||
nodeMemInfoTotalPages->open = systemfs_open;
|
||||
nodeMemInfoTotalPages->read = systemfs_read_meminfo_totalpages;
|
||||
nodeMemInfoTotalPages->parent = nodeMemInfo;
|
||||
|
||||
nodeMemInfo->firstChild = nodeMemInfoTotalPages;
|
||||
|
||||
FileSystemNode* nodeMemInfoUsedPages = kmalloc(sizeof(FileSystemNode));
|
||||
memset((uint8*)nodeMemInfoUsedPages, 0, sizeof(FileSystemNode));
|
||||
strcpy(nodeMemInfoUsedPages->name, "usedpages");
|
||||
nodeMemInfoUsedPages->nodeType = FT_File;
|
||||
nodeMemInfoUsedPages->open = systemfs_open;
|
||||
nodeMemInfoUsedPages->read = systemfs_read_meminfo_usedpages;
|
||||
nodeMemInfoUsedPages->parent = nodeMemInfo;
|
||||
|
||||
nodeMemInfoTotalPages->nextSibling = nodeMemInfoUsedPages;
|
||||
|
||||
//
|
||||
|
||||
FileSystemNode* nodeThreads = kmalloc(sizeof(FileSystemNode));
|
||||
memset((uint8*)nodeThreads, 0, sizeof(FileSystemNode));
|
||||
|
||||
strcpy(nodeThreads->name, "threads");
|
||||
nodeThreads->nodeType = FT_Directory;
|
||||
nodeThreads->open = systemfs_open_threads_dir;
|
||||
nodeThreads->close = systemfs_close_threads_dir;
|
||||
nodeThreads->finddir = systemfs_finddir;
|
||||
nodeThreads->readdir = systemfs_readdir;
|
||||
nodeThreads->parent = gSystemFsRoot;
|
||||
|
||||
nodeMemInfo->nextSibling = nodeThreads;
|
||||
|
||||
//
|
||||
|
||||
FileSystemNode* nodePipes = kmalloc(sizeof(FileSystemNode));
|
||||
memset((uint8*)nodePipes, 0, sizeof(FileSystemNode));
|
||||
|
||||
strcpy(nodePipes->name, "pipes");
|
||||
nodePipes->nodeType = FT_Directory;
|
||||
nodePipes->parent = gSystemFsRoot;
|
||||
|
||||
nodeThreads->nextSibling = nodePipes;
|
||||
|
||||
//
|
||||
|
||||
FileSystemNode* nodeShm = kmalloc(sizeof(FileSystemNode));
|
||||
memset((uint8*)nodeShm, 0, sizeof(FileSystemNode));
|
||||
|
||||
strcpy(nodeShm->name, "shm");
|
||||
nodeShm->nodeType = FT_Directory;
|
||||
nodeShm->parent = gSystemFsRoot;
|
||||
|
||||
nodePipes->nextSibling = nodeShm;
|
||||
}
|
||||
|
||||
static BOOL systemfs_open(File *file, uint32 flags)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static FileSystemDirent *systemfs_readdir(FileSystemNode *node, uint32 index)
|
||||
{
|
||||
int counter = 0;
|
||||
|
||||
FileSystemNode* child = node->firstChild;
|
||||
|
||||
//Screen_PrintF("systemfs_readdir-main:%s index:%d\n", node->name, index);
|
||||
|
||||
while (NULL != child)
|
||||
{
|
||||
//Screen_PrintF("systemfs_readdir-child:%s\n", child->name);
|
||||
if (counter == index)
|
||||
{
|
||||
strcpy(gDirent.name, child->name);
|
||||
gDirent.fileType = child->nodeType;
|
||||
|
||||
return &gDirent;
|
||||
}
|
||||
|
||||
++counter;
|
||||
|
||||
child = child->nextSibling;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static FileSystemNode *systemfs_finddir(FileSystemNode *node, char *name)
|
||||
{
|
||||
//Screen_PrintF("systemfs_finddir-main:%s requestedName:%s\n", node->name, name);
|
||||
|
||||
FileSystemNode* child = node->firstChild;
|
||||
while (NULL != child)
|
||||
{
|
||||
if (strcmp(name, child->name) == 0)
|
||||
{
|
||||
//Screen_PrintF("systemfs_finddir-found:%s\n", name);
|
||||
return child;
|
||||
}
|
||||
|
||||
child = child->nextSibling;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int32 systemfs_read_meminfo_totalpages(File *file, uint32 size, uint8 *buffer)
|
||||
{
|
||||
if (size >= 4)
|
||||
{
|
||||
if (file->offset == 0)
|
||||
{
|
||||
int totalPages = getTotalPageCount();
|
||||
|
||||
sprintf((char*)buffer, "%d", totalPages);
|
||||
|
||||
int len = strlen((char*)buffer);
|
||||
|
||||
file->offset += len;
|
||||
|
||||
return len;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int32 systemfs_read_meminfo_usedpages(File *file, uint32 size, uint8 *buffer)
|
||||
{
|
||||
if (size >= 4)
|
||||
{
|
||||
if (file->offset == 0)
|
||||
{
|
||||
int usedPages = getUsedPageCount();
|
||||
|
||||
sprintf((char*)buffer, "%d", usedPages);
|
||||
|
||||
int len = strlen((char*)buffer);
|
||||
|
||||
file->offset += len;
|
||||
|
||||
return len;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static BOOL systemfs_open_thread_file(File *file, uint32 flags)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void systemfs_close_thread_file(File *file)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static int32 systemfs_read_thread_file(File *file, uint32 size, uint8 *buffer)
|
||||
{
|
||||
if (size >= 128)
|
||||
{
|
||||
if (file->offset == 0)
|
||||
{
|
||||
int threadId = atoi(file->node->name);
|
||||
Thread* thread = getThreadById(threadId);
|
||||
if (thread)
|
||||
{
|
||||
int charIndex = 0;
|
||||
charIndex += sprintf((char*)buffer + charIndex, "tid:%d\n", thread->threadId);
|
||||
charIndex += sprintf((char*)buffer + charIndex, "userMode:%d\n", thread->userMode);
|
||||
uint8 state[10];
|
||||
threadStateToString(thread->state, state, 10);
|
||||
charIndex += sprintf((char*)buffer + charIndex, "state:%s\n", state);
|
||||
charIndex += sprintf((char*)buffer + charIndex, "contextSwitches:%d\n", thread->totalContextSwitchCount);
|
||||
if (thread->owner)
|
||||
{
|
||||
charIndex += sprintf((char*)buffer + charIndex, "process:%d\n", thread->owner->pid);
|
||||
}
|
||||
else
|
||||
{
|
||||
charIndex += sprintf((char*)buffer + charIndex, "process:-\n");
|
||||
}
|
||||
|
||||
int len = charIndex;
|
||||
|
||||
file->offset += len;
|
||||
|
||||
return len;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void cleanThreadNodes(File *file)
|
||||
{
|
||||
FileSystemNode* node = file->node->firstChild;
|
||||
|
||||
while (node)
|
||||
{
|
||||
FileSystemNode* next = node->nextSibling;
|
||||
|
||||
kfree(node);
|
||||
|
||||
node = next;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL systemfs_open_threads_dir(File *file, uint32 flags)
|
||||
{
|
||||
char buffer[16];
|
||||
|
||||
cleanThreadNodes(file);
|
||||
|
||||
//And fill again
|
||||
|
||||
FileSystemNode* nodePrevious = NULL;
|
||||
|
||||
Thread* thread = getMainKernelThread();
|
||||
|
||||
while (NULL != thread)
|
||||
{
|
||||
FileSystemNode* nodeThread = kmalloc(sizeof(FileSystemNode));
|
||||
memset((uint8*)nodeThread, 0, sizeof(FileSystemNode));
|
||||
|
||||
sprintf(buffer, "%d", thread->threadId);
|
||||
|
||||
strcpy(nodeThread->name, buffer);
|
||||
nodeThread->nodeType = FT_File;
|
||||
nodeThread->open = systemfs_open_thread_file;
|
||||
nodeThread->close = systemfs_close_thread_file;
|
||||
nodeThread->read = systemfs_read_thread_file;
|
||||
nodeThread->finddir = systemfs_finddir;
|
||||
nodeThread->readdir = systemfs_readdir;
|
||||
nodeThread->parent = file->node;
|
||||
|
||||
if (nodePrevious)
|
||||
{
|
||||
nodePrevious->nextSibling = nodeThread;
|
||||
}
|
||||
else
|
||||
{
|
||||
file->node->firstChild = nodeThread;
|
||||
}
|
||||
|
||||
nodePrevious = nodeThread;
|
||||
thread = thread->next;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void systemfs_close_threads_dir(File *file)
|
||||
{
|
||||
//left blank intentionally
|
||||
}
|
10
kernel.soso/systemfs.h
Normal file
10
kernel.soso/systemfs.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#ifndef SYSTEMFS_H
|
||||
#define SYSTEMFS_H
|
||||
|
||||
#include "device.h"
|
||||
#include "fs.h"
|
||||
#include "common.h"
|
||||
|
||||
void initializeSystemFS();
|
||||
|
||||
#endif // SYSTEMFS_H
|
39
kernel.soso/task.asm
Normal file
39
kernel.soso/task.asm
Normal file
|
@ -0,0 +1,39 @@
|
|||
global switchTask
|
||||
|
||||
switchTask:
|
||||
mov esi, [esp]
|
||||
pop eax ; *current thread
|
||||
|
||||
; get values from thread->regs structure
|
||||
|
||||
push dword [esi+4] ; eax
|
||||
push dword [esi+8] ; ecx
|
||||
push dword [esi+12] ; edx
|
||||
push dword [esi+16] ; ebx
|
||||
push dword [esi+24] ; ebp
|
||||
push dword [esi+28] ; esi
|
||||
push dword [esi+32] ; edi
|
||||
push dword [esi+48] ; ds
|
||||
push dword [esi+50] ; es
|
||||
push dword [esi+52] ; fs
|
||||
push dword [esi+54] ; gs
|
||||
|
||||
mov al, 0x20
|
||||
out 0x20, al
|
||||
|
||||
mov eax, [esi+56]
|
||||
mov cr3, eax
|
||||
|
||||
pop gs
|
||||
pop fs
|
||||
pop es
|
||||
pop ds
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebp
|
||||
pop ebx
|
||||
pop edx
|
||||
pop ecx
|
||||
pop eax
|
||||
|
||||
iret
|
192
kernel.soso/termios.h
Normal file
192
kernel.soso/termios.h
Normal file
|
@ -0,0 +1,192 @@
|
|||
#ifndef TERMIOS_H
|
||||
#define TERMIOS_H
|
||||
|
||||
//This file will also be included by C library.
|
||||
|
||||
typedef unsigned char cc_t;
|
||||
typedef unsigned int speed_t;
|
||||
typedef unsigned int tcflag_t;
|
||||
|
||||
#define NCCS 32
|
||||
|
||||
struct termios
|
||||
{
|
||||
tcflag_t c_iflag; // input mode flags
|
||||
tcflag_t c_oflag; // output mode flags
|
||||
tcflag_t c_cflag; // control mode flags
|
||||
tcflag_t c_lflag; // local mode flags
|
||||
cc_t c_line; // line discipline
|
||||
cc_t c_cc[NCCS]; // control characters
|
||||
speed_t c_ispeed; // input speed
|
||||
speed_t c_ospeed; // output speed
|
||||
|
||||
};
|
||||
|
||||
// c_cc characters
|
||||
#define VINTR 0
|
||||
#define VQUIT 1
|
||||
#define VERASE 2
|
||||
#define VKILL 3
|
||||
#define VEOF 4
|
||||
#define VTIME 5
|
||||
#define VMIN 6
|
||||
#define VSWTC 7
|
||||
#define VSTART 8
|
||||
#define VSTOP 9
|
||||
#define VSUSP 10
|
||||
#define VEOL 11
|
||||
#define VREPRINT 12
|
||||
#define VDISCARD 13
|
||||
#define VWERASE 14
|
||||
#define VLNEXT 15
|
||||
#define VEOL2 16
|
||||
|
||||
// c_iflag bits
|
||||
#define IGNBRK 0000001
|
||||
#define BRKINT 0000002
|
||||
#define IGNPAR 0000004
|
||||
#define PARMRK 0000010
|
||||
#define INPCK 0000020
|
||||
#define ISTRIP 0000040
|
||||
#define INLCR 0000100
|
||||
#define IGNCR 0000200
|
||||
#define ICRNL 0000400
|
||||
#define IUCLC 0001000
|
||||
#define IXON 0002000
|
||||
#define IXANY 0004000
|
||||
#define IXOFF 0010000
|
||||
#define IMAXBEL 0020000
|
||||
#define IUTF8 0040000
|
||||
|
||||
// c_oflag bits
|
||||
#define OPOST 0000001
|
||||
#define OLCUC 0000002
|
||||
#define ONLCR 0000004
|
||||
#define OCRNL 0000010
|
||||
#define ONOCR 0000020
|
||||
#define ONLRET 0000040
|
||||
#define OFILL 0000100
|
||||
#define OFDEL 0000200
|
||||
#define NLDLY 0000400
|
||||
#define NL0 0000000
|
||||
#define NL1 0000400
|
||||
#define CRDLY 0003000
|
||||
#define CR0 0000000
|
||||
#define CR1 0001000
|
||||
#define CR2 0002000
|
||||
#define CR3 0003000
|
||||
#define TABDLY 0014000
|
||||
#define TAB0 0000000
|
||||
#define TAB1 0004000
|
||||
#define TAB2 0010000
|
||||
#define TAB3 0014000
|
||||
#define BSDLY 0020000
|
||||
#define BS0 0000000
|
||||
#define BS1 0020000
|
||||
#define FFDLY 0100000
|
||||
#define FF0 0000000
|
||||
#define FF1 0100000
|
||||
|
||||
#define VTDLY 0040000
|
||||
#define VT0 0000000
|
||||
#define VT1 0040000
|
||||
#define XTABS 0014000
|
||||
|
||||
// c_cflag bit meaning
|
||||
# define CBAUD 0010017
|
||||
|
||||
#define B0 0000000 // hang up
|
||||
#define B50 0000001
|
||||
#define B75 0000002
|
||||
#define B110 0000003
|
||||
#define B134 0000004
|
||||
#define B150 0000005
|
||||
#define B200 0000006
|
||||
#define B300 0000007
|
||||
#define B600 0000010
|
||||
#define B1200 0000011
|
||||
#define B1800 0000012
|
||||
#define B2400 0000013
|
||||
#define B4800 0000014
|
||||
#define B9600 0000015
|
||||
#define B19200 0000016
|
||||
#define B38400 0000017
|
||||
#define EXTA B19200
|
||||
#define EXTB B38400
|
||||
#define CSIZE 0000060
|
||||
#define CS5 0000000
|
||||
#define CS6 0000020
|
||||
#define CS7 0000040
|
||||
#define CS8 0000060
|
||||
#define CSTOPB 0000100
|
||||
#define CREAD 0000200
|
||||
#define PARENB 0000400
|
||||
#define PARODD 0001000
|
||||
#define HUPCL 0002000
|
||||
#define CLOCAL 0004000
|
||||
|
||||
#define CBAUDEX 0010000
|
||||
|
||||
#define B57600 0010001
|
||||
#define B115200 0010002
|
||||
#define B230400 0010003
|
||||
#define B460800 0010004
|
||||
#define B500000 0010005
|
||||
#define B576000 0010006
|
||||
#define B921600 0010007
|
||||
#define B1000000 0010010
|
||||
#define B1152000 0010011
|
||||
#define B1500000 0010012
|
||||
#define B2000000 0010013
|
||||
#define B2500000 0010014
|
||||
#define B3000000 0010015
|
||||
#define B3500000 0010016
|
||||
#define B4000000 0010017
|
||||
#define __MAX_BAUD B4000000
|
||||
|
||||
#define CIBAUD 002003600000 // input baud rate (not used)
|
||||
#define CMSPAR 010000000000 // mark or space (stick) parity
|
||||
#define CRTSCTS 020000000000 // flow control
|
||||
|
||||
// c_lflag bits
|
||||
#define ISIG 0000001
|
||||
#define ICANON 0000002
|
||||
#define XCASE 0000004
|
||||
#define ECHO 0000010
|
||||
#define ECHOE 0000020
|
||||
#define ECHOK 0000040
|
||||
#define ECHONL 0000100
|
||||
#define NOFLSH 0000200
|
||||
#define TOSTOP 0000400
|
||||
#define ECHOCTL 0001000
|
||||
#define ECHOPRT 0002000
|
||||
#define ECHOKE 0004000
|
||||
#define FLUSHO 0010000
|
||||
#define PENDIN 0040000
|
||||
|
||||
#define IEXTEN 0100000
|
||||
#define EXTPROC 0200000
|
||||
|
||||
// tcflow() and TCXONC use these
|
||||
#define TCOOFF 0
|
||||
#define TCOON 1
|
||||
#define TCIOFF 2
|
||||
#define TCION 3
|
||||
|
||||
// tcflush() and TCFLSH use these
|
||||
#define TCIFLUSH 0
|
||||
#define TCOFLUSH 1
|
||||
#define TCIOFLUSH 2
|
||||
|
||||
// tcsetattr uses these
|
||||
#define TCSANOW 0
|
||||
#define TCSADRAIN 1
|
||||
#define TCSAFLUSH 2
|
||||
|
||||
//ioctl interface
|
||||
#define TCGETS 0x5001
|
||||
#define TCSETS 0x5002
|
||||
#define TCSETSW 0x5003
|
||||
#define TCSETSF 0x5004
|
||||
|
||||
#endif // TERMIOS_H
|
65
kernel.soso/timer.c
Normal file
65
kernel.soso/timer.c
Normal file
|
@ -0,0 +1,65 @@
|
|||
#include "timer.h"
|
||||
#include "isr.h"
|
||||
#include "screen.h"
|
||||
#include "process.h"
|
||||
#include "common.h"
|
||||
|
||||
#define TIMER_FREQ 1000
|
||||
|
||||
uint32 gSystemTickCount = 0;
|
||||
|
||||
BOOL gSchedulerEnabled = FALSE;
|
||||
|
||||
//called from assembly
|
||||
void handleTimerIRQ(TimerInt_Registers registers)
|
||||
{
|
||||
gSystemTickCount++;
|
||||
|
||||
if (/*gSystemTickCount % 10 == 0 &&*/ gSchedulerEnabled == TRUE)
|
||||
{
|
||||
schedule(®isters);
|
||||
}
|
||||
}
|
||||
|
||||
uint32 getSystemTickCount()
|
||||
{
|
||||
return gSystemTickCount;
|
||||
}
|
||||
|
||||
uint32 getUptimeSeconds()
|
||||
{
|
||||
return gSystemTickCount / TIMER_FREQ;
|
||||
}
|
||||
|
||||
uint32 getUptimeMilliseconds()
|
||||
{
|
||||
return gSystemTickCount;
|
||||
}
|
||||
|
||||
void enableScheduler()
|
||||
{
|
||||
gSchedulerEnabled = TRUE;
|
||||
}
|
||||
|
||||
void disableScheduler()
|
||||
{
|
||||
gSchedulerEnabled = FALSE;
|
||||
}
|
||||
|
||||
static void initTimer(uint32 frequency)
|
||||
{
|
||||
uint32 divisor = 1193180 / frequency;
|
||||
|
||||
outb(0x43, 0x36);
|
||||
|
||||
uint8 l = (uint8)(divisor & 0xFF);
|
||||
uint8 h = (uint8)( (divisor>>8) & 0xFF );
|
||||
|
||||
outb(0x40, l);
|
||||
outb(0x40, h);
|
||||
}
|
||||
|
||||
void initializeTimer()
|
||||
{
|
||||
initTimer(TIMER_FREQ);
|
||||
}
|
13
kernel.soso/timer.h
Normal file
13
kernel.soso/timer.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#ifndef TIMER_H
|
||||
#define TIMER_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
void initializeTimer();
|
||||
uint32 getSystemTickCount();
|
||||
uint32 getUptimeSeconds();
|
||||
uint32 getUptimeMilliseconds();
|
||||
void enableScheduler();
|
||||
void disableScheduler();
|
||||
|
||||
#endif
|
175
kernel.soso/tty.c
Normal file
175
kernel.soso/tty.c
Normal file
|
@ -0,0 +1,175 @@
|
|||
#include "tty.h"
|
||||
#include "alloc.h"
|
||||
|
||||
Tty* createTty(uint16 lineCount, uint16 columnCount, TtyFlushScreenFunction flushFunction)
|
||||
{
|
||||
Tty* tty = kmalloc(sizeof(Tty));
|
||||
memset((uint8*)tty, 0, sizeof(Tty));
|
||||
|
||||
tty->lineCount = lineCount;
|
||||
tty->columnCount = columnCount;
|
||||
tty->buffer = kmalloc(tty->lineCount * tty->columnCount * 2);
|
||||
tty->currentColumn = 0;
|
||||
tty->currentLine = 0;
|
||||
tty->color = 0x0A;
|
||||
|
||||
memset(tty->lineBuffer, 0, TTY_LINEBUFFER_SIZE);
|
||||
tty->lineBufferIndex = 0;
|
||||
tty->keyBuffer = FifoBuffer_create(64);
|
||||
tty->flushScreen = flushFunction;
|
||||
|
||||
tty->term.c_cc[VMIN] = 1;
|
||||
tty->term.c_lflag |= ECHO;
|
||||
tty->term.c_lflag |= ICANON;
|
||||
|
||||
Tty_Clear(tty);
|
||||
|
||||
return tty;
|
||||
}
|
||||
|
||||
void destroyTty(Tty* tty)
|
||||
{
|
||||
FifoBuffer_destroy(tty->keyBuffer);
|
||||
kfree(tty->buffer);
|
||||
kfree(tty);
|
||||
}
|
||||
|
||||
void Tty_Print(Tty* tty, int row, int column, const char* text)
|
||||
{
|
||||
unsigned char * video = tty->buffer;
|
||||
|
||||
video += (row * tty->columnCount + column) * 2;
|
||||
while(*text != 0)
|
||||
{
|
||||
*video++ = *text++;
|
||||
*video++ = tty->color;
|
||||
}
|
||||
}
|
||||
|
||||
//One line
|
||||
void Tty_ScrollUp(Tty* tty)
|
||||
{
|
||||
unsigned char * videoLine = tty->buffer;
|
||||
unsigned char * videoLineNext = tty->buffer;
|
||||
int line = 0;
|
||||
int column = 0;
|
||||
|
||||
for (line = 0; line < tty->lineCount - 1; ++line)
|
||||
{
|
||||
for (column = 0; column < tty->columnCount; ++column)
|
||||
{
|
||||
videoLine = tty->buffer + (line * tty->columnCount + column) * 2;
|
||||
videoLineNext = tty->buffer + ((line + 1) * tty->columnCount + column) * 2;
|
||||
|
||||
videoLine[0] = videoLineNext[0];
|
||||
videoLine[1] = videoLineNext[1];
|
||||
}
|
||||
}
|
||||
|
||||
//Last line should be empty.
|
||||
unsigned char * lastLine = tty->buffer + ((tty->lineCount - 1) * tty->columnCount) * 2;
|
||||
for (int i = 0; i < tty->columnCount * 2; i += 2)
|
||||
{
|
||||
lastLine[i] = 0;
|
||||
lastLine[i + 1] = tty->color;
|
||||
}
|
||||
}
|
||||
|
||||
void Tty_Clear(Tty* tty)
|
||||
{
|
||||
unsigned char * video = tty->buffer;
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < tty->lineCount * tty->columnCount; ++i)
|
||||
{
|
||||
*video++ = 0;
|
||||
*video++ = tty->color;
|
||||
}
|
||||
|
||||
tty->currentLine = 0;
|
||||
tty->currentColumn = 0;
|
||||
}
|
||||
|
||||
void Tty_PutChar(Tty* tty, char c)
|
||||
{
|
||||
unsigned char * video = tty->buffer;
|
||||
|
||||
if ('\n' == c || '\r' == c)
|
||||
{
|
||||
++tty->currentLine;
|
||||
tty->currentColumn = 0;
|
||||
|
||||
if (tty->currentLine >= tty->lineCount - 0)
|
||||
{
|
||||
--tty->currentLine;
|
||||
Tty_ScrollUp(tty);
|
||||
}
|
||||
|
||||
Tty_MoveCursor(tty, tty->currentLine, tty->currentColumn);
|
||||
return;
|
||||
}
|
||||
else if ('\b' == c)
|
||||
{
|
||||
if (tty->currentColumn > 0)
|
||||
{
|
||||
--tty->currentColumn;
|
||||
c = '\0';
|
||||
video = tty->buffer + (tty->currentLine * tty->columnCount + tty->currentColumn) * 2;
|
||||
video[0] = c;
|
||||
video[1] = tty->color;
|
||||
Tty_MoveCursor(tty, tty->currentLine, tty->currentColumn);
|
||||
return;
|
||||
}
|
||||
else if (tty->currentColumn == 0)
|
||||
{
|
||||
if (tty->currentLine > 0)
|
||||
{
|
||||
--tty->currentLine;
|
||||
tty->currentColumn = tty->columnCount - 1;
|
||||
c = '\0';
|
||||
video = tty->buffer + (tty->currentLine * tty->columnCount + tty->currentColumn) * 2;
|
||||
video[0] = c;
|
||||
video[1] = tty->color;
|
||||
Tty_MoveCursor(tty, tty->currentLine, tty->currentColumn);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tty->currentColumn >= tty->columnCount)
|
||||
{
|
||||
++tty->currentLine;
|
||||
tty->currentColumn = 0;
|
||||
}
|
||||
|
||||
if (tty->currentLine >= tty->lineCount - 0)
|
||||
{
|
||||
--tty->currentLine;
|
||||
Tty_ScrollUp(tty);
|
||||
}
|
||||
|
||||
video += (tty->currentLine * tty->columnCount + tty->currentColumn) * 2;
|
||||
|
||||
video[0] = c;
|
||||
video[1] = tty->color;
|
||||
|
||||
++tty->currentColumn;
|
||||
|
||||
Tty_MoveCursor(tty, tty->currentLine, tty->currentColumn);
|
||||
}
|
||||
|
||||
void Tty_PutText(Tty* tty, const char* text)
|
||||
{
|
||||
const char* c = text;
|
||||
while (*c)
|
||||
{
|
||||
Tty_PutChar(tty, *c);
|
||||
++c;
|
||||
}
|
||||
}
|
||||
|
||||
void Tty_MoveCursor(Tty* tty, uint16 line, uint16 column)
|
||||
{
|
||||
tty->currentLine = line;
|
||||
tty->currentColumn = column;
|
||||
}
|
42
kernel.soso/tty.h
Normal file
42
kernel.soso/tty.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
#ifndef TTY_H
|
||||
#define TTY_H
|
||||
|
||||
#include "common.h"
|
||||
#include "fifobuffer.h"
|
||||
#include "termios.h"
|
||||
|
||||
#define TTY_LINEBUFFER_SIZE 1024
|
||||
|
||||
typedef struct Tty Tty;
|
||||
|
||||
typedef void (*TtyFlushScreenFunction)(Tty* tty);
|
||||
|
||||
typedef struct Tty
|
||||
{
|
||||
uint16 lineCount;
|
||||
uint16 columnCount;
|
||||
uint8* buffer;
|
||||
uint16 currentLine;
|
||||
uint16 currentColumn;
|
||||
uint8 color;
|
||||
void* privateData;
|
||||
uint8 lineBuffer[TTY_LINEBUFFER_SIZE];
|
||||
uint32 lineBufferIndex;
|
||||
FifoBuffer* keyBuffer;
|
||||
struct termios term;
|
||||
TtyFlushScreenFunction flushScreen;
|
||||
} Tty;
|
||||
|
||||
|
||||
|
||||
Tty* createTty(uint16 lineCount, uint16 columnCount, TtyFlushScreenFunction flushFunction);
|
||||
void destroyTty(Tty* tty);
|
||||
|
||||
void Tty_Print(Tty* tty, int row, int column, const char* text);
|
||||
void Tty_Clear(Tty* tty);
|
||||
void Tty_PutChar(Tty* tty, char c);
|
||||
void Tty_PutText(Tty* tty, const char* text);
|
||||
void Tty_MoveCursor(Tty* tty, uint16 line, uint16 column);
|
||||
void Tty_ScrollUp(Tty* tty);
|
||||
|
||||
#endif // TTY_H
|
671
kernel.soso/ttydriver.c
Normal file
671
kernel.soso/ttydriver.c
Normal file
|
@ -0,0 +1,671 @@
|
|||
#include "ttydriver.h"
|
||||
#include "device.h"
|
||||
#include "screen.h"
|
||||
#include "serial.h"
|
||||
#include "devfs.h"
|
||||
#include "alloc.h"
|
||||
#include "common.h"
|
||||
#include "list.h"
|
||||
#include "fifobuffer.h"
|
||||
#include "gfx.h"
|
||||
#include "debugprint.h"
|
||||
#include "commonuser.h"
|
||||
#include "termios.h"
|
||||
|
||||
static List* gTtyList = NULL;
|
||||
|
||||
static List* gReaderList = NULL;
|
||||
|
||||
static Tty* gActiveTty = NULL;
|
||||
|
||||
static uint8 gKeyModifier = 0;
|
||||
|
||||
static uint32 gPseudoTerminalNameGenerator = 0;
|
||||
|
||||
typedef enum KeyModifier
|
||||
{
|
||||
KM_LeftShift = 1,
|
||||
KM_RightShift = 2,
|
||||
KM_Ctrl = 4,
|
||||
KM_Alt = 8
|
||||
} KeyModifier;
|
||||
|
||||
enum
|
||||
{
|
||||
KEY_LEFTSHIFT = 0x2A,
|
||||
KEY_RIGHTSHIFT = 0x36,
|
||||
KEY_CTRL = 0x1D,
|
||||
KEY_ALT = 0x38,
|
||||
KEY_CAPSLOCK = 0x3A,
|
||||
KEY_F1 = 0x3B,
|
||||
KEY_F2 = 0x3C,
|
||||
KEY_F3 = 0x3D
|
||||
};
|
||||
|
||||
// PC keyboard interface constants
|
||||
|
||||
#define KBSTATP 0x64 // kbd controller status port(I)
|
||||
#define KBS_DIB 0x01 // kbd data in buffer
|
||||
#define KBDATAP 0x60 // kbd data port(I)
|
||||
|
||||
#define NO 0
|
||||
|
||||
#define SHIFT (1<<0)
|
||||
#define CTL (1<<1)
|
||||
#define ALT (1<<2)
|
||||
|
||||
#define CAPSLOCK (1<<3)
|
||||
#define NUMLOCK (1<<4)
|
||||
#define SCROLLLOCK (1<<5)
|
||||
|
||||
#define E0ESC (1<<6)
|
||||
|
||||
// Special keycodes
|
||||
#define KEY_HOME 0xE0
|
||||
#define KEY_END 0xE1
|
||||
#define KEY_UP 0xE2
|
||||
#define KEY_DOWN 0xE3
|
||||
#define KEY_LEFT 0xE4
|
||||
#define KEY_RIGHT 0xE5
|
||||
#define KEY_PAGEUP 0xE6
|
||||
#define KEY_PAGEDOWN 0xE7
|
||||
#define KEY_INSERT 0xE8
|
||||
#define KEY_DELETE 0xE9
|
||||
|
||||
// C('A') == Control-A
|
||||
#define C(x) (x - '@')
|
||||
|
||||
|
||||
|
||||
|
||||
static uint8 gKeyMap[256] =
|
||||
{
|
||||
NO, 0x1B, '1', '2', '3', '4', '5', '6', // 0x00
|
||||
'7', '8', '9', '0', '-', '=', '\b', '\t',
|
||||
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', // 0x10
|
||||
'o', 'p', '[', ']', '\n', NO, 'a', 's',
|
||||
'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', // 0x20
|
||||
'\'', '`', NO, '\\', 'z', 'x', 'c', 'v',
|
||||
'b', 'n', 'm', ',', '.', '/', NO, '*', // 0x30
|
||||
NO, ' ', NO, NO, NO, NO, NO, NO,
|
||||
NO, NO, NO, NO, NO, NO, NO, '7', // 0x40
|
||||
'8', '9', '-', '4', '5', '6', '+', '1',
|
||||
'2', '3', '0', '.', NO, NO, NO, NO, // 0x50
|
||||
[0x49] = KEY_PAGEUP,
|
||||
[0x51] = KEY_PAGEDOWN,
|
||||
[0x47] = KEY_HOME,
|
||||
[0x4F] = KEY_END,
|
||||
[0x52] = KEY_INSERT,
|
||||
[0x53] = KEY_DELETE,
|
||||
[0x48] = KEY_UP,
|
||||
[0x50] = KEY_DOWN,
|
||||
[0x4B] = KEY_LEFT,
|
||||
[0x4D] = KEY_RIGHT,
|
||||
[0x9C] = '\n', // KP_Enter
|
||||
[0xB5] = '/', // KP_Div
|
||||
[0xC8] = KEY_UP,
|
||||
[0xD0] = KEY_DOWN,
|
||||
[0xC9] = KEY_PAGEUP,
|
||||
[0xD1] = KEY_PAGEDOWN,
|
||||
[0xCB] = KEY_LEFT,
|
||||
[0xCD] = KEY_RIGHT,
|
||||
[0x97] = KEY_HOME,
|
||||
[0xCF] = KEY_END,
|
||||
[0xD2] = KEY_INSERT,
|
||||
[0xD3] = KEY_DELETE
|
||||
};
|
||||
|
||||
static uint8 gKeyShiftMap[256] =
|
||||
{
|
||||
NO, 033, '!', '@', '#', '$', '%', '^', // 0x00
|
||||
'&', '*', '(', ')', '_', '+', '\b', '\t',
|
||||
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', // 0x10
|
||||
'O', 'P', '{', '}', '\n', NO, 'A', 'S',
|
||||
'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', // 0x20
|
||||
'"', '~', NO, '|', 'Z', 'X', 'C', 'V',
|
||||
'B', 'N', 'M', '<', '>', '?', NO, '*', // 0x30
|
||||
NO, ' ', NO, NO, NO, NO, NO, NO,
|
||||
NO, NO, NO, NO, NO, NO, NO, '7', // 0x40
|
||||
'8', '9', '-', '4', '5', '6', '+', '1',
|
||||
'2', '3', '0', '.', NO, NO, NO, NO, // 0x50
|
||||
[0x49] = KEY_PAGEUP,
|
||||
[0x51] = KEY_PAGEDOWN,
|
||||
[0x47] = KEY_HOME,
|
||||
[0x4F] = KEY_END,
|
||||
[0x52] = KEY_INSERT,
|
||||
[0x53] = KEY_DELETE,
|
||||
[0x48] = KEY_UP,
|
||||
[0x50] = KEY_DOWN,
|
||||
[0x4B] = KEY_LEFT,
|
||||
[0x4D] = KEY_RIGHT,
|
||||
[0x9C] = '\n', // KP_Enter
|
||||
[0xB5] = '/', // KP_Div
|
||||
[0xC8] = KEY_UP,
|
||||
[0xD0] = KEY_DOWN,
|
||||
[0xC9] = KEY_PAGEUP,
|
||||
[0xD1] = KEY_PAGEDOWN,
|
||||
[0xCB] = KEY_LEFT,
|
||||
[0xCD] = KEY_RIGHT,
|
||||
[0x97] = KEY_HOME,
|
||||
[0xCF] = KEY_END,
|
||||
[0xD2] = KEY_INSERT,
|
||||
[0xD3] = KEY_DELETE
|
||||
};
|
||||
|
||||
static BOOL tty_open(File *file, uint32 flags);
|
||||
static void tty_close(File *file);
|
||||
static int32 tty_ioctl(File *file, int32 request, void * argp);
|
||||
static int32 tty_read(File *file, uint32 size, uint8 *buffer);
|
||||
static int32 tty_write(File *file, uint32 size, uint8 *buffer);
|
||||
static int32 write(Tty* tty, uint32 size, uint8 *buffer);
|
||||
|
||||
static uint8 getCharacterForScancode(KeyModifier modifier, uint8 scancode);
|
||||
static void processScancode(uint8 scancode);
|
||||
|
||||
void initializeTTYs(BOOL graphicMode)
|
||||
{
|
||||
gTtyList = List_Create();
|
||||
|
||||
gReaderList = List_Create();
|
||||
|
||||
for (int i = 1; i <= 9; ++i)
|
||||
{
|
||||
Tty* tty = NULL;
|
||||
if (graphicMode)
|
||||
{
|
||||
tty = createTty(768 / 16, 1024 / 9, Gfx_FlushFromTty);
|
||||
}
|
||||
else
|
||||
{
|
||||
tty = createTty(25, 80, Screen_FlushFromTty);
|
||||
}
|
||||
|
||||
tty->color = 0x0A;
|
||||
|
||||
List_Append(gTtyList, tty);
|
||||
|
||||
Device device;
|
||||
memset((uint8*)&device, 0, sizeof(Device));
|
||||
sprintf(device.name, "tty%d", i);
|
||||
device.deviceType = FT_CharacterDevice;
|
||||
device.open = tty_open;
|
||||
device.close = tty_close;
|
||||
device.ioctl = tty_ioctl;
|
||||
device.read = tty_read;
|
||||
device.write = tty_write;
|
||||
device.privateData = tty;
|
||||
registerDevice(&device);
|
||||
}
|
||||
|
||||
gActiveTty = List_GetFirstNode(gTtyList)->data;
|
||||
}
|
||||
|
||||
Tty* getActiveTTY()
|
||||
{
|
||||
return gActiveTty;
|
||||
}
|
||||
|
||||
FileSystemNode* createPseudoTerminal()
|
||||
{
|
||||
Tty* tty = createTty(768 / 16, 1024 / 9, Gfx_FlushFromTty);
|
||||
|
||||
tty->color = 0x0A;
|
||||
|
||||
Device device;
|
||||
memset((uint8*)&device, 0, sizeof(Device));
|
||||
sprintf(device.name, "pts%d", gPseudoTerminalNameGenerator++);
|
||||
device.deviceType = FT_CharacterDevice;
|
||||
device.open = tty_open;
|
||||
device.close = tty_close;
|
||||
device.ioctl = tty_ioctl;
|
||||
device.read = tty_read;
|
||||
device.write = tty_write;
|
||||
device.privateData = tty;
|
||||
FileSystemNode* node = registerDevice(&device);
|
||||
if (NULL == node)
|
||||
{
|
||||
destroyTty(tty);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static void sendInputToKeyBuffer(Tty* tty, uint8 scancode, uint8 character)
|
||||
{
|
||||
char seq[8];
|
||||
memset(seq, 0, 8);
|
||||
|
||||
switch (character) {
|
||||
case KEY_PAGEUP:
|
||||
{
|
||||
seq[0] = 27;
|
||||
seq[1] = 91;
|
||||
seq[2] = 53;
|
||||
seq[3] = 126;
|
||||
FifoBuffer_enqueue(tty->keyBuffer, seq, 4);
|
||||
}
|
||||
break;
|
||||
case KEY_PAGEDOWN:
|
||||
{
|
||||
seq[0] = 27;
|
||||
seq[1] = 91;
|
||||
seq[2] = 54;
|
||||
seq[3] = 126;
|
||||
FifoBuffer_enqueue(tty->keyBuffer, seq, 4);
|
||||
}
|
||||
break;
|
||||
case KEY_HOME:
|
||||
{
|
||||
seq[0] = 27;
|
||||
seq[1] = 91;
|
||||
seq[2] = 72;
|
||||
FifoBuffer_enqueue(tty->keyBuffer, seq, 3);
|
||||
}
|
||||
break;
|
||||
case KEY_END:
|
||||
{
|
||||
seq[0] = 27;
|
||||
seq[1] = 91;
|
||||
seq[2] = 70;
|
||||
FifoBuffer_enqueue(tty->keyBuffer, seq, 3);
|
||||
}
|
||||
break;
|
||||
case KEY_INSERT:
|
||||
{
|
||||
seq[0] = 27;
|
||||
seq[1] = 91;
|
||||
seq[2] = 50;
|
||||
seq[3] = 126;
|
||||
FifoBuffer_enqueue(tty->keyBuffer, seq, 4);
|
||||
}
|
||||
break;
|
||||
case KEY_DELETE:
|
||||
{
|
||||
seq[0] = 27;
|
||||
seq[1] = 91;
|
||||
seq[2] = 51;
|
||||
seq[3] = 126;
|
||||
FifoBuffer_enqueue(tty->keyBuffer, seq, 4);
|
||||
}
|
||||
break;
|
||||
case KEY_UP:
|
||||
{
|
||||
seq[0] = 27;
|
||||
seq[1] = 91;
|
||||
seq[2] = 65;
|
||||
FifoBuffer_enqueue(tty->keyBuffer, seq, 3);
|
||||
}
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
{
|
||||
seq[0] = 27;
|
||||
seq[1] = 91;
|
||||
seq[2] = 66;
|
||||
FifoBuffer_enqueue(tty->keyBuffer, seq, 3);
|
||||
}
|
||||
break;
|
||||
case KEY_RIGHT:
|
||||
{
|
||||
seq[0] = 27;
|
||||
seq[1] = 91;
|
||||
seq[2] = 67;
|
||||
FifoBuffer_enqueue(tty->keyBuffer, seq, 3);
|
||||
}
|
||||
break;
|
||||
case KEY_LEFT:
|
||||
{
|
||||
seq[0] = 27;
|
||||
seq[1] = 91;
|
||||
seq[2] = 68;
|
||||
FifoBuffer_enqueue(tty->keyBuffer, seq, 3);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
FifoBuffer_enqueue(tty->keyBuffer, &character, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void sendKeyInputToTTY(Tty* tty, uint8 scancode)
|
||||
{
|
||||
beginCriticalSection();
|
||||
|
||||
processScancode(scancode);
|
||||
|
||||
uint8 character = getCharacterForScancode(gKeyModifier, scancode);
|
||||
|
||||
uint8 keyRelease = (0x80 & scancode); //ignore release event
|
||||
|
||||
if (character > 0 && keyRelease == 0)
|
||||
{
|
||||
//enqueue for non-canonical readers
|
||||
sendInputToKeyBuffer(tty, scancode, character);
|
||||
//FifoBuffer_enqueue(tty->keyBuffer, &scancode, 1);
|
||||
|
||||
if (tty->lineBufferIndex >= TTY_LINEBUFFER_SIZE - 1)
|
||||
{
|
||||
tty->lineBufferIndex = 0;
|
||||
}
|
||||
|
||||
if (character == '\b')
|
||||
{
|
||||
if (tty->lineBufferIndex > 0)
|
||||
{
|
||||
tty->lineBuffer[--tty->lineBufferIndex] = '\0';
|
||||
|
||||
if ((tty->term.c_lflag & ECHO) == ECHO)
|
||||
{
|
||||
write(tty, 1, &character);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tty->lineBuffer[tty->lineBufferIndex++] = character;
|
||||
|
||||
if ((tty->term.c_lflag & ECHO) == ECHO)
|
||||
{
|
||||
write(tty, 1, &character);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Wake readers
|
||||
List_Foreach(n, gReaderList)
|
||||
{
|
||||
File* file = n->data;
|
||||
|
||||
if (file->thread->state == TS_WAITIO)
|
||||
{
|
||||
if (file->thread->state_privateData == tty)
|
||||
{
|
||||
file->thread->state = TS_RUN;
|
||||
file->thread->state_privateData = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
endCriticalSection();
|
||||
}
|
||||
|
||||
static BOOL tty_open(File *file, uint32 flags)
|
||||
{
|
||||
//Screen_PrintF("tty_open: pid:%d\n", file->process->pid);
|
||||
|
||||
Tty* tty = (Tty*)file->node->privateNodeData;
|
||||
|
||||
FifoBuffer_clear(tty->keyBuffer);
|
||||
|
||||
List_Append(gReaderList, file);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void tty_close(File *file)
|
||||
{
|
||||
List_RemoveFirstOccurrence(gReaderList, file);
|
||||
}
|
||||
|
||||
static int32 tty_ioctl(File *file, int32 request, void * argp)
|
||||
{
|
||||
Tty* tty = (Tty*)file->node->privateNodeData;
|
||||
|
||||
switch (request)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
sendKeyInputToTTY(tty, (uint8)(uint32)argp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
return tty->columnCount * tty->lineCount * 2;
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
//set
|
||||
TtyUserBuffer* userTtyBuffer = (TtyUserBuffer*)argp;
|
||||
memcpy(tty->buffer, (uint8*)userTtyBuffer->buffer, tty->columnCount * tty->lineCount * 2);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
//get
|
||||
TtyUserBuffer* userTtyBuffer = (TtyUserBuffer*)argp;
|
||||
userTtyBuffer->columnCount = tty->columnCount;
|
||||
userTtyBuffer->lineCount = tty->lineCount;
|
||||
userTtyBuffer->currentColumn = tty->currentColumn;
|
||||
userTtyBuffer->currentLine = tty->currentLine;
|
||||
memcpy((uint8*)userTtyBuffer->buffer, tty->buffer, tty->columnCount * tty->lineCount * 2);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case TCGETS:
|
||||
{
|
||||
struct termios* term = (struct termios*)argp;
|
||||
|
||||
//Debug_PrintF("TCGETS\n");
|
||||
|
||||
memcpy((uint8*)term, (uint8*)&(tty->term), sizeof(struct termios));
|
||||
|
||||
return 0;//success
|
||||
}
|
||||
break;
|
||||
case TCSETS:
|
||||
case TCSETSW:
|
||||
break;
|
||||
case TCSETSF:
|
||||
{
|
||||
struct termios* term = (struct termios*)argp;
|
||||
|
||||
//Debug_PrintF("TCSETSF\n");
|
||||
|
||||
memcpy((uint8*)&(tty->term), (uint8*)term, sizeof(struct termios));
|
||||
|
||||
return 0;//success
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int32 tty_read(File *file, uint32 size, uint8 *buffer)
|
||||
{
|
||||
enableInterrupts();
|
||||
|
||||
if (size > 0)
|
||||
{
|
||||
Tty* tty = (Tty*)file->node->privateNodeData;
|
||||
|
||||
if ((tty->term.c_lflag & ICANON) == ICANON)
|
||||
{
|
||||
while (TRUE)
|
||||
{
|
||||
for (int i = 0; i < tty->lineBufferIndex; ++i)
|
||||
{
|
||||
char chr = tty->lineBuffer[i];
|
||||
|
||||
if (chr == '\n')
|
||||
{
|
||||
int bytesToCopy = MIN(tty->lineBufferIndex, size);
|
||||
|
||||
if (bytesToCopy >= tty->term.c_cc[VMIN])
|
||||
{
|
||||
tty->lineBufferIndex = 0;
|
||||
memcpy(buffer, tty->lineBuffer, bytesToCopy);
|
||||
|
||||
return bytesToCopy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file->thread->state = TS_WAITIO;
|
||||
file->thread->state_privateData = tty;
|
||||
halt();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (TRUE)
|
||||
{
|
||||
uint32 neededSize = tty->term.c_cc[VMIN];
|
||||
uint32 bufferLen = FifoBuffer_getSize(tty->keyBuffer);
|
||||
|
||||
if (bufferLen >= neededSize)
|
||||
{
|
||||
int readSize = FifoBuffer_dequeue(tty->keyBuffer, buffer, MIN(bufferLen, size));
|
||||
|
||||
return readSize;
|
||||
}
|
||||
|
||||
file->thread->state = TS_WAITIO;
|
||||
file->thread->state_privateData = tty;
|
||||
halt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int32 write(Tty* tty, uint32 size, uint8 *buffer)
|
||||
{
|
||||
buffer[size] = '\0';
|
||||
|
||||
Tty_PutText(tty, (const char*)buffer);
|
||||
|
||||
if (gActiveTty == tty)
|
||||
{
|
||||
if (gActiveTty->flushScreen)
|
||||
{
|
||||
gActiveTty->flushScreen(gActiveTty);
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static int32 tty_write(File *file, uint32 size, uint8 *buffer)
|
||||
{
|
||||
return write(file->node->privateNodeData, size, buffer);
|
||||
}
|
||||
|
||||
static void setActiveTty(Tty* tty)
|
||||
{
|
||||
gActiveTty = tty;
|
||||
|
||||
Gfx_Fill(0xFFFFFFFF);
|
||||
|
||||
if (tty->flushScreen)
|
||||
{
|
||||
tty->flushScreen(tty);
|
||||
}
|
||||
|
||||
//Serial_PrintF("line:%d column:%d\r\n", gActiveTty->currentLine, gActiveTty->currentColumn);
|
||||
}
|
||||
|
||||
BOOL isValidTTY(Tty* tty)
|
||||
{
|
||||
List_Foreach(n, gTtyList)
|
||||
{
|
||||
if (n->data == tty)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static uint8 getCharacterForScancode(KeyModifier modifier, uint8 scancode)
|
||||
{
|
||||
//return gKeyboardLayout[scancode];
|
||||
if ((modifier & KM_LeftShift) == KM_LeftShift || (modifier & KM_RightShift) == KM_RightShift)
|
||||
{
|
||||
return gKeyShiftMap[scancode];
|
||||
}
|
||||
|
||||
return gKeyMap[scancode];
|
||||
}
|
||||
|
||||
static void applyModifierKeys(KeyModifier modifier, uint8 scancode)
|
||||
{
|
||||
if ((modifier & KM_Ctrl) == KM_Ctrl)
|
||||
{
|
||||
int ttyIndex = scancode - KEY_F1;
|
||||
//printkf("TTY:%d\n", ttyIndex);
|
||||
int ttyCount = List_GetCount(gTtyList);
|
||||
if (ttyIndex >= 0 && ttyIndex < ttyCount)
|
||||
{
|
||||
int i = 0;
|
||||
List_Foreach(n, gTtyList)
|
||||
{
|
||||
if (ttyIndex == i)
|
||||
{
|
||||
setActiveTty(n->data);
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void processScancode(uint8 scancode)
|
||||
{
|
||||
uint8 lastBit = scancode & 0x80;
|
||||
|
||||
scancode &= 0x7F;
|
||||
|
||||
if (lastBit)
|
||||
{
|
||||
//key release
|
||||
|
||||
switch (scancode)
|
||||
{
|
||||
case KEY_LEFTSHIFT:
|
||||
gKeyModifier &= ~KM_LeftShift;
|
||||
break;
|
||||
case KEY_RIGHTSHIFT:
|
||||
gKeyModifier &= ~KM_RightShift;
|
||||
break;
|
||||
case KEY_CTRL:
|
||||
gKeyModifier &= ~KM_Ctrl;
|
||||
break;
|
||||
case KEY_ALT:
|
||||
gKeyModifier &= ~KM_Alt;
|
||||
break;
|
||||
}
|
||||
|
||||
//Screen_PrintF("released: %x (%d)\n", scancode, scancode);
|
||||
}
|
||||
else
|
||||
{
|
||||
//key pressed
|
||||
|
||||
switch (scancode)
|
||||
{
|
||||
case KEY_LEFTSHIFT:
|
||||
gKeyModifier |= KM_LeftShift;
|
||||
break;
|
||||
case KEY_RIGHTSHIFT:
|
||||
gKeyModifier |= KM_RightShift;
|
||||
break;
|
||||
case KEY_CTRL:
|
||||
gKeyModifier |= KM_Ctrl;
|
||||
break;
|
||||
case KEY_ALT:
|
||||
gKeyModifier |= KM_Alt;
|
||||
break;
|
||||
}
|
||||
|
||||
//Screen_PrintF("pressed: %x (%d)\n", scancode, scancode);
|
||||
|
||||
applyModifierKeys(gKeyModifier, scancode);
|
||||
}
|
||||
}
|
17
kernel.soso/ttydriver.h
Normal file
17
kernel.soso/ttydriver.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef TTYDRIVER_H
|
||||
#define TTYDRIVER_H
|
||||
|
||||
#include "common.h"
|
||||
#include "tty.h"
|
||||
#include "fs.h"
|
||||
|
||||
void initializeTTYs(BOOL graphicMode);
|
||||
Tty* getActiveTTY();
|
||||
|
||||
void sendKeyInputToTTY(Tty* tty, uint8 scancode);
|
||||
|
||||
BOOL isValidTTY(Tty* tty);
|
||||
|
||||
FileSystemNode* createPseudoTerminal();
|
||||
|
||||
#endif // TTYDRIVER_H
|
18
kernel.soso/utils.asm
Normal file
18
kernel.soso/utils.asm
Normal file
|
@ -0,0 +1,18 @@
|
|||
[GLOBAL readEip]
|
||||
readEip:
|
||||
pop eax
|
||||
jmp eax
|
||||
|
||||
[GLOBAL disablePaging]
|
||||
disablePaging:
|
||||
mov edx, cr0
|
||||
and edx, 0x7fffffff
|
||||
mov cr0, edx
|
||||
ret
|
||||
|
||||
[GLOBAL enablePaging]
|
||||
enablePaging:
|
||||
mov edx, cr0
|
||||
or edx, 0x80000000
|
||||
mov cr0, edx
|
||||
ret
|
63
kernel.soso/vbe.h
Normal file
63
kernel.soso/vbe.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
#ifndef VBE_H
|
||||
#define VBE_H
|
||||
|
||||
typedef struct {
|
||||
/* Mandatory information for all VBE revisions */
|
||||
uint16 ModeAttributes; /**< @brief mode attributes */
|
||||
uint8 WinAAttributes; /**< @brief window A attributes */
|
||||
uint8 WinBAttributes; /**< @brief window B attributes */
|
||||
uint16 WinGranularity; /**< @brief window granularity */
|
||||
uint16 WinSize; /**< @brief window size */
|
||||
uint16 WinASegment; /**< @brief window A start segment */
|
||||
uint16 WinBSegment; /**< @brief window B start segment */
|
||||
void* WinFuncPtr; /**< @brief real mode/far pointer to window function */
|
||||
uint16 BytesPerScanLine; /**< @brief bytes per scan line */
|
||||
|
||||
/* Mandatory information for VBE 1.2 and above */
|
||||
|
||||
uint16 XResolution; /**< @brief horizontal resolution in pixels/characters */
|
||||
uint16 YResolution; /**< @brief vertical resolution in pixels/characters */
|
||||
uint8 XCharSize; /**< @brief character cell width in pixels */
|
||||
uint8 YCharSize; /**< @brief character cell height in pixels */
|
||||
uint8 NumberOfPlanes; /**< @brief number of memory planes */
|
||||
uint8 BitsPerPixel; /**< @brief bits per pixel */
|
||||
uint8 NumberOfBanks; /**< @brief number of banks */
|
||||
uint8 MemoryModel; /**< @brief memory model type */
|
||||
uint8 BankSize; /**< @brief bank size in KB */
|
||||
uint8 NumberOfImagePages; /**< @brief number of images */
|
||||
uint8 Reserved1; /**< @brief reserved for page function */
|
||||
|
||||
/* Direct Color fields (required for direct/6 and YUV/7 memory models) */
|
||||
|
||||
uint8 RedMaskSize; /* size of direct color red mask in bits */
|
||||
uint8 RedFieldPosition; /* bit position of lsb of red mask */
|
||||
uint8 GreenMaskSize; /* size of direct color green mask in bits */
|
||||
uint8 GreenFieldPosition; /* bit position of lsb of green mask */
|
||||
uint8 BlueMaskSize; /* size of direct color blue mask in bits */
|
||||
uint8 BlueFieldPosition; /* bit position of lsb of blue mask */
|
||||
uint8 RsvdMaskSize; /* size of direct color reserved mask in bits */
|
||||
uint8 RsvdFieldPosition; /* bit position of lsb of reserved mask */
|
||||
uint8 DirectColorModeInfo; /* direct color mode attributes */
|
||||
|
||||
/* Mandatory information for VBE 2.0 and above */
|
||||
void* PhysBasePtr; /**< @brief physical address for flat memory frame buffer */
|
||||
uint8 Reserved2[4]; /**< @brief Reserved - always set to 0 */
|
||||
uint8 Reserved3[2]; /**< @brief Reserved - always set to 0 */
|
||||
|
||||
/* Mandatory information for VBE 3.0 and above */
|
||||
uint16 LinBytesPerScanLine; /* bytes per scan line for linear modes */
|
||||
uint8 BnkNumberOfImagePages; /* number of images for banked modes */
|
||||
uint8 LinNumberOfImagePages; /* number of images for linear modes */
|
||||
uint8 LinRedMaskSize; /* size of direct color red mask (linear modes) */
|
||||
uint8 LinRedFieldPosition; /* bit position of lsb of red mask (linear modes) */
|
||||
uint8 LinGreenMaskSize; /* size of direct color green mask (linear modes) */
|
||||
uint8 LinGreenFieldPosition; /* bit position of lsb of green mask (linear modes) */
|
||||
uint8 LinBlueMaskSize; /* size of direct color blue mask (linear modes) */
|
||||
uint8 LinBlueFieldPosition; /* bit position of lsb of blue mask (linear modes ) */
|
||||
uint8 LinRsvdMaskSize; /* size of direct color reserved mask (linear modes) */
|
||||
uint8 LinRsvdFieldPosition; /* bit position of lsb of reserved mask (linear modes) */
|
||||
uint32 MaxPixelClock; /* maximum pixel clock (in Hz) for graphics mode */
|
||||
uint8 Reserved4[190]; /* remainder of ModeInfoBlock */
|
||||
} __attribute__((packed)) vbe_mode_info_t;
|
||||
|
||||
#endif // VBE_H
|
580
kernel.soso/vmm.c
Normal file
580
kernel.soso/vmm.c
Normal file
|
@ -0,0 +1,580 @@
|
|||
#include "vmm.h"
|
||||
#include "common.h"
|
||||
#include "screen.h"
|
||||
#include "alloc.h"
|
||||
#include "isr.h"
|
||||
#include "process.h"
|
||||
#include "list.h"
|
||||
#include "debugprint.h"
|
||||
|
||||
uint32 *gKernelPageDirectory = (uint32 *)KERN_PAGE_DIRECTORY;
|
||||
uint8 gPhysicalPageFrameBitmap[RAM_AS_4M_PAGES / 8];
|
||||
uint8 gKernelPageHeapBitmap[RAM_AS_4K_PAGES / 8];
|
||||
|
||||
static int gTotalPageCount = 0;
|
||||
|
||||
static void handlePageFault(Registers *regs);
|
||||
static void syncPageDirectoriesKernelMemory();
|
||||
|
||||
void initializeMemory(uint32 high_mem)
|
||||
{
|
||||
int pg;
|
||||
unsigned long i;
|
||||
|
||||
registerInterruptHandler(14, handlePageFault);
|
||||
|
||||
gTotalPageCount = (high_mem * 1024) / PAGESIZE_4M;
|
||||
|
||||
for (pg = 0; pg < gTotalPageCount / 8; ++pg)
|
||||
{
|
||||
gPhysicalPageFrameBitmap[pg] = 0;
|
||||
}
|
||||
|
||||
for (pg = gTotalPageCount / 8; pg < RAM_AS_4M_PAGES / 8; ++pg)
|
||||
{
|
||||
gPhysicalPageFrameBitmap[pg] = 0xFF;
|
||||
}
|
||||
|
||||
//Pages reserved for the kernel
|
||||
for (pg = PAGE_INDEX_4M(0x0); pg < (int)(PAGE_INDEX_4M(RESERVED_AREA)); ++pg)
|
||||
{
|
||||
SET_PAGEFRAME_USED(gPhysicalPageFrameBitmap, pg);
|
||||
}
|
||||
|
||||
//Heap pages reserved
|
||||
for (pg = 0; pg < RAM_AS_4K_PAGES / 8; ++pg)
|
||||
{
|
||||
gKernelPageHeapBitmap[pg] = 0xFF;
|
||||
}
|
||||
|
||||
for (pg = PAGE_INDEX_4K(KERN_PD_AREA_BEGIN); pg < (int)(PAGE_INDEX_4K(KERN_PD_AREA_END)); ++pg)
|
||||
{
|
||||
SET_PAGEHEAP_UNUSED(pg * PAGESIZE_4K);
|
||||
}
|
||||
|
||||
//Identity map
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
gKernelPageDirectory[i] = (i * PAGESIZE_4M | (PG_PRESENT | PG_WRITE | PG_4MB));//add PG_USER for accesing kernel code in user mode
|
||||
}
|
||||
|
||||
for (i = 4; i < 1024; ++i)
|
||||
{
|
||||
gKernelPageDirectory[i] = 0;
|
||||
}
|
||||
|
||||
//Enable paging
|
||||
asm(" mov %0, %%eax \n \
|
||||
mov %%eax, %%cr3 \n \
|
||||
mov %%cr4, %%eax \n \
|
||||
or %2, %%eax \n \
|
||||
mov %%eax, %%cr4 \n \
|
||||
mov %%cr0, %%eax \n \
|
||||
or %1, %%eax \n \
|
||||
mov %%eax, %%cr0"::"m"(gKernelPageDirectory), "i"(PAGING_FLAG), "i"(PSE_FLAG));
|
||||
|
||||
initializeKernelHeap();
|
||||
}
|
||||
|
||||
char* getPageFrame4M()
|
||||
{
|
||||
int byte, bit;
|
||||
uint32 page = -1;
|
||||
|
||||
for (byte = 0; byte < RAM_AS_4M_PAGES / 8; byte++)
|
||||
{
|
||||
if (gPhysicalPageFrameBitmap[byte] != 0xFF)
|
||||
{
|
||||
for (bit = 0; bit < 8; bit++)
|
||||
{
|
||||
if (!(gPhysicalPageFrameBitmap[byte] & (1 << bit)))
|
||||
{
|
||||
page = 8 * byte + bit;
|
||||
SET_PAGEFRAME_USED(gPhysicalPageFrameBitmap, page);
|
||||
Debug_PrintF("DEBUG: got 4M on physical %x\n", page * PAGESIZE_4M);
|
||||
return (char *) (page * PAGESIZE_4M);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PANIC("Memory is full!");
|
||||
return (char *) -1;
|
||||
}
|
||||
|
||||
void releasePageFrame4M(uint32 p_addr)
|
||||
{
|
||||
Debug_PrintF("DEBUG: released 4M on physical %x\n", p_addr);
|
||||
|
||||
SET_PAGEFRAME_UNUSED(gPhysicalPageFrameBitmap, p_addr);
|
||||
}
|
||||
|
||||
uint32* getPdFromReservedArea4K()
|
||||
{
|
||||
int byte, bit;
|
||||
int page = -1;
|
||||
|
||||
//Screen_PrintF("DEBUG: getPdFromReservedArea4K() begin\n");
|
||||
|
||||
for (byte = 0; byte < RAM_AS_4K_PAGES / 8; byte++)
|
||||
{
|
||||
if (gKernelPageHeapBitmap[byte] != 0xFF)
|
||||
{
|
||||
for (bit = 0; bit < 8; bit++)
|
||||
{
|
||||
if (!(gKernelPageHeapBitmap[byte] & (1 << bit)))
|
||||
{
|
||||
page = 8 * byte + bit;
|
||||
SET_PAGEHEAP_USED(page);
|
||||
//Screen_PrintF("DEBUG: getPdFromReservedArea4K() found pageIndex:%d\n", page);
|
||||
return (uint32 *) (page * PAGESIZE_4K);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PANIC("Reserved Page Directory Area is Full!!!");
|
||||
return (uint32 *) -1;
|
||||
}
|
||||
|
||||
void releasePdFromReservedArea4K(uint32 *v_addr)
|
||||
{
|
||||
SET_PAGEHEAP_UNUSED(v_addr);
|
||||
}
|
||||
|
||||
uint32 *createPd()
|
||||
{
|
||||
int i;
|
||||
|
||||
uint32* pd = getPdFromReservedArea4K();
|
||||
|
||||
|
||||
for (i = 0; i < KERNELMEMORY_PAGE_COUNT; ++i)
|
||||
{
|
||||
pd[i] = gKernelPageDirectory[i];
|
||||
}
|
||||
|
||||
|
||||
for (i = KERNELMEMORY_PAGE_COUNT; i < 1024; ++i)
|
||||
{
|
||||
pd[i] = 0;
|
||||
}
|
||||
|
||||
return pd;
|
||||
}
|
||||
|
||||
void destroyPd(uint32 *pd)
|
||||
{
|
||||
int startIndex = PAGE_INDEX_4M(USER_OFFSET);
|
||||
int lastIndex = PAGE_INDEX_4M(USER_OFFSET_END);
|
||||
|
||||
///we don't touch mmapped areas
|
||||
|
||||
for (int i = startIndex; i < lastIndex; ++i)
|
||||
{
|
||||
uint32 p_addr = pd[i] & 0xFFC00000;
|
||||
|
||||
if (p_addr)
|
||||
{
|
||||
releasePageFrame4M(p_addr);
|
||||
}
|
||||
|
||||
pd[i] = 0;
|
||||
}
|
||||
|
||||
releasePdFromReservedArea4K(pd);
|
||||
}
|
||||
|
||||
uint32 *copyPd(uint32* pd)
|
||||
{
|
||||
int i;
|
||||
|
||||
uint32* newPd = getPdFromReservedArea4K();
|
||||
|
||||
|
||||
for (i = 0; i < KERNELMEMORY_PAGE_COUNT; ++i)
|
||||
{
|
||||
newPd[i] = gKernelPageDirectory[i];
|
||||
}
|
||||
|
||||
disablePaging();
|
||||
|
||||
for (i = KERNELMEMORY_PAGE_COUNT; i < 1024; ++i)
|
||||
{
|
||||
newPd[i] = 0;
|
||||
|
||||
if ((pd[i] & PG_PRESENT) == PG_PRESENT)
|
||||
{
|
||||
uint32 pagePyhsical = pd[i] & 0xFFC00000;
|
||||
char* newPagePhysical = getPageFrame4M();
|
||||
|
||||
memcpy((uint8*)newPagePhysical, (uint8*)pagePyhsical, PAGESIZE_4M);
|
||||
|
||||
uint32 vAddr = (i * 4) << 20;
|
||||
|
||||
//Screen_PrintF("Copied page virtual %x\n", vAddr);
|
||||
|
||||
addPageToPd(newPd, (char*)vAddr, newPagePhysical, PG_USER);
|
||||
}
|
||||
}
|
||||
|
||||
enablePaging();
|
||||
|
||||
return newPd;
|
||||
}
|
||||
|
||||
//When calling this function:
|
||||
//If it is intended to alloc kernel memory, v_addr must be < KERN_HEAP_END.
|
||||
//If it is intended to alloc user memory, v_addr must be > KERN_HEAP_END.
|
||||
BOOL addPageToPd(uint32* pd, char *v_addr, char *p_addr, int flags)
|
||||
{
|
||||
uint32 *pde = NULL;
|
||||
|
||||
//Screen_PrintF("DEBUG: addPageToPd(): v_addr:%x p_addr:%x flags:%x\n", v_addr, p_addr, flags);
|
||||
|
||||
|
||||
int index = (((uint32) v_addr & 0xFFC00000) >> 22);
|
||||
pde = pd + index;
|
||||
if ((*pde & PG_PRESENT) == PG_PRESENT)
|
||||
{
|
||||
//Already assigned!
|
||||
Debug_PrintF("ERROR: addPageToPd(): pde:%x is already assigned!!\n", pde);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//Screen_PrintF("addPageToPd(): index:%d pde:%x\n", index, pde);
|
||||
|
||||
*pde = ((uint32) p_addr) | (PG_PRESENT | PG_4MB | PG_WRITE | flags);
|
||||
//Screen_PrintF("pde:%x *pde:%x\n", pde, *pde);
|
||||
|
||||
SET_PAGEFRAME_USED(gPhysicalPageFrameBitmap, PAGE_INDEX_4M((uint32)p_addr));
|
||||
|
||||
asm("invlpg %0"::"m"(v_addr));
|
||||
|
||||
if (v_addr <= (char*)(KERN_HEAP_END - PAGESIZE_4M))
|
||||
{
|
||||
if (pd == gKernelPageDirectory)
|
||||
{
|
||||
syncPageDirectoriesKernelMemory();
|
||||
}
|
||||
else
|
||||
{
|
||||
PANIC("Attemped to allocate kernel memory to a page directory which is not the kernel page directory!!!\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pd == gKernelPageDirectory)
|
||||
{
|
||||
//No panic here. Because we allow kernel to map anywhere!
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL removePageFromPd(uint32* pd, char *v_addr, BOOL releasePageFrame)
|
||||
{
|
||||
int index = (((uint32) v_addr & 0xFFC00000) >> 22);
|
||||
uint32* pde = pd + index;
|
||||
if ((*pde & PG_PRESENT) == PG_PRESENT)
|
||||
{
|
||||
uint32 p_addr = *pde & 0xFFC00000;
|
||||
|
||||
if (releasePageFrame)
|
||||
{
|
||||
releasePageFrame4M(p_addr);
|
||||
}
|
||||
|
||||
*pde = 0;
|
||||
|
||||
asm("invlpg %0"::"m"(v_addr));
|
||||
|
||||
if (v_addr <= (char*)(KERN_HEAP_END - PAGESIZE_4M))
|
||||
{
|
||||
if (pd == gKernelPageDirectory)
|
||||
{
|
||||
syncPageDirectoriesKernelMemory();
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void syncPageDirectoriesKernelMemory()
|
||||
{
|
||||
//get page directory list
|
||||
//it can be easier to traverse proccesses(and access its pd) here
|
||||
for (int byte = 0; byte < RAM_AS_4M_PAGES / 8; byte++)
|
||||
{
|
||||
if (gKernelPageHeapBitmap[byte] != 0xFF)
|
||||
{
|
||||
for (int bit = 0; bit < 8; bit++)
|
||||
{
|
||||
if ((gKernelPageHeapBitmap[byte] & (1 << bit)))
|
||||
{
|
||||
int page = 8 * byte + bit;
|
||||
|
||||
uint32* pd = (uint32*)(page * PAGESIZE_4K);
|
||||
|
||||
for (int i = 0; i < KERNELMEMORY_PAGE_COUNT; ++i)
|
||||
{
|
||||
pd[i] = gKernelPageDirectory[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 getTotalPageCount()
|
||||
{
|
||||
return gTotalPageCount;
|
||||
}
|
||||
|
||||
uint32 getUsedPageCount()
|
||||
{
|
||||
int count = 0;
|
||||
for (int i = 0; i < gTotalPageCount; ++i)
|
||||
{
|
||||
if(IS_PAGEFRAME_USED(gPhysicalPageFrameBitmap, i))
|
||||
{
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
uint32 getFreePageCount()
|
||||
{
|
||||
return gTotalPageCount - getUsedPageCount();
|
||||
}
|
||||
|
||||
static void printPageFaultInfo(uint32 faultingAddress, Registers *regs)
|
||||
{
|
||||
int present = regs->errorCode & 0x1;
|
||||
int rw = regs->errorCode & 0x2;
|
||||
int us = regs->errorCode & 0x4;
|
||||
int reserved = regs->errorCode & 0x8;
|
||||
int id = regs->errorCode & 0x10;
|
||||
|
||||
printkf("Page fault!!! When trying to %s %x - IP:%x\n", rw ? "write to" : "read from", faultingAddress, regs->eip);
|
||||
printkf("The page was %s\n", present ? "present" : "not present");
|
||||
|
||||
if (reserved)
|
||||
{
|
||||
printkf("Reserved bit was set\n");
|
||||
}
|
||||
|
||||
if (id)
|
||||
{
|
||||
printkf("Caused by an instruction fetch\n");
|
||||
}
|
||||
|
||||
printkf("CPU was in %s\n", us ? "user-mode" : "supervisor mode");
|
||||
}
|
||||
|
||||
static void handlePageFault(Registers *regs)
|
||||
{
|
||||
// A page fault has occurred.
|
||||
|
||||
// The faulting address is stored in the CR2 register.
|
||||
uint32 faultingAddress;
|
||||
asm volatile("mov %%cr2, %0" : "=r" (faultingAddress));
|
||||
|
||||
//Debug_PrintF("page_fault()\n");
|
||||
//Debug_PrintF("stack of handler is %x\n", &faultingAddress);
|
||||
|
||||
Thread* faultingThread = getCurrentThread();
|
||||
if (NULL != faultingThread)
|
||||
{
|
||||
Thread* mainThread = getMainKernelThread();
|
||||
|
||||
if (mainThread == faultingThread)
|
||||
{
|
||||
printPageFaultInfo(faultingAddress, regs);
|
||||
|
||||
PANIC("Page fault in Kernel main thread!!!");
|
||||
}
|
||||
else
|
||||
{
|
||||
printPageFaultInfo(faultingAddress, regs);
|
||||
|
||||
Debug_PrintF("Faulting thread is %d\n", faultingThread->threadId);
|
||||
|
||||
if (faultingThread->userMode)
|
||||
{
|
||||
Debug_PrintF("Destroying process %d\n", faultingThread->owner->pid);
|
||||
|
||||
destroyProcess(faultingThread->owner);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug_PrintF("Destroying kernel thread %d\n", faultingThread->threadId);
|
||||
|
||||
destroyThread(faultingThread);
|
||||
}
|
||||
|
||||
waitForSchedule();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printPageFaultInfo(faultingAddress, regs);
|
||||
|
||||
PANIC("Page fault!!!");
|
||||
}
|
||||
}
|
||||
|
||||
void initializeProcessMmap(Process* process)
|
||||
{
|
||||
int page = 0;
|
||||
|
||||
for (page = 0; page < RAM_AS_4M_PAGES / 8; ++page)
|
||||
{
|
||||
process->mmappedVirtualMemory[page] = 0xFF;
|
||||
}
|
||||
|
||||
//Virtual pages reserved for mmap
|
||||
for (page = PAGE_INDEX_4M(USER_OFFSET_MMAP); page < (int)(PAGE_INDEX_4M(USER_OFFSET_MMAP_END)); ++page)
|
||||
{
|
||||
//? printkf("reserving for mmap: %x\n", page*PAGESIZE_4M);
|
||||
SET_PAGEFRAME_UNUSED(process->mmappedVirtualMemory, page * PAGESIZE_4M);
|
||||
}
|
||||
}
|
||||
|
||||
//this functions uses either pAddress or pAddressList
|
||||
//both of them must not be null!
|
||||
void* mapMemory(Process* process, uint32 nBytes, uint32 pAddress, List* pAddressList)
|
||||
{
|
||||
if (nBytes == 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int pageIndex = 0;
|
||||
|
||||
int neededPages = (nBytes / PAGESIZE_4M) + 1;
|
||||
|
||||
if (pAddressList)
|
||||
{
|
||||
if (List_GetCount(pAddressList) < neededPages)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if (0 == pAddress)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int foundAdjacent = 0;
|
||||
|
||||
uint32 vMem = 0;
|
||||
|
||||
for (pageIndex = PAGE_INDEX_4M(USER_OFFSET_MMAP); pageIndex < (int)(PAGE_INDEX_4M(USER_OFFSET_MMAP_END)); ++pageIndex)
|
||||
{
|
||||
if (IS_PAGEFRAME_USED(process->mmappedVirtualMemory, pageIndex))
|
||||
{
|
||||
foundAdjacent = 0;
|
||||
vMem = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (0 == foundAdjacent)
|
||||
{
|
||||
vMem = pageIndex * PAGESIZE_4M;
|
||||
}
|
||||
++foundAdjacent;
|
||||
}
|
||||
|
||||
if (foundAdjacent == neededPages)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Debug_PrintF("mapMemory: needed:%d foundAdjacent:%d vMem:%x\n", neededPages, foundAdjacent, vMem);
|
||||
|
||||
if (foundAdjacent == neededPages)
|
||||
{
|
||||
uint32 p = 0;
|
||||
ListNode* pListNode = NULL;
|
||||
if (pAddressList)
|
||||
{
|
||||
pListNode = List_GetFirstNode(pAddressList);
|
||||
p = (uint32)(uint32*)pListNode->data;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = pAddress;
|
||||
}
|
||||
p = p & 0xFFC00000;
|
||||
uint32 v = vMem;
|
||||
for (int i = 0; i < neededPages; ++i)
|
||||
{
|
||||
addPageToPd(process->pd, (char*)v, (char*)p, PG_USER);
|
||||
|
||||
SET_PAGEFRAME_USED(process->mmappedVirtualMemory, PAGE_INDEX_4M(v));
|
||||
|
||||
v += PAGESIZE_4M;
|
||||
|
||||
if (pAddressList)
|
||||
{
|
||||
pListNode = pListNode->next;
|
||||
p = (uint32)(uint32*)pListNode->data;
|
||||
p = p & 0xFFC00000;
|
||||
}
|
||||
else
|
||||
{
|
||||
p += PAGESIZE_4M;
|
||||
}
|
||||
}
|
||||
|
||||
return (void*)vMem;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BOOL unmapMemory(Process* process, uint32 nBytes, uint32 vAddress)
|
||||
{
|
||||
if (nBytes == 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (vAddress < USER_OFFSET_MMAP)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int pageIndex = 0;
|
||||
|
||||
int neededPages = (nBytes / PAGESIZE_4M) + 1;
|
||||
|
||||
int startIndex = PAGE_INDEX_4M(vAddress);
|
||||
int endIndex = startIndex + neededPages;
|
||||
|
||||
BOOL result = FALSE;
|
||||
|
||||
for (pageIndex = startIndex; pageIndex < endIndex; ++pageIndex)
|
||||
{
|
||||
if (IS_PAGEFRAME_USED(process->mmappedVirtualMemory, pageIndex))
|
||||
{
|
||||
char* vAddr = (char*)(pageIndex * PAGESIZE_4M);
|
||||
|
||||
removePageFromPd(process->pd, vAddr, FALSE);
|
||||
|
||||
SET_PAGEFRAME_UNUSED(process->mmappedVirtualMemory, vAddr);
|
||||
|
||||
result = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
48
kernel.soso/vmm.h
Normal file
48
kernel.soso/vmm.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
#ifndef VMM_H
|
||||
#define VMM_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
typedef struct Process Process;
|
||||
typedef struct List List;
|
||||
|
||||
extern uint32 *gKernelPageDirectory;
|
||||
|
||||
extern uint8 gKernelPageHeapBitmap[];
|
||||
|
||||
|
||||
#define SET_PAGEFRAME_USED(bitmap, pageIndex) bitmap[((uint32) pageIndex)/8] |= (1 << (((uint32) pageIndex)%8))
|
||||
#define SET_PAGEFRAME_UNUSED(bitmap, p_addr) bitmap[((uint32) p_addr/PAGESIZE_4M)/8] &= ~(1 << (((uint32) p_addr/PAGESIZE_4M)%8))
|
||||
#define IS_PAGEFRAME_USED(bitmap, pageIndex) (bitmap[((uint32) pageIndex)/8] & (1 << (((uint32) pageIndex)%8)))
|
||||
|
||||
#define SET_PAGEHEAP_USED(pageIndex) gKernelPageHeapBitmap[((uint32) pageIndex)/8] |= (1 << (((uint32) pageIndex)%8))
|
||||
#define SET_PAGEHEAP_UNUSED(p_addr) gKernelPageHeapBitmap[((uint32) p_addr/PAGESIZE_4K)/8] &= ~(1 << (((uint32) p_addr/PAGESIZE_4K)%8))
|
||||
#define IS_PAGEHEAP_USED(pageIndex) (gKernelPageHeapBitmap[((uint32) pageIndex)/8] & (1 << (((uint32) pageIndex)%8)))
|
||||
|
||||
char* getPageFrame4M();
|
||||
void releasePageFrame4M(uint32 p_addr);
|
||||
|
||||
uint32 *getPdFromReservedArea4K();
|
||||
void releasePdFromReservedArea4K(uint32 *);
|
||||
|
||||
void initializeMemory(uint32 high_mem);
|
||||
|
||||
uint32 *createPd();
|
||||
void destroyPd(uint32 *);
|
||||
uint32 *copyPd(uint32* pd);
|
||||
|
||||
BOOL addPageToPd(uint32* pd, char *v_addr, char *p_addr, int flags);
|
||||
BOOL removePageFromPd(uint32* pd, char *v_addr, BOOL releasePageFrame);
|
||||
|
||||
void enablePaging();
|
||||
void disablePaging();
|
||||
|
||||
uint32 getTotalPageCount();
|
||||
uint32 getUsedPageCount();
|
||||
uint32 getFreePageCount();
|
||||
|
||||
void initializeProcessMmap(Process* process);
|
||||
void* mapMemory(Process* process, uint32 nBytes, uint32 pAddress, List* pAddressList);
|
||||
BOOL unmapMemory(Process* process, uint32 nBytes, uint32 vAddress);
|
||||
|
||||
#endif // VMM_H
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user