Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  kernel.fuc   Sprache: unbekannt

 
/*
 * Copyright 2013 Red Hat Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Authors: Ben Skeggs
 */

/******************************************************************************
 * kernel data segment
 *****************************************************************************/
#ifdef INCLUDE_PROC
proc_kern:
process(PROC_KERN, 0, 0)
proc_list_head:
#endif

#ifdef INCLUDE_DATA
proc_list_tail:
time_prev: .b32 0
time_next: .b32 0
#endif

/******************************************************************************
 * kernel code segment
 *****************************************************************************/
#ifdef INCLUDE_CODE
 bra #init

// read nv register
//
// $r15 - current
// $r14 - addr
// $r13 - data (return)
// $r0  - zero
rd32:
 nv_iowr(NV_PPWR_MMIO_ADDR, $r14)
 imm32($r13, NV_PPWR_MMIO_CTRL_OP_RD | NV_PPWR_MMIO_CTRL_TRIGGER)
 nv_iowr(NV_PPWR_MMIO_CTRL, $r13)
 rd32_wait:
  nv_iord($r13, NV_PPWR_MMIO_CTRL)
  and $r13 NV_PPWR_MMIO_CTRL_STATUS
  bra nz #rd32_wait
 nv_iord($r13, NV_PPWR_MMIO_DATA)
 ret

// write nv register
//
// $r15 - current
// $r14 - addr
// $r13 - data
// $r0  - zero
wr32:
 nv_iowr(NV_PPWR_MMIO_ADDR, $r14)
 nv_iowr(NV_PPWR_MMIO_DATA, $r13)
 imm32($r13, NV_PPWR_MMIO_CTRL_OP_WR | NV_PPWR_MMIO_CTRL_MASK_B32_0 | NV_PPWR_MMIO_CTRL_TRIGGER)

#ifdef NVKM_FALCON_MMIO_TRAP
 push $r13
 mov $r13 NV_PPWR_INTR_TRIGGER_USER1
 nv_iowr(NV_PPWR_INTR_TRIGGER, $r13)
 wr32_host:
  nv_iord($r13, NV_PPWR_INTR)
  and $r13 NV_PPWR_INTR_USER1
  bra nz #wr32_host
 pop $r13
#endif

 nv_iowr(NV_PPWR_MMIO_CTRL, $r13)
 wr32_wait:
  nv_iord($r13, NV_PPWR_MMIO_CTRL)
  and $r13 NV_PPWR_MMIO_CTRL_STATUS
  bra nz #wr32_wait
 ret

// busy-wait for a period of time
//
// $r15 - current
// $r14 - ns
// $r0  - zero
nsec:
 push $r9
 push $r8
 nv_iord($r8, NV_PPWR_TIMER_LOW)
 nsec_loop:
  nv_iord($r9, NV_PPWR_TIMER_LOW)
  sub b32 $r9 $r8
  cmp b32 $r9 $r14
  bra l #nsec_loop
 pop $r8
 pop $r9
 ret

// busy-wait for a period of time
//
// $r15 - current
// $r14 - addr
// $r13 - mask
// $r12 - data
// $r11 - timeout (ns)
// $r0  - zero
wait:
 push $r9
 push $r8
 nv_iord($r8, NV_PPWR_TIMER_LOW)
 wait_loop:
  nv_rd32($r10, $r14)
  and $r10 $r13
  cmp b32 $r10 $r12
  bra e #wait_done
  nv_iord($r9, NV_PPWR_TIMER_LOW)
  sub b32 $r9 $r8
  cmp b32 $r9 $r11
  bra l #wait_loop
 wait_done:
 pop $r8
 pop $r9
 ret

