1use core::{arch::asm, fmt};
4
5use loongArch64::register::badv;
6
7use crate::{GeneralRegisters, TrapFrame};
8
9core::arch::global_asm!(include_asm_macros!(), include_str!("unaligned.S"));
10
11extern "C" {
12 fn _unaligned_read(addr: u64, value: &mut u64, n: u64, symbol: bool) -> i32;
13 fn _unaligned_write(addr: u64, value: u64, n: u64) -> i32;
14}
15
16#[derive(Copy, Eq, PartialEq, Clone, Debug)]
18pub struct UnalignedError {
19 addr: u64,
20 n: Option<u64>,
21}
22
23impl fmt::Display for UnalignedError {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 if let Some(n) = self.n {
26 write!(f, "unaligned access at {:#x} (n={})", self.addr, n)
27 } else {
28 write!(f, "unaligned access at {:#x} (unknown op)", self.addr)
29 }
30 }
31}
32
33impl core::error::Error for UnalignedError {}
34
35fn unaligned_read(addr: u64, value: &mut u64, n: u64, symbol: bool) -> Result<(), UnalignedError> {
36 if unsafe { _unaligned_read(addr, value, n, symbol) } == -1 {
37 return Err(UnalignedError { addr, n: Some(n) });
38 }
39 Ok(())
40}
41
42fn unaligned_write(addr: u64, value: u64, n: u64) -> Result<(), UnalignedError> {
43 if unsafe { _unaligned_write(addr, value, n) } == -1 {
44 return Err(UnalignedError { addr, n: Some(n) });
45 }
46 Ok(())
47}
48
49#[inline]
50fn asm_write_fpr_0(val: u64) {
51 unsafe { asm!("movgr2fr.d $f0, {val} ", val = in(reg) val) }
52}
53
54#[inline]
55fn asm_write_fpr_1(val: u64) {
56 unsafe { asm!("movgr2fr.d $f1, {val} ", val = in(reg) val) }
57}
58
59#[inline]
60fn asm_write_fpr_2(val: u64) {
61 unsafe { asm!("movgr2fr.d $f2, {val} ", val = in(reg) val) }
62}
63
64#[inline]
65fn asm_write_fpr_3(val: u64) {
66 unsafe { asm!("movgr2fr.d $f3, {val} ", val = in(reg) val) }
67}
68
69#[inline]
70fn asm_write_fpr_4(val: u64) {
71 unsafe { asm!("movgr2fr.d $f4, {val} ", val = in(reg) val) }
72}
73
74#[inline]
75fn asm_write_fpr_5(val: u64) {
76 unsafe { asm!("movgr2fr.d $f5, {val} ", val = in(reg) val) }
77}
78
79#[inline]
80fn asm_write_fpr_6(val: u64) {
81 unsafe { asm!("movgr2fr.d $f6, {val} ", val = in(reg) val) }
82}
83
84#[inline]
85fn asm_write_fpr_7(val: u64) {
86 unsafe { asm!("movgr2fr.d $f7, {val} ", val = in(reg) val) }
87}
88
89#[inline]
90fn asm_write_fpr_8(val: u64) {
91 unsafe { asm!("movgr2fr.d $f8, {val} ", val = in(reg) val) }
92}
93
94#[inline]
95fn asm_write_fpr_9(val: u64) {
96 unsafe { asm!("movgr2fr.d $f9, {val} ", val = in(reg) val) }
97}
98
99#[inline]
100fn asm_write_fpr_10(val: u64) {
101 unsafe { asm!("movgr2fr.d $f10, {val} ", val = in(reg) val) }
102}
103
104#[inline]
105fn asm_write_fpr_11(val: u64) {
106 unsafe { asm!("movgr2fr.d $f11, {val} ", val = in(reg) val) }
107}
108
109#[inline]
110fn asm_write_fpr_12(val: u64) {
111 unsafe { asm!("movgr2fr.d $f12, {val} ", val = in(reg) val) }
112}
113
114#[inline]
115fn asm_write_fpr_13(val: u64) {
116 unsafe { asm!("movgr2fr.d $f13, {val} ", val = in(reg) val) }
117}
118
119#[inline]
120fn asm_write_fpr_14(val: u64) {
121 unsafe { asm!("movgr2fr.d $f14, {val} ", val = in(reg) val) }
122}
123
124#[inline]
125fn asm_write_fpr_15(val: u64) {
126 unsafe { asm!("movgr2fr.d $f15, {val} ", val = in(reg) val) }
127}
128
129#[inline]
130fn asm_write_fpr_16(val: u64) {
131 unsafe { asm!("movgr2fr.d $f16, {val} ", val = in(reg) val) }
132}
133
134#[inline]
135fn asm_write_fpr_17(val: u64) {
136 unsafe { asm!("movgr2fr.d $f17, {val} ", val = in(reg) val) }
137}
138
139#[inline]
140fn asm_write_fpr_18(val: u64) {
141 unsafe { asm!("movgr2fr.d $f18, {val} ", val = in(reg) val) }
142}
143
144#[inline]
145fn asm_write_fpr_19(val: u64) {
146 unsafe { asm!("movgr2fr.d $f19, {val} ", val = in(reg) val) }
147}
148
149#[inline]
150fn asm_write_fpr_20(val: u64) {
151 unsafe { asm!("movgr2fr.d $f20, {val} ", val = in(reg) val) }
152}
153
154#[inline]
155fn asm_write_fpr_21(val: u64) {
156 unsafe { asm!("movgr2fr.d $f21, {val} ", val = in(reg) val) }
157}
158
159#[inline]
160fn asm_write_fpr_22(val: u64) {
161 unsafe { asm!("movgr2fr.d $f22, {val} ", val = in(reg) val) }
162}
163
164#[inline]
165fn asm_write_fpr_23(val: u64) {
166 unsafe { asm!("movgr2fr.d $f23, {val} ", val = in(reg) val) }
167}
168
169#[inline]
170fn asm_write_fpr_24(val: u64) {
171 unsafe { asm!("movgr2fr.d $f24, {val} ", val = in(reg) val) }
172}
173
174#[inline]
175fn asm_write_fpr_25(val: u64) {
176 unsafe { asm!("movgr2fr.d $f25, {val} ", val = in(reg) val) }
177}
178
179#[inline]
180fn asm_write_fpr_26(val: u64) {
181 unsafe { asm!("movgr2fr.d $f26, {val} ", val = in(reg) val) }
182}
183
184#[inline]
185fn asm_write_fpr_27(val: u64) {
186 unsafe { asm!("movgr2fr.d $f27, {val} ", val = in(reg) val) }
187}
188
189#[inline]
190fn asm_write_fpr_28(val: u64) {
191 unsafe { asm!("movgr2fr.d $f28, {val} ", val = in(reg) val) }
192}
193
194#[inline]
195fn asm_write_fpr_29(val: u64) {
196 unsafe { asm!("movgr2fr.d $f29, {val} ", val = in(reg) val) }
197}
198
199#[inline]
200fn asm_write_fpr_30(val: u64) {
201 unsafe { asm!("movgr2fr.d $f30, {val} ", val = in(reg) val) }
202}
203
204#[inline]
205fn asm_write_fpr_31(val: u64) {
206 unsafe { asm!("movgr2fr.d $f31, {val} ", val = in(reg) val) }
207}
208
209#[inline]
210fn asm_read_fpr_0() -> u64 {
211 let mut value: u64;
212 unsafe { asm!( "movfr2gr.d {val}, $f0", val = out(reg) value) }
213 value
214}
215
216#[inline]
217fn asm_read_fpr_1() -> u64 {
218 let mut value: u64;
219 unsafe { asm!( "movfr2gr.d {val}, $f1", val = out(reg) value) }
220 value
221}
222
223#[inline]
224fn asm_read_fpr_2() -> u64 {
225 let mut value: u64;
226 unsafe { asm!( "movfr2gr.d {val}, $f2", val = out(reg) value) }
227 value
228}
229
230#[inline]
231fn asm_read_fpr_3() -> u64 {
232 let mut value: u64;
233 unsafe { asm!( "movfr2gr.d {val}, $f3", val = out(reg) value) }
234 value
235}
236
237#[inline]
238fn asm_read_fpr_4() -> u64 {
239 let mut value: u64;
240 unsafe { asm!( "movfr2gr.d {val}, $f4", val = out(reg) value) }
241 value
242}
243
244#[inline]
245fn asm_read_fpr_5() -> u64 {
246 let mut value: u64;
247 unsafe { asm!( "movfr2gr.d {val}, $f5", val = out(reg) value) }
248 value
249}
250
251#[inline]
252fn asm_read_fpr_6() -> u64 {
253 let mut value: u64;
254 unsafe { asm!( "movfr2gr.d {val}, $f6", val = out(reg) value) }
255 value
256}
257
258#[inline]
259fn asm_read_fpr_7() -> u64 {
260 let mut value: u64;
261 unsafe { asm!( "movfr2gr.d {val}, $f7", val = out(reg) value) }
262 value
263}
264
265#[inline]
266fn asm_read_fpr_8() -> u64 {
267 let mut value: u64;
268 unsafe { asm!( "movfr2gr.d {val}, $f8", val = out(reg) value) }
269 value
270}
271
272#[inline]
273fn asm_read_fpr_9() -> u64 {
274 let mut value: u64;
275 unsafe { asm!( "movfr2gr.d {val}, $f9", val = out(reg) value) }
276 value
277}
278
279#[inline]
280fn asm_read_fpr_10() -> u64 {
281 let mut value: u64;
282 unsafe { asm!( "movfr2gr.d {val}, $f10", val = out(reg) value) }
283 value
284}
285
286#[inline]
287fn asm_read_fpr_11() -> u64 {
288 let mut value: u64;
289 unsafe { asm!( "movfr2gr.d {val}, $f11", val = out(reg) value) }
290 value
291}
292
293#[inline]
294fn asm_read_fpr_12() -> u64 {
295 let mut value: u64;
296 unsafe { asm!( "movfr2gr.d {val}, $f12", val = out(reg) value) }
297 value
298}
299
300#[inline]
301fn asm_read_fpr_13() -> u64 {
302 let mut value: u64;
303 unsafe { asm!( "movfr2gr.d {val}, $f13", val = out(reg) value) }
304 value
305}
306
307#[inline]
308fn asm_read_fpr_14() -> u64 {
309 let mut value: u64;
310 unsafe { asm!( "movfr2gr.d {val}, $f14", val = out(reg) value) }
311 value
312}
313
314#[inline]
315fn asm_read_fpr_15() -> u64 {
316 let mut value: u64;
317 unsafe { asm!( "movfr2gr.d {val}, $f15", val = out(reg) value) }
318 value
319}
320
321#[inline]
322fn asm_read_fpr_16() -> u64 {
323 let mut value: u64;
324 unsafe { asm!( "movfr2gr.d {val}, $f16", val = out(reg) value) }
325 value
326}
327
328#[inline]
329fn asm_read_fpr_17() -> u64 {
330 let mut value: u64;
331 unsafe { asm!( "movfr2gr.d {val}, $f17", val = out(reg) value) }
332 value
333}
334
335#[inline]
336fn asm_read_fpr_18() -> u64 {
337 let mut value: u64;
338 unsafe { asm!( "movfr2gr.d {val}, $f18", val = out(reg) value) }
339 value
340}
341
342#[inline]
343fn asm_read_fpr_19() -> u64 {
344 let mut value: u64;
345 unsafe { asm!( "movfr2gr.d {val}, $f19", val = out(reg) value) }
346 value
347}
348
349#[inline]
350fn asm_read_fpr_20() -> u64 {
351 let mut value: u64;
352 unsafe { asm!( "movfr2gr.d {val}, $f20", val = out(reg) value) }
353 value
354}
355
356#[inline]
357fn asm_read_fpr_21() -> u64 {
358 let mut value: u64;
359 unsafe { asm!( "movfr2gr.d {val}, $f21", val = out(reg) value) }
360 value
361}
362
363#[inline]
364fn asm_read_fpr_22() -> u64 {
365 let mut value: u64;
366 unsafe { asm!( "movfr2gr.d {val}, $f22", val = out(reg) value) }
367 value
368}
369
370#[inline]
371fn asm_read_fpr_23() -> u64 {
372 let mut value: u64;
373 unsafe { asm!( "movfr2gr.d {val}, $f23", val = out(reg) value) }
374 value
375}
376
377#[inline]
378fn asm_read_fpr_24() -> u64 {
379 let mut value: u64;
380 unsafe { asm!( "movfr2gr.d {val}, $f24", val = out(reg) value) }
381 value
382}
383
384#[inline]
385fn asm_read_fpr_25() -> u64 {
386 let mut value: u64;
387 unsafe { asm!( "movfr2gr.d {val}, $f25", val = out(reg) value) }
388 value
389}
390
391#[inline]
392fn asm_read_fpr_26() -> u64 {
393 let mut value: u64;
394 unsafe { asm!( "movfr2gr.d {val}, $f26", val = out(reg) value) }
395 value
396}
397
398#[inline]
399fn asm_read_fpr_27() -> u64 {
400 let mut value: u64;
401 unsafe { asm!( "movfr2gr.d {val}, $f27", val = out(reg) value) }
402 value
403}
404
405#[inline]
406fn asm_read_fpr_28() -> u64 {
407 let mut value: u64;
408 unsafe { asm!( "movfr2gr.d {val}, $f28", val = out(reg) value) }
409 value
410}
411
412#[inline]
413fn asm_read_fpr_29() -> u64 {
414 let mut value: u64;
415 unsafe { asm!( "movfr2gr.d {val}, $f29", val = out(reg) value) }
416 value
417}
418
419#[inline]
420fn asm_read_fpr_30() -> u64 {
421 let mut value: u64;
422 unsafe { asm!( "movfr2gr.d {val}, $f30", val = out(reg) value) }
423 value
424}
425
426#[inline]
427fn asm_read_fpr_31() -> u64 {
428 let mut value: u64;
429 unsafe { asm!( "movfr2gr.d {val}, $f31", val = out(reg) value) }
430 value
431}
432
433pub fn write_fpr(fd: usize, val: u64) {
434 match fd {
435 0 => asm_write_fpr_0(val),
436 1 => asm_write_fpr_1(val),
437 2 => asm_write_fpr_2(val),
438 3 => asm_write_fpr_3(val),
439 4 => asm_write_fpr_4(val),
440 5 => asm_write_fpr_5(val),
441 6 => asm_write_fpr_6(val),
442 7 => asm_write_fpr_7(val),
443 8 => asm_write_fpr_8(val),
444 9 => asm_write_fpr_9(val),
445 10 => asm_write_fpr_10(val),
446 11 => asm_write_fpr_11(val),
447 12 => asm_write_fpr_12(val),
448 13 => asm_write_fpr_13(val),
449 14 => asm_write_fpr_14(val),
450 15 => asm_write_fpr_15(val),
451 16 => asm_write_fpr_16(val),
452 17 => asm_write_fpr_17(val),
453 18 => asm_write_fpr_18(val),
454 19 => asm_write_fpr_19(val),
455 20 => asm_write_fpr_20(val),
456 21 => asm_write_fpr_21(val),
457 22 => asm_write_fpr_22(val),
458 23 => asm_write_fpr_23(val),
459 24 => asm_write_fpr_24(val),
460 25 => asm_write_fpr_25(val),
461 26 => asm_write_fpr_26(val),
462 27 => asm_write_fpr_27(val),
463 28 => asm_write_fpr_28(val),
464 29 => asm_write_fpr_29(val),
465 30 => asm_write_fpr_30(val),
466 31 => asm_write_fpr_31(val),
467 _ => {
468 panic!("Undefined Float Register")
469 }
470 }
471}
472
473pub fn read_fpr(fd: usize) -> u64 {
474 let value: u64;
475 match fd {
476 0 => value = asm_read_fpr_0(),
477 1 => value = asm_read_fpr_1(),
478 2 => value = asm_read_fpr_2(),
479 3 => value = asm_read_fpr_3(),
480 4 => value = asm_read_fpr_4(),
481 5 => value = asm_read_fpr_5(),
482 6 => value = asm_read_fpr_6(),
483 7 => value = asm_read_fpr_7(),
484 8 => value = asm_read_fpr_8(),
485 9 => value = asm_read_fpr_9(),
486 10 => value = asm_read_fpr_10(),
487 11 => value = asm_read_fpr_11(),
488 12 => value = asm_read_fpr_12(),
489 13 => value = asm_read_fpr_13(),
490 14 => value = asm_read_fpr_14(),
491 15 => value = asm_read_fpr_15(),
492 16 => value = asm_read_fpr_16(),
493 17 => value = asm_read_fpr_17(),
494 18 => value = asm_read_fpr_18(),
495 19 => value = asm_read_fpr_19(),
496 20 => value = asm_read_fpr_20(),
497 21 => value = asm_read_fpr_21(),
498 22 => value = asm_read_fpr_22(),
499 23 => value = asm_read_fpr_23(),
500 24 => value = asm_read_fpr_24(),
501 25 => value = asm_read_fpr_25(),
502 26 => value = asm_read_fpr_26(),
503 27 => value = asm_read_fpr_27(),
504 28 => value = asm_read_fpr_28(),
505 29 => value = asm_read_fpr_29(),
506 30 => value = asm_read_fpr_30(),
507 31 => value = asm_read_fpr_31(),
508 _ => {
509 panic!("Undefined Float Register")
510 }
511 }
512 value
513}
514
515const LDH_OP: u32 = 0xa1;
516const LDHU_OP: u32 = 0xa9;
517const LDW_OP: u32 = 0xa2;
518const LDWU_OP: u32 = 0xaa;
519const LDD_OP: u32 = 0xa3;
520const STH_OP: u32 = 0xa5;
521const STW_OP: u32 = 0xa6;
522const STD_OP: u32 = 0xa7;
523
524const LDPTRW_OP: u32 = 0x24;
525const LDPTRD_OP: u32 = 0x26;
526const STPTRW_OP: u32 = 0x25;
527const STPTRD_OP: u32 = 0x27;
528
529const LDXH_OP: u32 = 0x7048;
530const LDXHU_OP: u32 = 0x7008;
531const LDXW_OP: u32 = 0x7010;
532const LDXWU_OP: u32 = 0x7050;
533const LDXD_OP: u32 = 0x7018;
534const STXH_OP: u32 = 0x7028;
535const STXW_OP: u32 = 0x7030;
536const STXD_OP: u32 = 0x7038;
537
538const FLDS_OP: u32 = 0xac;
539const FLDD_OP: u32 = 0xae;
540const FSTS_OP: u32 = 0xad;
541const FSTD_OP: u32 = 0xaf;
542
543const FSTXS_OP: u32 = 0x7070;
544const FSTXD_OP: u32 = 0x7078;
545const FLDXS_OP: u32 = 0x7060;
546const FLDXD_OP: u32 = 0x7068;
547
548impl TrapFrame {
549 pub unsafe fn emulate_unaligned(&mut self) -> Result<(), UnalignedError> {
555 let mut value: u64 = 0;
556
557 let badv = badv::read().vaddr() as u64;
558 let badi = core::ptr::read(self.era as *const u32);
559 let rd = (badi & 0x1f) as usize;
560
561 let regs = unsafe {
562 core::mem::transmute::<&mut GeneralRegisters, &mut [usize; 32]>(&mut self.regs)
563 };
564
565 if (badi >> 22) == LDD_OP || (badi >> 24) == LDPTRD_OP || (badi >> 15) == LDXD_OP {
566 unaligned_read(badv, &mut value, 8, true)?;
567 regs[rd] = value as usize;
568 } else if (badi >> 22) == LDW_OP || (badi >> 24) == LDPTRW_OP || (badi >> 15) == LDXW_OP {
569 unaligned_read(badv, &mut value, 4, true)?;
570 regs[rd] = value as usize;
571 } else if (badi >> 22) == LDWU_OP || (badi >> 15) == LDXWU_OP {
572 unaligned_read(badv, &mut value, 4, false)?;
573 regs[rd] = value as usize;
574 } else if (badi >> 22) == LDH_OP || (badi >> 15) == LDXH_OP {
575 unaligned_read(badv, &mut value, 2, true)?;
576 regs[rd] = value as usize;
577 } else if (badi >> 22) == LDHU_OP || (badi >> 15) == LDXHU_OP {
578 unaligned_read(badv, &mut value, 2, false)?;
579 regs[rd] = value as usize;
580 } else if (badi >> 22) == STD_OP || (badi >> 24) == STPTRD_OP || (badi >> 15) == STXD_OP {
581 value = regs[rd] as u64;
582 unaligned_write(badv, value, 8)?;
583 } else if (badi >> 22) == STW_OP || (badi >> 24) == STPTRW_OP || (badi >> 15) == STXW_OP {
584 value = regs[rd] as u64;
585 unaligned_write(badv, value, 4)?;
586 } else if (badi >> 22) == STH_OP || (badi >> 15) == STXH_OP {
587 value = regs[rd] as u64;
588 unaligned_write(badv, value, 2)?;
589 } else if (badi >> 22) == FLDD_OP || (badi >> 15) == FLDXD_OP {
590 unaligned_read(badv, &mut value, 8, true)?;
591 write_fpr(rd, value);
592 } else if (badi >> 22) == FLDS_OP || (badi >> 15) == FLDXS_OP {
593 unaligned_read(badv, &mut value, 4, true)?;
594 write_fpr(rd, value);
595 } else if (badi >> 22) == FSTD_OP || (badi >> 15) == FSTXD_OP {
596 value = read_fpr(rd);
597 unaligned_write(badv, value, 8)?;
598 } else if (badi >> 22) == FSTS_OP || (badi >> 15) == FSTXS_OP {
599 value = read_fpr(rd);
600 unaligned_write(badv, value, 4)?;
601 } else {
602 return Err(UnalignedError {
603 addr: badv,
604 n: None,
605 });
606 }
607
608 self.era += 4;
609
610 Ok(())
611 }
612}