there's no need to waste space for a error buffer in the Segio
structure, as the segmentio kproc will be waiting for the next
command after an error and will not overwite it until we issue
another command.
devproc's procctlmemio() did not handle physical segment
types correctly, as it assumed it can just kmap() the page
in question and write to it. physical segments however
need to be mapped uncached but kmap() will always map
cached as it assumes normal memory. on some machines with
aliasing memory with different cache attributes
leads to undefined behaviour!
we borrow the code from devsegment and provide a generic
segio() function to read and write user segments which
handles all the cases without using kmap by just spawning
a kproc that attaches the segment that needs to be read
from or written to. fault() will setup the right mmu
attributes for us. it will also properly flush pages for
segments that maintain instruction cache when written.
however, tlb's have to be flushed separately.
segio() is used for devsegment and devproc now, which
also allows for simplification of fixfault() as there is no
special error handling case anymore as fixfault() is now
called from faulting process *only*.
reads from /proc/$pid/mem can now span multiple pages.
code like "return g->dlen;" is wrong as we do not hold the
qlock of the global segment. another process could come in
and override g->dlen making us return the wrong byte count.
avoid copying when we already got a kernel address (kernel memory
is the same on processes) which is the case with bread()/bwrite().
this is the same optimization that devsd does.
also avoid allocating/freeing and copying while holding the qlock.
when we copy to/from user memory, we might fault preventing
others from accessing the segment while fault handling is in
progress.
walking the freelist for every page is too slow. as we
are freeing a range, we can do a single pass unlinking all
pages in our range and at the end, check if all pages
where freed, if not put the pages that we did free back
and retry, otherwise we'r done.
fixed segments are continuous in physical memory but
allocated in user pages. unlike shared segments, they
are not allocated on demand but the pages are allocated
on creation time (devsegment). fixed segments are
never swapped out, segfreed or resized and can only be
destroyed as a whole.
the physical base address can be discovered by userspace
reading the ctl file in devsegment.
when we trim the front of a block with freefromfront(),
the block magic of the back was not initialized which
could sometimes trigger the assert in blocksetsize()
to fail. fix is to just move the initialization of the
magic field before the blocksetsize() call.
the second b->magic = UNALLOC_MAGIC isnt really required
but just done for consistency with the trim() code above.
when we get an i/o error, always call hdrecover() which
will reset the port and reinitialize the interface of
the calling processes endpoint.
handle the case when we have multi-function device with
multiple reader procs in hdrecover(). the sequence is
as follows:
1) any of the reader procs encounters i/o error and calls hdrecover(),
acquires qlock and initiates port reset.
2) any other readerprocs will now encounter i/o error (due to reset) and also call
hdrecover() but will be waiting on the qlock for reset to complete.
3) first process completes reset and reinitializes its interface with setproto()
and then releases the qlock for the other readers todo the same.
this avoids listing the upper half of 64-bit membars
in Pcidev.mem[] array avoiding potential confusion
in drivers.
we also check if the upper half is programmed to zero
by bios and otherwise zap the entry in Pcidev.mem[]
and print a warning.
qemu puts multiboot data after the end of the kernel image, so
to be able to KADDR() that memory early, we extend the initial
identity mapping by 16K. right now we just got lucky with
the pc kernel as it rounds the map to 4MB pages.
when we switch to graphics mode, we do not want graphical arcs console
to print on the screen anymore as it assumes 8bit color mode and just
messes up the screen on kernel prints.
fixes bug with libmemdraw where the linker would hoist
the final ADD $const, SP at the end over loads from the
stack causing the front to fall off once a interrupt hits.
GEVector() saves the exception return PC in Ureg.r27 which needs
to be preserved.
there should be no reason for the user to change the status
register from noted() eigther, so we now just use setregisters()
in noted() to restore previous general purpose registers. this
means that CU1 will always be off after noted() because notify()
has disabled the FPU on entry and set fpstatus to FPinactive
if it was on. once user starts using FPU again, it will trap and
restore fpu registers.