// $r15 - current (kern)
// $r14 - process
// $r8  - NV_PPWR_INTR
intr_watchdog:
 // read process' timer status, skip if not enabled
 ld b32 $r9 D[$r14 + #proc_time]
 cmp b32 $r9 0
 bra z #intr_watchdog_next_proc

 // subtract last timer's value from process' timer,
 // if it's <= 0 then the timer has expired
 ld b32 $r10 D[$r0 + #time_prev]
 sub b32 $r9 $r10
 bra g #intr_watchdog_next_time
  mov $r13 KMSG_ALARM
  call(send_proc)
  clear b32 $r9
  bra #intr_watchdog_next_proc

 // otherwise, update the next timer's value if this
 // process' timer is the soonest
 intr_watchdog_next_time:
  // ... or if there's no next timer yet
  ld b32 $r10 D[$r0 + #time_next]
  cmp b32 $r10 0
  bra z #intr_watchdog_next_time_set

  cmp b32 $r9 $r10
  bra g #intr_watchdog_next_proc
  intr_watchdog_next_time_set:
  st b32 D[$r0 + #time_next] $r9

 // update process' timer status, and advance
 intr_watchdog_next_proc:
 st b32 D[$r14 + #proc_time] $r9
 add b32 $r14 #proc_size
 cmp b32 $r14 #proc_list_tail
 bra ne #intr_watchdog
 ret

intr:
 push $r0
 clear b32 $r0
 push $r8
 push $r9
 push $r10
 push $r11
 push $r12
 push $r13
 push $r14
 push $r15
 mov $r15 #proc_kern
 mov $r8 $flags
 push $r8

 nv_iord($r8, NV_PPWR_DSCRATCH(0))
 add b32 $r8 1
 nv_iowr(NV_PPWR_DSCRATCH(0), $r8)

 nv_iord($r8, NV_PPWR_INTR)
 and $r9 $r8 NV_PPWR_INTR_WATCHDOG
 bra z #intr_skip_watchdog
  st b32 D[$r0 + #time_next] $r0
  mov $r14 #proc_list_head
  call(intr_watchdog)
  ld b32 $r9 D[$r0 + #time_next]
  cmp b32 $r9 0
  bra z #intr_skip_watchdog
   nv_iowr(NV_PPWR_WATCHDOG_TIME, $r9)
   st b32 D[$r0 + #time_prev] $r9

 intr_skip_watchdog:
 and $r9 $r8 NV_PPWR_INTR_SUBINTR
 bra z #intr_skip_subintr
  nv_iord($r9, NV_PPWR_SUBINTR)
  and $r10 $r9 NV_PPWR_SUBINTR_FIFO
  bra z #intr_subintr_skip_fifo
   nv_iord($r12, NV_PPWR_FIFO_INTR)
   push $r12
   imm32($r14, PROC_HOST)
   mov $r13 KMSG_FIFO
   call(send)
   pop $r12
   nv_iowr(NV_PPWR_FIFO_INTR, $r12)
  intr_subintr_skip_fifo:
  nv_iowr(NV_PPWR_SUBINTR, $r9)

 intr_skip_subintr:
 mov $r9 (NV_PPWR_INTR_USER0 | NV_PPWR_INTR_USER1 | NV_PPWR_INTR_PAUSE)
 not b32 $r9
 and $r8 $r9
 nv_iowr(NV_PPWR_INTR_ACK, $r8)

 pop $r8
 mov $flags $r8
 pop $r15
 pop $r14
 pop $r13
 pop $r12
 pop $r11
 pop $r10
 pop $r9
 pop $r8
 pop $r0
 bclr $flags $p0
 iret

// calculate the number of ticks in the specified nanoseconds delay
//
// $r15 - current
// $r14 - ns
// $r14 - ticks (return)
// $r0  - zero
ticks_from_ns:
 push $r12
 push $r11

 /* try not losing precision (multiply then divide) */
 imm32($r13, HW_TICKS_PER_US)
 call(mulu32_32_64)

 /* use an immeditate, it's ok because HW_TICKS_PER_US < 16 bits */
 div $r12 $r12 1000

 /* check if there wasn't any overflow */
 cmpu b32 $r11 0
 bra e #ticks_from_ns_quit

 /* let's divide then multiply, too bad for the precision! */
 div $r14 $r14 1000
 imm32($r13, HW_TICKS_PER_US)
 call(mulu32_32_64)

 /* this cannot overflow as long as HW_TICKS_PER_US < 1000 */

ticks_from_ns_quit:
 mov b32 $r14 $r12
 pop $r11
 pop $r12
 ret

// calculate the number of ticks in the specified microsecond delay
//
// $r15 - current
// $r14 - us
// $r14 - ticks (return)
// $r0  - zero
ticks_from_us:
 push $r12
 push $r11

 /* simply multiply $us by HW_TICKS_PER_US */
 imm32($r13, HW_TICKS_PER_US)
 call(mulu32_32_64)
 mov b32 $r14 $r12

 /* check if there wasn't any overflow */
 cmpu b32 $r11 0
 bra e #ticks_from_us_quit

 /* Overflow! */
 clear b32 $r14

ticks_from_us_quit:
 pop $r11
 pop $r12
 ret

// calculate the number of ticks in the specified microsecond delay
//
// $r15 - current
// $r14 - ticks
// $r14 - us (return)
// $r0  - zero
ticks_to_us:
 /* simply divide $ticks by HW_TICKS_PER_US */
 imm32($r13, HW_TICKS_PER_US)
 div $r14 $r14 $r13

 ret

// request the current process be sent a message after a timeout expires
//
// $r15 - current
// $r14 - ticks (make sure it is < 2^31 to avoid any possible overflow)
// $r0  - zero
timer:
 push $r9
 push $r8

 // interrupts off to prevent racing with timer isr
 bclr $flags ie0

 // if current process already has a timer set, bail
 ld b32 $r8 D[$r15 + #proc_time]
 cmp b32 $r8 0
 bra g #timer_done

 // halt watchdog timer temporarily
 clear b32 $r8
 nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r8)

 // find out how much time elapsed since the last update
 // of the watchdog and add this time to the wanted ticks
 nv_iord($r8, NV_PPWR_WATCHDOG_TIME)
 ld b32 $r9 D[$r0 + #time_prev]
 sub b32 $r9 $r8
 add b32 $r14 $r9
 st b32 D[$r15 + #proc_time] $r14

 // check for a pending interrupt.  if there's one already
 // pending, we can just bail since the timer isr will
 // queue the next soonest right after it's done
 nv_iord($r8, NV_PPWR_INTR)
 and $r8 NV_PPWR_INTR_WATCHDOG
 bra nz #timer_enable

 // update the watchdog if this timer should expire first,
 // or if there's no timeout already set
 nv_iord($r8, NV_PPWR_WATCHDOG_TIME)
 cmp b32 $r14 $r0
 bra e #timer_reset
 cmp b32 $r14 $r8
 bra g #timer_enable
  timer_reset:
  nv_iowr(NV_PPWR_WATCHDOG_TIME, $r14)
  st b32 D[$r0 + #time_prev] $r14

 // re-enable the watchdog timer
 timer_enable:
 mov $r8 1
 nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r8)

 // interrupts back on
 timer_done:
 bset $flags ie0

 pop $r8
 pop $r9
 ret

// send message to another process
//
// $r15 - current
// $r14 - process
// $r13 - message
// $r12 - message data 0
// $r11 - message data 1
// $r0  - zero
send_proc:
 push $r8
 push $r9
 // check for space in queue
 ld b32 $r8 D[$r14 + #proc_qget]
 ld b32 $r9 D[$r14 + #proc_qput]
 xor $r8 #proc_qmaskb
 cmp b32 $r8 $r9
 bra e #send_done

 // enqueue message
 and $r8 $r9 #proc_qmaskp
 shl b32 $r8 $r8 #proc_qlen
 add b32 $r8 #proc_queue
 add b32 $r8 $r14

 ld b32 $r10 D[$r15 + #proc_id]
 st b32 D[$r8 + #msg_process] $r10
 st b32 D[$r8 + #msg_message] $r13
 st b32 D[$r8 + #msg_data0] $r12
 st b32 D[$r8 + #msg_data1] $r11

 // increment PUT
 add b32 $r9 1
 and $r9 #proc_qmaskf
 st b32 D[$r14 + #proc_qput] $r9
 bset $flags $p2
 send_done:
 pop $r9
 pop $r8
 ret

// lookup process structure by its name
//
// $r15 - current
// $r14 - process name
// $r0  - zero
//
// $r14 - process
// $p1  - success
find:
 push $r8
 mov $r8 #proc_list_head
 bset $flags $p1
 find_loop:
  ld b32 $r10 D[$r8 + #proc_id]
  cmp b32 $r10 $r14
  bra e #find_done
  add b32 $r8 #proc_size
  cmp b32 $r8 #proc_list_tail
  bra ne #find_loop
  bclr $flags $p1
 find_done:
 mov b32 $r14 $r8
 pop $r8
 ret

// send message to another process
//
// $r15 - current
// $r14 - process id
// $r13 - message
// $r12 - message data 0
// $r11 - message data 1
// $r0  - zero
send:
 call(find)
 bra $p1 #send_proc
 ret

// process single message for a given process
//
// $r15 - current
// $r14 - process
// $r0  - zero
recv:
 push $r9
 push $r8

 ld b32 $r8 D[$r14 + #proc_qget]
 ld b32 $r9 D[$r14 + #proc_qput]
 bclr $flags $p1
 cmp b32 $r8 $r9
 bra e #recv_done
  // dequeue message
  and $r9 $r8 #proc_qmaskp
  add b32 $r8 1
  and $r8 #proc_qmaskf
  st b32 D[$r14 + #proc_qget] $r8
  ld b32 $r10 D[$r14 + #proc_recv]

  push $r15
  mov $r15 $flags
  push $r15
  mov b32 $r15 $r14

  shl b32 $r9 $r9 #proc_qlen
  add b32 $r14 $r9
  add b32 $r14 #proc_queue
  ld b32 $r11 D[$r14 + #msg_data1]
  ld b32 $r12 D[$r14 + #msg_data0]
  ld b32 $r13 D[$r14 + #msg_message]
  ld b32 $r14 D[$r14 + #msg_process]

  // process it
  call $r10
  pop $r15
  mov $flags $r15
  bset $flags $p1
  pop $r15
 recv_done:
 pop $r8
 pop $r9
 ret

init:
 // setup stack
 nv_iord($r1, NV_PPWR_CAPS)
 extr $r1 $r1 9:17
 shl b32 $r1 8
 mov $sp $r1

#ifdef NVKM_FALCON_MMIO_UAS
 // somehow allows the magic "access mmio via D[]" stuff that's
 // used by the nv_rd32/nv_wr32 macros to work
 imm32($r1, 0x10 | NV_PPWR_UAS_CONFIG_ENABLE)
 nv_iowrs(NV_PPWR_UAS_CONFIG, $r1)
#endif

 // route all interrupts except user0/1 and pause to fuc
 imm32($r1, 0xe0)
 nv_iowr(NV_PPWR_INTR_ROUTE, $r1)

 // enable watchdog and subintr intrs
 mov $r1 NV_PPWR_INTR_EN_CLR_MASK
 nv_iowr(NV_PPWR_INTR_EN_CLR, $r1)
 mov $r1 NV_PPWR_INTR_EN_SET_WATCHDOG
 or $r1 NV_PPWR_INTR_EN_SET_SUBINTR
 nv_iowr(NV_PPWR_INTR_EN_SET, $r1)

 // enable interrupts globally
 imm32($r1, #intr)
 and $r1 0xffff
 mov $iv0 $r1
 bset $flags ie0

 // enable watchdog timer
 mov $r1 1
 nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r1)

 // bootstrap processes, idle process will be last, and not return
 mov $r15 #proc_list_head
 init_proc:
  ld b32 $r1 D[$r15 + #proc_init]
  cmp b32 $r1 0
  bra z #init_proc
  call $r1
  add b32 $r15 #proc_size
  bra #init_proc
#endif

[ Dauer der Verarbeitung: 0.20 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge