cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

kernel.fuc (11853B)


      1/*
      2 * Copyright 2013 Red Hat Inc.
      3 *
      4 * Permission is hereby granted, free of charge, to any person obtaining a
      5 * copy of this software and associated documentation files (the "Software"),
      6 * to deal in the Software without restriction, including without limitation
      7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 * and/or sell copies of the Software, and to permit persons to whom the
      9 * Software is furnished to do so, subject to the following conditions:
     10 *
     11 * The above copyright notice and this permission notice shall be included in
     12 * all copies or substantial portions of the Software.
     13 *
     14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 * OTHER DEALINGS IN THE SOFTWARE.
     21 *
     22 * Authors: Ben Skeggs
     23 */
     24
     25/******************************************************************************
     26 * kernel data segment
     27 *****************************************************************************/
     28#ifdef INCLUDE_PROC
     29proc_kern:
     30process(PROC_KERN, 0, 0)
     31proc_list_head:
     32#endif
     33
     34#ifdef INCLUDE_DATA
     35proc_list_tail:
     36time_prev: .b32 0
     37time_next: .b32 0
     38#endif
     39
     40/******************************************************************************
     41 * kernel code segment
     42 *****************************************************************************/
     43#ifdef INCLUDE_CODE
     44	bra #init
     45
     46// read nv register
     47//
     48// $r15 - current
     49// $r14 - addr
     50// $r13 - data (return)
     51// $r0  - zero
     52rd32:
     53	nv_iowr(NV_PPWR_MMIO_ADDR, $r14)
     54	imm32($r13, NV_PPWR_MMIO_CTRL_OP_RD | NV_PPWR_MMIO_CTRL_TRIGGER)
     55	nv_iowr(NV_PPWR_MMIO_CTRL, $r13)
     56	rd32_wait:
     57		nv_iord($r13, NV_PPWR_MMIO_CTRL)
     58		and $r13 NV_PPWR_MMIO_CTRL_STATUS
     59		bra nz #rd32_wait
     60	nv_iord($r13, NV_PPWR_MMIO_DATA)
     61	ret
     62
     63// write nv register
     64//
     65// $r15 - current
     66// $r14 - addr
     67// $r13 - data
     68// $r0  - zero
     69wr32:
     70	nv_iowr(NV_PPWR_MMIO_ADDR, $r14)
     71	nv_iowr(NV_PPWR_MMIO_DATA, $r13)
     72	imm32($r13, NV_PPWR_MMIO_CTRL_OP_WR | NV_PPWR_MMIO_CTRL_MASK_B32_0 | NV_PPWR_MMIO_CTRL_TRIGGER)
     73
     74#ifdef NVKM_FALCON_MMIO_TRAP
     75	push $r13
     76	mov $r13 NV_PPWR_INTR_TRIGGER_USER1
     77	nv_iowr(NV_PPWR_INTR_TRIGGER, $r13)
     78	wr32_host:
     79		nv_iord($r13, NV_PPWR_INTR)
     80		and $r13 NV_PPWR_INTR_USER1
     81		bra nz #wr32_host
     82	pop $r13
     83#endif
     84
     85	nv_iowr(NV_PPWR_MMIO_CTRL, $r13)
     86	wr32_wait:
     87		nv_iord($r13, NV_PPWR_MMIO_CTRL)
     88		and $r13 NV_PPWR_MMIO_CTRL_STATUS
     89		bra nz #wr32_wait
     90	ret
     91
     92// busy-wait for a period of time
     93//
     94// $r15 - current
     95// $r14 - ns
     96// $r0  - zero
     97nsec:
     98	push $r9
     99	push $r8
    100	nv_iord($r8, NV_PPWR_TIMER_LOW)
    101	nsec_loop:
    102		nv_iord($r9, NV_PPWR_TIMER_LOW)
    103		sub b32 $r9 $r8
    104		cmp b32 $r9 $r14
    105		bra l #nsec_loop
    106	pop $r8
    107	pop $r9
    108	ret
    109
    110// busy-wait for a period of time
    111//
    112// $r15 - current
    113// $r14 - addr
    114// $r13 - mask
    115// $r12 - data
    116// $r11 - timeout (ns)
    117// $r0  - zero
    118wait:
    119	push $r9
    120	push $r8
    121	nv_iord($r8, NV_PPWR_TIMER_LOW)
    122	wait_loop:
    123		nv_rd32($r10, $r14)
    124		and $r10 $r13
    125		cmp b32 $r10 $r12
    126		bra e #wait_done
    127		nv_iord($r9, NV_PPWR_TIMER_LOW)
    128		sub b32 $r9 $r8
    129		cmp b32 $r9 $r11
    130		bra l #wait_loop
    131	wait_done:
    132	pop $r8
    133	pop $r9
    134	ret
    135
    136// $r15 - current (kern)
    137// $r14 - process
    138// $r8  - NV_PPWR_INTR
    139intr_watchdog:
    140	// read process' timer status, skip if not enabled
    141	ld b32 $r9 D[$r14 + #proc_time]
    142	cmp b32 $r9 0
    143	bra z #intr_watchdog_next_proc
    144
    145	// subtract last timer's value from process' timer,
    146	// if it's <= 0 then the timer has expired
    147	ld b32 $r10 D[$r0 + #time_prev]
    148	sub b32 $r9 $r10
    149	bra g #intr_watchdog_next_time
    150		mov $r13 KMSG_ALARM
    151		call(send_proc)
    152		clear b32 $r9
    153		bra #intr_watchdog_next_proc
    154
    155	// otherwise, update the next timer's value if this
    156	// process' timer is the soonest
    157	intr_watchdog_next_time:
    158		// ... or if there's no next timer yet
    159		ld b32 $r10 D[$r0 + #time_next]
    160		cmp b32 $r10 0
    161		bra z #intr_watchdog_next_time_set
    162
    163		cmp b32 $r9 $r10
    164		bra g #intr_watchdog_next_proc
    165		intr_watchdog_next_time_set:
    166		st b32 D[$r0 + #time_next] $r9
    167
    168	// update process' timer status, and advance
    169	intr_watchdog_next_proc:
    170	st b32 D[$r14 + #proc_time] $r9
    171	add b32 $r14 #proc_size
    172	cmp b32 $r14 #proc_list_tail
    173	bra ne #intr_watchdog
    174	ret
    175
    176intr:
    177	push $r0
    178	clear b32 $r0
    179	push $r8
    180	push $r9
    181	push $r10
    182	push $r11
    183	push $r12
    184	push $r13
    185	push $r14
    186	push $r15
    187	mov $r15 #proc_kern
    188	mov $r8 $flags
    189	push $r8
    190
    191	nv_iord($r8, NV_PPWR_DSCRATCH(0))
    192	add b32 $r8 1
    193	nv_iowr(NV_PPWR_DSCRATCH(0), $r8)
    194
    195	nv_iord($r8, NV_PPWR_INTR)
    196	and $r9 $r8 NV_PPWR_INTR_WATCHDOG
    197	bra z #intr_skip_watchdog
    198		st b32 D[$r0 + #time_next] $r0
    199		mov $r14 #proc_list_head
    200		call(intr_watchdog)
    201		ld b32 $r9 D[$r0 + #time_next]
    202		cmp b32 $r9 0
    203		bra z #intr_skip_watchdog
    204			nv_iowr(NV_PPWR_WATCHDOG_TIME, $r9)
    205			st b32 D[$r0 + #time_prev] $r9
    206
    207	intr_skip_watchdog:
    208	and $r9 $r8 NV_PPWR_INTR_SUBINTR
    209	bra z #intr_skip_subintr
    210		nv_iord($r9, NV_PPWR_SUBINTR)
    211		and $r10 $r9 NV_PPWR_SUBINTR_FIFO
    212		bra z #intr_subintr_skip_fifo
    213			nv_iord($r12, NV_PPWR_FIFO_INTR)
    214			push $r12
    215			imm32($r14, PROC_HOST)
    216			mov $r13 KMSG_FIFO
    217			call(send)
    218			pop $r12
    219			nv_iowr(NV_PPWR_FIFO_INTR, $r12)
    220		intr_subintr_skip_fifo:
    221		nv_iowr(NV_PPWR_SUBINTR, $r9)
    222
    223	intr_skip_subintr:
    224	mov $r9 (NV_PPWR_INTR_USER0 | NV_PPWR_INTR_USER1 | NV_PPWR_INTR_PAUSE)
    225	not b32 $r9
    226	and $r8 $r9
    227	nv_iowr(NV_PPWR_INTR_ACK, $r8)
    228
    229	pop $r8
    230	mov $flags $r8
    231	pop $r15
    232	pop $r14
    233	pop $r13
    234	pop $r12
    235	pop $r11
    236	pop $r10
    237	pop $r9
    238	pop $r8
    239	pop $r0
    240	bclr $flags $p0
    241	iret
    242
    243// calculate the number of ticks in the specified nanoseconds delay
    244//
    245// $r15 - current
    246// $r14 - ns
    247// $r14 - ticks (return)
    248// $r0  - zero
    249ticks_from_ns:
    250	push $r12
    251	push $r11
    252
    253	/* try not losing precision (multiply then divide) */
    254	imm32($r13, HW_TICKS_PER_US)
    255	call(mulu32_32_64)
    256
    257	/* use an immeditate, it's ok because HW_TICKS_PER_US < 16 bits */
    258	div $r12 $r12 1000
    259
    260	/* check if there wasn't any overflow */
    261	cmpu b32 $r11 0
    262	bra e #ticks_from_ns_quit
    263
    264	/* let's divide then multiply, too bad for the precision! */
    265	div $r14 $r14 1000
    266	imm32($r13, HW_TICKS_PER_US)
    267	call(mulu32_32_64)
    268
    269	/* this cannot overflow as long as HW_TICKS_PER_US < 1000 */
    270
    271ticks_from_ns_quit:
    272	mov b32 $r14 $r12
    273	pop $r11
    274	pop $r12
    275	ret
    276
    277// calculate the number of ticks in the specified microsecond delay
    278//
    279// $r15 - current
    280// $r14 - us
    281// $r14 - ticks (return)
    282// $r0  - zero
    283ticks_from_us:
    284	push $r12
    285	push $r11
    286
    287	/* simply multiply $us by HW_TICKS_PER_US */
    288	imm32($r13, HW_TICKS_PER_US)
    289	call(mulu32_32_64)
    290	mov b32 $r14 $r12
    291
    292	/* check if there wasn't any overflow */
    293	cmpu b32 $r11 0
    294	bra e #ticks_from_us_quit
    295
    296	/* Overflow! */
    297	clear b32 $r14
    298
    299ticks_from_us_quit:
    300	pop $r11
    301	pop $r12
    302	ret
    303
    304// calculate the number of ticks in the specified microsecond delay
    305//
    306// $r15 - current
    307// $r14 - ticks
    308// $r14 - us (return)
    309// $r0  - zero
    310ticks_to_us:
    311	/* simply divide $ticks by HW_TICKS_PER_US */
    312	imm32($r13, HW_TICKS_PER_US)
    313	div $r14 $r14 $r13
    314
    315	ret
    316
    317// request the current process be sent a message after a timeout expires
    318//
    319// $r15 - current
    320// $r14 - ticks (make sure it is < 2^31 to avoid any possible overflow)
    321// $r0  - zero
    322timer:
    323	push $r9
    324	push $r8
    325
    326	// interrupts off to prevent racing with timer isr
    327	bclr $flags ie0
    328
    329	// if current process already has a timer set, bail
    330	ld b32 $r8 D[$r15 + #proc_time]
    331	cmp b32 $r8 0
    332	bra g #timer_done
    333
    334	// halt watchdog timer temporarily
    335	clear b32 $r8
    336	nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r8)
    337
    338	// find out how much time elapsed since the last update
    339	// of the watchdog and add this time to the wanted ticks
    340	nv_iord($r8, NV_PPWR_WATCHDOG_TIME)
    341	ld b32 $r9 D[$r0 + #time_prev]
    342	sub b32 $r9 $r8
    343	add b32 $r14 $r9
    344	st b32 D[$r15 + #proc_time] $r14
    345
    346	// check for a pending interrupt.  if there's one already
    347	// pending, we can just bail since the timer isr will
    348	// queue the next soonest right after it's done
    349	nv_iord($r8, NV_PPWR_INTR)
    350	and $r8 NV_PPWR_INTR_WATCHDOG
    351	bra nz #timer_enable
    352
    353	// update the watchdog if this timer should expire first,
    354	// or if there's no timeout already set
    355	nv_iord($r8, NV_PPWR_WATCHDOG_TIME)
    356	cmp b32 $r14 $r0
    357	bra e #timer_reset
    358	cmp b32 $r14 $r8
    359	bra g #timer_enable
    360		timer_reset:
    361		nv_iowr(NV_PPWR_WATCHDOG_TIME, $r14)
    362		st b32 D[$r0 + #time_prev] $r14
    363
    364	// re-enable the watchdog timer
    365	timer_enable:
    366	mov $r8 1
    367	nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r8)
    368
    369	// interrupts back on
    370	timer_done:
    371	bset $flags ie0
    372
    373	pop $r8
    374	pop $r9
    375	ret
    376
    377// send message to another process
    378//
    379// $r15 - current
    380// $r14 - process
    381// $r13 - message
    382// $r12 - message data 0
    383// $r11 - message data 1
    384// $r0  - zero
    385send_proc:
    386	push $r8
    387	push $r9
    388	// check for space in queue
    389	ld b32 $r8 D[$r14 + #proc_qget]
    390	ld b32 $r9 D[$r14 + #proc_qput]
    391	xor $r8 #proc_qmaskb
    392	cmp b32 $r8 $r9
    393	bra e #send_done
    394
    395	// enqueue message
    396	and $r8 $r9 #proc_qmaskp
    397	shl b32 $r8 $r8 #proc_qlen
    398	add b32 $r8 #proc_queue
    399	add b32 $r8 $r14
    400
    401	ld b32 $r10 D[$r15 + #proc_id]
    402	st b32 D[$r8 + #msg_process] $r10
    403	st b32 D[$r8 + #msg_message] $r13
    404	st b32 D[$r8 + #msg_data0] $r12
    405	st b32 D[$r8 + #msg_data1] $r11
    406
    407	// increment PUT
    408	add b32 $r9 1
    409	and $r9 #proc_qmaskf
    410	st b32 D[$r14 + #proc_qput] $r9
    411	bset $flags $p2
    412	send_done:
    413	pop $r9
    414	pop $r8
    415	ret
    416
    417// lookup process structure by its name
    418//
    419// $r15 - current
    420// $r14 - process name
    421// $r0  - zero
    422//
    423// $r14 - process
    424// $p1  - success
    425find:
    426	push $r8
    427	mov $r8 #proc_list_head
    428	bset $flags $p1
    429	find_loop:
    430		ld b32 $r10 D[$r8 + #proc_id]
    431		cmp b32 $r10 $r14
    432		bra e #find_done
    433		add b32 $r8 #proc_size
    434		cmp b32 $r8 #proc_list_tail
    435		bra ne #find_loop
    436		bclr $flags $p1
    437	find_done:
    438	mov b32 $r14 $r8
    439	pop $r8
    440	ret
    441
    442// send message to another process
    443//
    444// $r15 - current
    445// $r14 - process id
    446// $r13 - message
    447// $r12 - message data 0
    448// $r11 - message data 1
    449// $r0  - zero
    450send:
    451	call(find)
    452	bra $p1 #send_proc
    453	ret
    454
    455// process single message for a given process
    456//
    457// $r15 - current
    458// $r14 - process
    459// $r0  - zero
    460recv:
    461	push $r9
    462	push $r8
    463
    464	ld b32 $r8 D[$r14 + #proc_qget]
    465	ld b32 $r9 D[$r14 + #proc_qput]
    466	bclr $flags $p1
    467	cmp b32 $r8 $r9
    468	bra e #recv_done
    469		// dequeue message
    470		and $r9 $r8 #proc_qmaskp
    471		add b32 $r8 1
    472		and $r8 #proc_qmaskf
    473		st b32 D[$r14 + #proc_qget] $r8
    474		ld b32 $r10 D[$r14 + #proc_recv]
    475
    476		push $r15
    477		mov $r15 $flags
    478		push $r15
    479		mov b32 $r15 $r14
    480
    481		shl b32 $r9 $r9 #proc_qlen
    482		add b32 $r14 $r9
    483		add b32 $r14 #proc_queue
    484		ld b32 $r11 D[$r14 + #msg_data1]
    485		ld b32 $r12 D[$r14 + #msg_data0]
    486		ld b32 $r13 D[$r14 + #msg_message]
    487		ld b32 $r14 D[$r14 + #msg_process]
    488
    489		// process it
    490		call $r10
    491		pop $r15
    492		mov $flags $r15
    493		bset $flags $p1
    494		pop $r15
    495	recv_done:
    496	pop $r8
    497	pop $r9
    498	ret
    499
    500init:
    501	// setup stack
    502	nv_iord($r1, NV_PPWR_CAPS)
    503	extr $r1 $r1 9:17
    504	shl b32 $r1 8
    505	mov $sp $r1
    506
    507#ifdef NVKM_FALCON_MMIO_UAS
    508	// somehow allows the magic "access mmio via D[]" stuff that's
    509	// used by the nv_rd32/nv_wr32 macros to work
    510	imm32($r1, 0x10 | NV_PPWR_UAS_CONFIG_ENABLE)
    511	nv_iowrs(NV_PPWR_UAS_CONFIG, $r1)
    512#endif
    513
    514	// route all interrupts except user0/1 and pause to fuc
    515	imm32($r1, 0xe0)
    516	nv_iowr(NV_PPWR_INTR_ROUTE, $r1)
    517
    518	// enable watchdog and subintr intrs
    519	mov $r1 NV_PPWR_INTR_EN_CLR_MASK
    520	nv_iowr(NV_PPWR_INTR_EN_CLR, $r1)
    521	mov $r1 NV_PPWR_INTR_EN_SET_WATCHDOG
    522	or $r1 NV_PPWR_INTR_EN_SET_SUBINTR
    523	nv_iowr(NV_PPWR_INTR_EN_SET, $r1)
    524
    525	// enable interrupts globally
    526	imm32($r1, #intr)
    527	and $r1 0xffff
    528	mov $iv0 $r1
    529	bset $flags ie0
    530
    531	// enable watchdog timer
    532	mov $r1 1
    533	nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r1)
    534
    535	// bootstrap processes, idle process will be last, and not return
    536	mov $r15 #proc_list_head
    537	init_proc:
    538		ld b32 $r1 D[$r15 + #proc_init]
    539		cmp b32 $r1 0
    540		bra z #init_proc
    541		call $r1
    542		add b32 $r15 #proc_size
    543		bra #init_proc
    544#endif