the 9000 series uses a new receive descriptor format
wich appears to reqire 4k aligned buffers. the old
format "halfworks" and just makes the firmware not
respond to any commands after the enable paging command.
the smartfifo command appears to causes problems.
but apparently not issuing it at all seems to work
fine on both the 8265 and 9260. so removing the code
for now.
issuing the bindingquota command before associated
makes association impossible. but enabling afterwards
works fine. (tested in 8265 and 9260).
the prph access functions now mask the address with
0xfffff. it is unclear why linux and openbsd drivers
specify addresses beyond that in ther register constants.
the timeevent change is interesting. the timeevent
needs to be restarted when it has stoped to make sure
probing/association packets are sent during the evnet.
The new pci code is moved to port/pci.[hc] and shared by
all ports.
Each port has its own PCI controller implementation,
providing the pcicfgrw*() functions for low level pci
config space access. The locking for pcicfgrw*() is now
done by the caller (only port/pci.c).
Device drivers now need to include "../port/pci.h" in
addition to "io.h".
The new code now checks bridge windows and membars,
while enumerating the bus, giving the pc driver a chance
to re-assign them. This is needed because some UEFI
implementations fail to assign the bars for some devices,
so we need to do it outselfs. (See pcireservemem()).
While working on this, it was discovered that the pci
code assimed the smallest I/O bar size is 16 (pcibarsize()),
which is wrong. I/O bars can be as small as 4 bytes.
Bit 1 in an I/O bar is also reserved and should be masked off,
making the port mask: port = bar & ~3;
The Abind case in namec() needs to cunique() the chan
before attaching the umh mount head pointer onto it.
This is because we cannot give a reference to the mount
head to any of the mh->mount...->to channels, as they
will never go away until the mount head goes away.
This is a cyclic reference.
This could be reproduced with:
@{rfork n; mount -a '#s/boot' /mnt/root; bind /mnt/root /}
Also, fix memory leaks around cunique(), which can
error, leaking the mount head we got from domount().
Move the umh != nil check inside cunique().
we have to disable interrupts during mmuwalk() of user pages
as we can get preempted during mmu walk and the original
m->pml4 might become one of a different process.
This change makes it mandatory for programs to call segflush() on
code that is not in the text segment if they want to execute it.
As a side effect, this means that everything but the text segment
will be non-executable by default, even without the SG_NOEXEC
attribute. Segments with the SG_NOEXEC attribute never become
executable, even when segflush() is called on them.
widen and move the KMAP window to a new address so we can
handle the 8GB of physical memory of the new raspberry pi4.
the new memory map on pi4 uses the following 4 banks:
0x000000000 0x03e600000
0x040000000 0x0fc000000 <- soc.dramsize (only < 4GB)
0x100000000 0x180000000
0x180000000 0x200000000
On the 8GB variant of the raspberry pi 4,
the eeprom chip for the xhci controller is missing and
instead loaded from sdram (by the gpu firmware).
for this, the gpu firmware needs to be notified of
the xhci controllers pci bus address (after reset)
that was assigned by our pci enumeration code.
instruction cache maintenance is done on tlb miss;
when a page gets fauled in; with putmmu() checking
the page->txtflush cpu bitmap.
syssegflush() used to only call flushmmu() after
segflush() for the calling process, but when a segment
is shared with other processes, we have to flush the
other processes tlb as well.
this adds the missing procflushseg() call into segflush().
note that procflushseg() leaves the calling process alone,
so the flushmmu() call in syssegflush() is still required.
segmentioproc() does not need to call flushmmu() after
segflush() as it is never going to jump to the modified
page, hence the stale icache does not matter.
The sample frequency is an artificial parameter used for
isochronous out transfers to better match the target
frequency (usually, a sound card).
when hz is set, devusb adjusts the endpoint's maxpkt to get
the requested frequency and a multiple of the samplesize per
packet.
however, when hz is not set, then we should calculate the
frequency from maxpkt, ntds and pollival, so all parameters
will be consistent with each other.
Added a ver= field to the filter to distinguish the ip version.
By default, a filter is parsed as ipv6, and after parsing
proto, src and dst fields are converted to ipv4. When no
ver= field is specified, a ip version filter is implicitely
added and both protocols are parsed.
This change also gets rid of the fast compare types as the
filed might not be aligned correctly in the packet.
This also fixes the ifc= filter, as we have to check any
local address.
We used to just return the first address of the incoming
interface regardless of if the address matches the source
ip type and scope.
This change tries to find the best interface address that
will match the source ip so it can be used as a source
address when replying to the packet.
the page attribute table was initialized in mmuinit(), which is
too late for bootscreen(). So now we check for PAT support and
insert the write-combine entry early in cpuidentify().
this might have been the cause of some slow EFI framebuffers on
machines with overlapping or insufficient MTRR entries.
ipiput4() and ipiput6() are called with the incoming interface rlocked
while ipoput4() and ipoput6() also rlock() the outgoing interface once
a route has been found. it is common that the incoming and outgoing
interfaces are the same recusive rlocking().
the deadlock happens when a reader holds the rlock for the incoming interface,
then ip/ipconfig tries to add a new address, trying to wlock the interface.
as there are still active readers on the ifc, ip/ipconfig process gets queued
on the inteface RWlock.
now the reader finds the outgoing route which has the same interface as the
incoming packet and tries to rlock the ifc again. but now theres a writer
queued, so we also go to sleep waiting four outselfs to release the lock.
the solution is to never wait for the outgoing interface rlock, but instead
use non-queueing canrlock() and if it cannot be acquired, discard the packet.
do not touch s->map on SG_PHYSICAL type segments as they do
not have a pte map (s->mapsize == 0 && s->map == nil).
also remove the SG_PHYSICAL switch in freepte(), this is never
reached.
the calculation for the control endpoint0 output device context
missed the context size scaling shift, resulting in botched
stall handling as we would not read the correct endpoint status
value.
note, this calculation only affected control endpoint 0, which
was handled separately from all other endpoints.
spectacular bug. cmpswap() had a sign extension bug
using sign extending MOV to load the old compare
value and LDXRW using zero extension while the CMP
instruction compared 64 bit registers.
this caused cmpswap with negative old value always
to fail.
interestingly, libc's version of this function was
fine.
when reclaiming pages from an image, always reclaim all
the hash chains equally. that way, we avoid being biased
towards the chains at the start of the Image.pghash[] array.
images can be in two states: active or inactive. inactive
images are the ones which are not used by program while
active ones aare.
when reclaiming pages, we should try to reclaim pages
from inactive images first and only if that set becomes
exhausted attempt to release text pages and attempt to
reclaim pages from active images.
when we run out of Image structures, it makes only sense
to reclaim pages from inactive images, as reclaiming pages
from active ones will never free any Image structures.
change putimage() to require a image already locked and
make it unlock the image. this avoids many pointless
unlock()/lock() sequences as all callers of putimage()
already had the image locked.
looks like linux changed the device tree names for
the memory node:
4b17654f51 (diff-ac03c9402b807c11d42edc9e8d03dfc7)
this fixes the memory size detection with latest firmware
on raspberry pi4-b (4GB) for kenji.
The swcursor used a 32x32 image for saving/restoring
screen contents for no reason.
Add a doflush argument to swcursorhide(), so that
disabling software cursor with a double buffered
softscreen is properly hidden. The doflush parameter
should be set to 0 in all other cases as swcursordraw()
will flushes both (current and previours) locations.
Make sure swcursorinit() and swcursorhide() clear the
visibility flag, even when gscreen is nil.
Remove the cursor locking and just do everything within
the drawlock. All cursor functions such as curson(),
cursoff() and setcursor() will be called drawlock
locked. This also means &cursor can be read.
Fix devmouse cursor reads and writes. We now have the
global cursor variable that is only modified under
the drawlock. So copy under drawlock.
Move the pc software cursor implementation into vgasoft
driver, so screen.c does not need to handle it as
a special case.
Remove unused functions such as drawhasclients().
most pc's are multiprocessors these days, that use apic or
msi interrupts, then the irq does not matter anymore. and
uefi does not even assign irq to pci devices anymore. if
we have a problem enabling an interrupt, we will print.
memory returned by rampage() is not zeroed, so we have to
zero it ourselfs. apparently, this bug didnt show up as we
where zeroing conventional low memory before the new memory
map code. also rampage() never returns nil.
This replaces the memory map code for both pc and pc64
kernels with a unified implementation using the new
portable memory map code.
The main motivation is to be robust against broken
e820 memory maps by the bios and delay the Conf.mem[]
allocation after archinit(), so mp and acpi tables
can be reserved and excluded from user memory.
There are a few changes:
new memreserve() function has been added for archinit()
to reserve bios and acpi tables.
upareserve() has been replaced by upaalloc(), which now
has an address argument.
umbrwmalloc() and umbmalloc() have been replaced by
umballoc().
both upaalloc() and umballoc() return physical addresses
or -1 on error. the physical address -1 is now used as
a sentinel value instead of 0 when dealing with physical
addresses.
archmp and archacpi now always use vmap() to access
the bios tables and reserve the ranges. more overflow
checks have been added.
ramscan() has been rewritten using vmap().
to handle the population of kernel memory, pc and pc64
now have pmap() and punmap() functions to do permanent
mappings.
This is a generic memory map for physical addresses. Entries
can be added with memmapadd() giving a range and a type.
Ranges can be allocated and freed from the map. The code
automatically resolves overlapping ranges by type priority.
Fix the inconsistent use of ether->mem. Always use physical
addresses. Let ether8390 convert to virtual addresses using
KADDR() when we have to copy data in/out.
the previous mkfile had a sneaky hack that would use
sed to delete the first 2 lines of hex output to strip
the 32 byte long a.out header for apbootstrap and rebootcode.
use 8l -H3 flag to strip the header from the output file.
the rc & operator changes stdin to /dev/null, so we
have to do the <[0=1] inside the {}
this never showed up as an issue because many
fileservers just read 9p messages from standard
output.
when the control mountpoint side gets removed, close
mount channel immediately. this is usefull for implementing
automatic cleanup with ORCLOSE create mode.
allow reading the control file of a process and return
its pid number. if the process has exited, return an error.
this can be usefull as a way to test if a process is
still alive. and also makes it behave similar to
network protocol directories.
another side effect is that processes who erroneously
open the ctl file ORDWR would be allowed todo so as
along as they have write permission and the process is
not a kernel process.
progarg[0] can be assigned to elem directly as it is a
copy in kernel memory, so the char proelem[64] buffer
is not neccesary.
do the close-on-exit outside of the segment lock. there
is no reason to keep the segment table locked.
the user buffer could be changed while we parse it resulting
in a different number of watchpoints than initially calculated.
so add a check to the parse loop so we wont overflow the
watchpoint array.
in case the calling process changes its arguments under us, it could
happen that the final argument string lengths become bigger than
initially calculated. this is fine as we still make sure we wont
overflow the stack segment, but we could overrun into the tos
structure at the end of the stack. so change the limit to the
base of the tos, not the end of the stack segment.
writes to /proc/n/notepg and /proc/n/note should be able to write
at ERRMAX-1 bytes, not ERRMAX-2.
simplify write to /proc/n/args by just copying to local buf first
and then doing a kstrdup(). the value of Proc.nargs does not matter
when Proc.setargs is 1.
devproc assumes that when we hold the Proc.debug qlock,
the process will be prevented from exiting. but there is
another race where the process has already exited and
the Proc* slot gets reused. to solve this, on process
creation we also have to acquire the debug qlock while
initializing the fields of the process. this also means
newproc() should only initialize fields *not* protected
by the debug qlock.
always acquire the Proc.debug qlock when changing strings
in the proc structure to avoid doublefree on concurrent
update. for changing the user string, we add a procsetuser()
function that does this for auth.c and devcap.
remove pgrpnote() from pgrp.c and replace by static
postnotepg() in devproc.
avoid the assumption that the Proc* entries returned by
proctab() are continuous.
fixed devproc permission issues:
- make sure only eve can access /proc/trace
- none should only be allowed to read its own /proc/n/text
- move Proc.kp checks into procopen()
pid reuse was not handled correctly, as we where only
checking if a pid had a living process, but there still
could be processes expecting a particular parentpid or
noteid.
this is now addressed with reference counted Pid
structures which are organized in a hash table.
read access to the hash table does not require locks
which will be usefull for dtracy later.
replace machine specific userinit() by a portable
implemntation that uses kproc() to create the first
process. the initcode text is mapped using kmap(),
so there is no need for machine specific tmpmap()
functions.
initcode stack preparation should be done in init0()
where the stack is mapped and can be accessed directly.
replacing the machine specific userinit() allows some
big simplifications as sysrfork() and kproc() are now
the only callers of newproc() and we can avoid initializing
fields that we know are being initialized by these
callers.
rename autogenerated init.h and reboot.h headers.
the initcode[] and rebootcode[] blobs are now in *.i
files and hex generation was moved to portmkfile. the
machine specific mkfile only needs to specify how to
build rebootcode.out and initcode.out.
to prevent deadlock on media unbind (which is called with
the interface wlock()'ed), the medias reader processes
that unbind was waiting for used to discard packets when
the interface could not be rlocked.
this has the unfortunate side effect that when we change
addresses on a interface that packets are getting lost.
this is problematic for the processing of ipv6 router
advertisements when multiple RA's are getting received
in quick succession.
this change removes that packet dropping behaviour and
instead changes the unbind process to avoid the deadlock
by wunlock()ing the interface temporarily while waiting
for the reader processes to finish. the interface media
is also changed to the mullmedium before unlocking (see
the comment).
comparing m with MACHP() is wrong as m is a constant on 386.
add procflushothers(), which flushes all processes except up
using common procflushmmu() routine.
procflushmmu() returns once all *OTHER* processors that had
matching processes running on them flushed ther tlb/mmu state.
the caller of procflush...() takes care of flushing "up" by
calling flushmmu() later.
if the current process matched, then that means m->flushmmu
would be set, and hzclock() would call flushmmu() again.
to avoid this, we now check up->newtlb in addition to m->flushmmu
in hzclock() before calling flushmmu().
we also maintain information on which process on what processor
to wait for locally, which helps making progress when multiple
procflushmmu()'s are running concurrently.
in addition, this makes the wait condition for procflushmmu()
more sophisticated, by validating if the processor still runs
the selected process and only if it matchatches, considers
the MACHP(nm)->flushmmu flag.
the change to support no-execute bits broke the original
raspberry pi1, as it uses backwards compatible page table
format.
to use the XN bit, subpage AP bits have to be disabled
using the XP bit in CP15 Control Register c1 Bit 23.
when a process does an exec syscall, procsetup() is called and
we have to disable the debug watchpoint registers. just clearing
p->dr is not enougth as we are not going thru a procsave() and
procrestore() cycle which would disable and reload the saved
debug registers.
instead of clearing debug registers in procfork(), we should
clear the saved debug registers before a process goes to die
(pexit() calls sched() with up->state = Moribund) as the Proc
structure can get reused for kernel processes (kproc) which
never call procfork() and would therefore have debug registers
loaded.
for better system diagnostics, we *ALWAYS* want to record the parent
pid of a user process, regardless of if the child will post a wait
record on exit or not.
for that, we reverse the roles of Proc.parent and Proc.parentpid so
Proc.parentpid will always be set on rfork() and the Proc.parent
pointer will point to the parent's Proc structure or is set to nil
when no wait record should be posted on exit (RFNOWAIT flag).
this means that we can get the pid of the original parent process
from /proc, regardless of the the child having rforked with the
RFNOWAIT flag. this improves the output of pstree(1) somewhat if
the parent is still alive. note that theres no guarantee that the
parent pid is still valid.
the conditions are unchanged:
a user process that will post wait record has:
up->kp == 0 && up->parent != nil && up->parent->pid == up->parentpid
the boot process is:
up->kp == 0 && up->parent == nil && up->parentpid == 0
and kproc's have:
up->kp != 0 && up->parent == nil && up->parentpid == 0
Ori_B reports that his controller gets stuck in the ahciencreset()
wait loop. so we implement a 1000 ms timeout. we replace delay()
with esleep() as we are always called from the ledkproc().
blink() could enter infinite delay loop as well, so instead of
waiting for the message to get transmitted we exit making it
non-blocking (we will get called again anyway).
the access to the controller map[] was wrong in ledkproc(). the
index is the controller number, not the drive number!
when making outgoing connections, the source ip was selected
by just iterating from the first to the last interface and
trying each local address until a route was found. the result
was kind of hard to predict as it depends on the interface
order.
this change replaces the algorithm with the route lookup algorithm
that we already have which takes more specific desination and
source prefixes into account. so the order of interfaces does
not matter anymore.
on 386, the kernel memory region is mapped using huge 4MB pages
(when supported by the cpu). so the uncached pte manipulation
does not work to map the cursor data with uncached attribute.
instead, we allocate a memory page using newpage() and map
it globally using vmap(), which maps it uncached.
after issuing CR_RESETEP command, we have to invalidate
the endpoints output context buffer so that the halted/error
status reflects the new state. not doing so resulted in
the halted state to be stuck and we continued issuing
endpoint reset commands when we where already recovered.
handle the devusb Ep.clrhalt flag from devusb that userspace
uses to force a endpoint reset on the next transaction.
permission checking had the "other" and "owner" bits swapped plus incoming
connections where always owned by "network" instead of the owner of
the listening connection. also, ipwstat() was not effective as the uid
strings where not parsed.
this fixes the permission checks for data/ctl/err file and makes incoming
connections inherit the owner from the listening connection.
we also allow ipwstat() to change ownership to the commonuser() or anyone
if we are eve.
we might have to add additional restrictions for none at a later point...
we want devip to get reattached after hostowner has been written. factotum
already handles this with a private authdial() routine that mounts devip
when it is not present. so we detach devmnt before starting factotum,
and attach once factotum finishes.
the locking in proctext() is wrong. we have to acquire Proc.seglock
when reading segments from Proc.seg[] as segments do not
have a private freelist and can therefore be reused for other
data structures.
once we have Proc.seglock acquired, check that the process pid
is still valid so we wont accidentally read some other processes
segments. (for both proctext() and procctlmemio()). this also
should give better error message to distinguish the case when
the process did segdetach() the segment in question before we
could acquire Proc.seglock.
declare private functions as static.
there was a small window between modifying mmutop and switching the
asid where the core could bring in the new entries under the old asid
into the tlb due to speculation / prefetching.
this change moves the entering of the page tables into mmutop after
setttbr() to prevent this scenario.
due to us switching to the resereved asid 0 on procsave()->putasid(),
the only asid that could have potentially been poisoned would be asid 0
which does not have any user mappings. so this did not show any noticable
effect.
pexit() and pprint() can get called outside of a syscall
(from procctl()) with a process that is in active note
handling and require floating point in the kernel on amd64
for aesni (devtls).