| Age | Commit message (Collapse) | Author |
|
Changed the type for block addresses from size_t to uint16_t.
Added the '%c' conversion specifier to vsprintf(), so that it can now
output individual characters passed as arguments.
Added a an errno.h header containing a list of commonly used error
codes, as well as a basic strerror() routine to fetch corresponding
human-readable strings from a table.
Implemented barebones floppy driver. Currently lacking many (essential)
features, see TODO notes in floppy.c for more details.
Buffer structs now have a b_present flag to indicate whether or not the
data section is populated, as well as a b_wait element, as a queue for
any tasks waiting on the buffer. All tasks waiting on a block wait in
this queue, however, the task that originally called the driver to read,
may wait in a separate queue maintained by the driver. This system may
change in the future, and will likely depend on how head scheduling is
implemented in the driver.
The buffer_get_block() routine is now publically available in
kernel/fs.h. It can be called to retrieve a block from the buffer cache
(if readily available), or from the specified block device otherwise.
This routine returns a pointer to the buffer containing the cache.
The block_read() function now passes arguments and return values to the
floppy driver regardless of the device specified. The block_write()
function now indicates an error condition by setting b_device to zero in
the allocated buffer structure, as no devices with write functionality
currently exist. This behaviour will be updated in future, as more block
devices are added.
The mount_root() function has been modified to call buffer_get_block(),
instead of calling block_read() directly. As of now, nothing should call
block_read() or block_write() directly, as those functions are intended
for use by the buffer subsystem only.
|
|
descriptor as their first parameter. read()/write() calls to descriptors
other than stdin/stdout respectively, are currently discared as the file
table has yet to be fully implemented.
|
|
inode in memory.
Added a jump instruction in front of the multiboot header so that the
kernel may be run as a binary image. The jump instruction will skip over
the multiboot header to the beginning of the kernel's startup procedure
in kboot.
Moved the call to initialize the timer to earlier in the boot sequence.
This is to allow for some drivers that may require it's functionality
during the startup to function properly.
Added functionality for the 'fast-gate' to the enable_a20 subroutine.
Now, if the keyboard controller method fails when enabling the gate, an
attempt is made to enable the A20 gate using the PS/2's fast-gate
interface. If this also fails, the kernel will panic.
Implemented TTY output for the console. The console is now TTY device 0
(the default for new userspace programs).
|
|
to make management/maintenance easier.
Defined the structures super_block and m_inode in kernel/fs.h for super
blocks and inodes respectively.
Added the new header file sys/stat.h which contains basic definitions
for inode types and permissions. These definitions will be required by
any functions handling m_inode structures.
Moved the sys_read and sys_write system calls to the filesystem's main
source file at kernel/fs/fs.c.
Added the file kernel/fs/mount.c which will contain the super-blocks
table as well as the function mount_root() which will attempt to mount
the root filesystem during boot. Eventually, this file will be expanded
to include a general-purpose mount function to mount any filesystem as
well as the system call handler for sys_mount.
Seperated block I/O functions into their own subsystem under
kernel/fs/block.c which currently supports two functions; block_read()
and block_write() to read and write blocks from block devices.
Currently, no device can be specified since the primary ATA master drive
is the only possible target. This will change in the future however.
Modified the hard disk driver's read and write functions to use
filesystem blocks rather than sectors as the units of transfer. This is
intended to keep the block I/O subsystem simple by ensuring a uniform
transfer unit is used across all block devices and drivers.
The hard disk driver is no longer initialized during the main boot
procedure. Instead, a call is made to the new function fs_init() which
will setup filesystem tables and structures, call hd_init() to
initialize the disk and finally, attempt to load the super-block for the
root filesystem.
The hard disk driver now stores the disk's size and sanity checks
addresses and sizes in read and write calls against this value.
|
|
Removed the rsputs() function in favour of calls to tty_write().
Corrected a bug in the serial driver and TTY subsystem where a full
buffer wouldn't be detected. This was caused by a missing set of
brackets on several operations involving the modulus operator.
Added the ability for the serial driver to automatically take data from
the TTY device's write buffer and push it to the serial port. This can
happen in one of two ways; 1) the TTY subsystem notifies the serial
driver of new data by calling the write() function pointer in the
tty_struct or, 2) the serial port issues an interrupt signalling that it
has finished sending data prompting the driver to check the buffers for
any more pending data.
|
|
the project.
Added the system call 'sys_panic' as well as the corresponding library
function panic() whose prototype is defined in unistd.h. This is to
allow userspace programs to deliberately crash the kernel for the
purpose of debugging.
Added the element 'write' as a function pointer in the tty_struct
structure. The purpose of this function pointer is to provide a means
for the TTY subsystem to notify the device driver of any newly added
data to the write queue.
Added the tty_write() function to the TTY subsystem. This function will
copy data provided by the user into the specified TTY device's write
queue, blocking if the queue's buffer is full. tty_write() will then
call the driver's write() function to notify it of new data.
Added the rsint_tx() function to the serial driver to handle transmit
interrupts by re-supplying the UART's transmit FIFO.
|
|
interrupts respectively.
Added the scheduling primatives sleep_on() and interruptible_sleep_on()
to sched.c. sleep_on() adds the current task to the specified wait queue
then puts it into an uninterruptible sleep. Wait queues are formed by
having each waiting task holding a pointer to the waiting task that
preceeded it, then placing a pointer to it's own task struct into the
queue's head pointer. When the first task in the queue is awoken, it
wakes the preceeding task prior to returning from sleep_on(). The
function interruptible_sleep_on() works in a similar manner, however
when a task is awoken from interruptible_sleep_on(), it wakes up the
first task in it's wait queue, then puts itself back to sleep. The
purpose of this, is to automatically dissolve and reform the wait queue.
As each task in the queue is a awakened, tasks that need to handle
signals will do so whilst tasks that have no pending signals and are
still waiting will place themselves back into the wait queue by calling
interruptible_sleep_on() again. Whilst this method isn't the most
effiecient due to waking every task in a wait queue because one received
a signal, it does avoid the mess and complications involved in
maintaining the queue as an array or linked list.
Added prototypes for the scheduling primatives wake_up(), sleep_on() and
interruptible_sleep_on() to kernel/sched.h so that these functions may
be used throughout the kernel.
Added code to temporaily re-enable interrupts in reschedule() so that
the idle loop may continue to function even if interrupts were disabled
prior to calling the function.
|
|
printk() to notify the user of the kernel panic. This resulted in a
system call being made to the kernel itself and the machine not fully
halting.
Fixed an issue with the serial driver in which the functions rsputs()
and rsread() will still attempt a data transfer even if serial_init()
failed to detect and initialize a serial port.
Added the ability for tasks to be interrupted whilst reading from the
serial port. This was done by putting the task into TSTATE_INTERRUPTIBLE
instead of TSTATE_UNINTERRUPTIBLE when waiting for data in the serial
buffer. Furthermore, a check was introduced after the task wakes up to
see if any data was put in the buffer, or if the task was awoken by
another source.
Changed the type pid_t from an unsigned 16-bit integer to a signed
16-bit integer. This was done to make passing PID's to certain functions
easier.
Added the new system call sys_kill which will allow one process to send
a signal to another.
Added the kill_proc() function to sched.c to kill a process. Currently,
this works by nullifying the PID field in the process' task structure,
marking all the pages mapped to it's address space as free for use, then
calling the scheduler to switch to another runnable task (or to idle).
Modified the default signal handler within the kernel to now handle the
SIGKILL signal by calling kill_proc().
|
|
Added the _syscall2 macro to unistd.h to facilitate system calls that
require two arguments to be passed.
Modified the ATA driver to simply abort initialisation if a drive is not
found, or cannot be configured. This will allow the kernel to function
on a diskless system without invoking panic() unnecessarily.
Added the functions irq_enable() and irq_disable() to asm/interrupt.h to
make it easier for C code to mask and unmask IRQ's on each PIC.
Moved the declaration for rsputs() from kernel/con.h to the new
kernel/serial.h file since this is a function provided by the serial
driver.
Implemented a basic I/O input framework. This involves the new system
call sys_read, which takes an I/O read request and directs it to the
appropriate kernel handler function depending on the calling process'
ctty value. This mechanism is identical to the sys_puts system call.
Added the rsread() function to service sys_read calls from processes
whose ctty value is equal to 1. This function will continually copy data
from the serial buffer to the location specified. If there is not a
sufficient amount of new data in the buffer to satisfy the request, the
process is put into the TSTATE_UNINTERRUPTIBLE state and the scheduler
is called to switch tasks. Prior to calling the scheduler, the function
will set the waiting_task pointer to the calling process. This pointer
will later be used by the interrupt handler to wake the process when new
data arrives.
Added an interrupt handler to service the IRQ4 (UART) interrupt. This
subroutine is a stub which will save the machine's state then transfer
control to rs_handler() in serial.c which will read bytes from the
serial port and place them in a buffer. Before returning, rs_handler()
checks the waiting_task pointer to see if a task is waiting for the
newly received data and if so, it sets the task's state to
TSTATE_RUNNING before resetting the pointer to NULL and returning.
Ideally, the scheduler should be invoked at this point to select another
task but since our basic round-robin scheduler currently has no concept
of task priorities (and for the sake of simplicity), we will avoid
invoking the scheduler in response to interrupts for now.
|
|
Implemented the sprintf() library function in lib/stdio.c which uses the
vsprintf() function.
Implemented a very primative controlling TTY for each process. This is
achieved by a switch in the sys_puts system call which uses the 'ctty'
element of the process' task structure to determine an appropriate I/O
channel. A negative ctty value doesn't equate to any I/O channel
effectively disabling the process' output.
Added the sys_ctty system call which allows a process to set it's own
ctty value.
Removed the sys_rsputs system call. Output to serial is now performed by
the process first setting it's ctty value to 1, then invoking sys_puts.
|
|
a pointer to the saved state information to check_signals(). This bug
would have only manifested itself if multiple signals were to be
processed (sigret) or if a signal had been set during the handling of a
timer interrupt (tick_handler) and *ONLY* if switching to the user's own
handler since the state information is not needed to invoke the kernel's
default signal handler.
Implemented alarms for userspace processes. This required significant
modification of the scheduler algorithm. When idling waiting for a
process that can run, the scheduler now continually checks the alarms
and signals of each process and updates their state accordingly.
Implemented the sys_alarm system call to set the new 'alarm' field for
the calling process.
Created the sys_pause system call which changes the state of the calling
process to TSTATE_INTERRUPTIBLE, effectively removing it from the
scheduler's run queue, putting it to sleep until a signal arrives.
|
|
the IDT. This function takes the same parameters as register_isr() which
creates interrupt gate entries in the IDT.
The register_isr() function now sets the gate type to 0x0E regardless of
what was already in the descriptor. This is to break reliance on the IDT
already being initialized to a known state as well as avoiding conflicts
with the new register_trap() function.
Added declaration for the 'ticks' variable in kernel/sched.h so that
it's value may be used throughout the kernel.
Changed the system call gate to a trap gate. This means that interrupts
will not be disabled prior to entry into the system call handler. This
will allow hardware functions such as the timer to operate continuously
even if the user makes a system call.
Added checks to the timer interrupt handler. These checks prevent the
scheduler from being called if the interrupt occurred during kernel mode
execution. The idea here, is that the timer interrupt handler only
services the hardware (increments the tick count and sends an EOI to the
PIC's) if a system call was already running in the kernel. The system
call handler has also been expanded to check if the timer fired prior to
returning to userspace. If the timer did fire, the syscall handler will
invoke the scheduler (as the timer handler would have), so that it can
decide if it's time to switch tasks.
|
|
prior to return. This meant that switching to the same task did not
abort properly as the incorrect return address was popped off the stack.
Fixed a bug where the task register was not initialized before the
scheduler. This meant that on the first task switch, the CPU would dump
it's current state to a random address (0 most likely), potentially
corrupting important data. This has been corrected by introducing a
'garbage TSS' (and associated descriptor in the GDT) which is selected
before the scheduler is initialized as a safe place for the data to be
written.
Modified the scheduler so that it now waits indefinitely until a task
becomes ready to run. This fixes the possible bug where the scheduler
won't re-schedule the currently running task if it is the only task on
the system.
Add signal handling capabilities to the kernel. The bulk of this is
present in the subroutine check_signals() defined in traps.s. This
function is called on every timer tick and system call prior to
userspace return. The subroutine operates by pushing fake state
information onto the kernel's stack, then using it to return to
userspace. Prior to this, the subroutine pushes the return address
0xFFFFE000 onto the user's stack. This address corresponds to the
unmapped page located between the top of the user's stack (lower) and
the kernel's stack page (upper). When the user's signal handler tries to
return, it will cause a page fault that will be used as a notification
mechanism to inform the kernel that the signal handler is done. The
kernel will then switch to the originally pushed state information and
use it to return the task to the original execution state. Due to it's
nature, check_signals() must only be called prior to exiting the kernel
since it may not return.
Added the header file 'signal.h' which defines (most) of the POSIX
signals as well as the prototype for the signal() function.
Added the 'signal' element to the task structure. This field is a bitmap
of all currently pending signals.
Added the 'sig_handlers' element to the task structure. This is an array
of all user-defined signal handlers. Currently, a value of 0 indicates
the default handler should be used whilst any other value is considered
to be the address of a userspace signal handler. The ability to ignore a
signal is not yet present but will be added sometime soon.
Added the sys_signal system call to register a signal.
Added the stub function sighandler_default() to sched.c which handles
all signals not caught by the user.
|
|
each structure has a TSS inside, as well as several descriptor entries
in the GDT pointing to each task's TSS. Task switching is performed in
hardware by means of far jumping to the new task's TSS descriptor in the
GDT. Task states are saved manually by copying the saved state from the
interrupt handler's stack, back into the task's TSS.
Added the function save_state() to sched.c which can be called from
assembly to copy the state information of the suspended task from the
current stack, to it's respective task structure. NOTE: this assumes
that the pointer cstate has been set ahead of time to point to the state
information on the stack, and that the pointer ctask has not yet been
modified.
Added the function reschedule() which is currently called from the
timer's tick handler. Currently, this function merely alternates between
the two tasks created in sched_init(), but in future, will be expanded
to decided independently which task will run next.
The function userspace_init() was renamed to the more appropriate
sched_init().
Moved most of the code from the original userspace_init() to the new
function create_proc() which sets up a virtual address space and state
information, copies the specified binary into the new address space,
then returns a pointer to the newly created tasks entry in the task
table.
Defined the type pid_t in unistd.h as a 16-bit unsigned integer.
Added two new debugging system calls for checking which task is
currently active. The getpid() system calls returns the caller's PID
whilst the getpdir() call returns the physical location of the caller's
page directory (the value of CR3). The getpdir() call can be used as a
fallback to determine which task is *actually* running if the
information in ctask or the getpid() call is faulty.
Added two new subroutines; set_tss() and clear_tss() (whose prototypes
are defined in asm/system.h) for managing the task-state descriptor
entries in the GDT. set_tss() initializes a TSS descriptor and sets it's
base pointer to the supplied TSS pointer whilst clear_tss() simply marks
a TSS descriptor as 'not present' without clearing it.
|
|
vsprintf() function to render formatted strings and then the puts system
call to output them.
Moved the vsprintf() function from the kernel to the library.
Furthermore, the prototype for the function has been moved from the
kernel's headers, to the new header file stdio.h.
Renamed the kernel's internal printf() function to printk() in order to
avoid confusion with the library provided function.
Renamed the sys_print system call to the more appropriate name,
sys_puts.
Added a new system call sys_time, which returns the system's uptime in
seconds. This is mainly for testing the userspace binary and will not be
permanent.
Added the file time.c to the library which contains the caller for
sys_time and a helper routine sleep() which delays execution for the
specified number of seconds. The new header file time.h contains
prototypes for both these functions as well as the definition for the
type time_t.
Fixed a bug in which the value of EAX was not properly passed to the
system call handler, resulting in the wrong system call being executed.
This was caused by the code in the SAVE macro not properly preserving
the value.
Fixed a bug in which the value of EAX was not preserved during a return
from system call, but rather restored with the original EAX value prior
to the call. As a result, system call return codes were not properly
passed. This has been corrected by introducing a new macro RESTORE_SYS
which carries out the same restore operations, but maintains EAX prior
to the return.
|
|
is produced. This may change later.
Added the new directory 'lib' to the source tree which build lib.a, an
archive containing common library routines for both the kernel and
userspace code to use.
Added the file string.c to the lib directory (as well as the appropriate
headers in /include) which provides some basic functions from the
standard C string library.
Added a physical memory manager which is now located in memory.c. This
memory manager tracks free pages from 1MB-8MB with a simple table and
allocates memory in blocks of 4KB pages. Multiple pages can be allocated
in which they are returned as a linked list.
Added a 'page window' in memory.c which allows the temporary mapping of
a single page at a time into the current address space.
Moved all paging routines that were previously located in page.s over to
memory.c where they have been re-implemented as a mixture of C and
inline assembly.
Moved the primative userspace routines from usrspace.s over to the new
sched.c. The only remaining routine, usrcall is now located in asm.s as
'switch_to' which takes two arguments, pointers to the task structure
and task state structure of the new task which is being switched to.
Pages for userspace are now allocated dynamically. The user binary is
loaded in at 1GB upwards. The user stack is located at the end of the
4GB address space with the lower 1GB being reserved for the kernel.
Updated the link.ld file for the userspace binary to include the new
starting address 0x40000000 (1GB).
Renamed the symbols for the user binary blob to make them shorter.
|
|
assembly function register_isr making it usable within the C portions of
the source.
Added a new file panic.s with the function panic that will print a panic
message, disable interrupts and halt the system.
Created the skeleton framework for paging in the new file page.s. The
new function paging_init (called in kboot) will setup a simple page
directory with two tables covering all addresses 0-8MB. It will also
mark pages from 0-1MB as 'supervisor-only' to protect the kernel. NOTE:
The function paging_init must be called before initialising the IDT as
it does not disable interrupts!
Modified the page fault handler to print the offending linear address
along with the supplied error code. Following that, the handler will
initiate a kernel panic. This function (along with panic) assumes
console I/O to be operational.
Modified the userspace test code to deliberately intiate a page fault by
accessing an unmapped page.
|
|
Hopefully further separation will help to keep the code readable and
understandable.
|