VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR0/HWACCMR0A.asm@ 6311

Last change on this file since 6311 was 6258, checked in by vboxsync, 17 years ago

db x,y,z -> mnemonics; yasm supports them.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 17.7 KB
Line 
1; $Id: HWACCMR0A.asm 6258 2008-01-06 01:38:45Z vboxsync $
2;; @file
3; VMXM - R0 vmx helpers
4;
5
6;
7; Copyright (C) 2006-2007 innotek GmbH
8;
9; This file is part of VirtualBox Open Source Edition (OSE), as
10; available from http://www.virtualbox.org. This file is free software;
11; you can redistribute it and/or modify it under the terms of the GNU
12; General Public License (GPL) as published by the Free Software
13; Foundation, in version 2 as it comes in the "COPYING" file of the
14; VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16;
17
18;*******************************************************************************
19;* Header Files *
20;*******************************************************************************
21%include "VBox/asmdefs.mac"
22%include "VBox/err.mac"
23%include "VBox/hwacc_vmx.mac"
24%include "VBox/cpum.mac"
25%include "VBox/x86.mac"
26
27%ifdef RT_OS_OS2 ;; @todo fix OMF support in yasm and kick nasm out completely.
28 %macro vmwrite 2,
29 int3
30 %endmacro
31 %define vmlaunch int3
32 %define vmresume int3
33%endif
34
35
36;; @def MYPUSHAD
37; Macro generating an equivalent to pushad
38
39;; @def MYPOPAD
40; Macro generating an equivalent to popad
41
42;; @def MYPUSHSEGS
43; Macro saving all segment registers on the stack.
44; @param 1 full width register name
45; @param 2 16-bit regsiter name for \a 1.
46
47;; @def MYPOPSEGS
48; Macro restoring all segment registers on the stack
49; @param 1 full width register name
50; @param 2 16-bit regsiter name for \a 1.
51
52%ifdef RT_ARCH_AMD64
53 %ifdef ASM_CALL64_GCC
54 %macro MYPUSHAD 0
55 push r15
56 push r14
57 push r13
58 push r12
59 push rbx
60 %endmacro
61 %macro MYPOPAD 0
62 pop rbx
63 pop r12
64 pop r13
65 pop r14
66 pop r15
67 %endmacro
68
69 %else ; ASM_CALL64_MSC
70 %macro MYPUSHAD 0
71 push r15
72 push r14
73 push r13
74 push r12
75 push rbx
76 push rsi
77 push rdi
78 %endmacro
79 %macro MYPOPAD 0
80 pop rdi
81 pop rsi
82 pop rbx
83 pop r12
84 pop r13
85 pop r14
86 pop r15
87 %endmacro
88 %endif
89
90 %macro MYPUSHSEGS 2
91 mov %2, es
92 push %1
93 mov %2, ds
94 push %1
95 push fs
96 ; Special case for GS; OSes typically use swapgs to reset the hidden base register for GS on entry into the kernel. The same happens on exit
97 push rcx
98 mov ecx, MSR_K8_GS_BASE
99 rdmsr
100 pop rcx
101 push rdx
102 push rax
103 push gs
104 %endmacro
105
106 %macro MYPOPSEGS 2
107 ; Note: do not step through this code with a debugger!
108 pop gs
109 pop rax
110 pop rdx
111 push rcx
112 mov ecx, MSR_K8_GS_BASE
113 wrmsr
114 pop rcx
115 ; Now it's safe to step again
116
117 pop fs
118 pop %1
119 mov ds, %2
120 pop %1
121 mov es, %2
122 %endmacro
123
124%else ; RT_ARCH_X86
125 %macro MYPUSHAD 0
126 pushad
127 %endmacro
128 %macro MYPOPAD 0
129 popad
130 %endmacro
131
132 %macro MYPUSHSEGS 2
133 push ds
134 push es
135 push fs
136 push gs
137 %endmacro
138 %macro MYPOPSEGS 2
139 pop gs
140 pop fs
141 pop es
142 pop ds
143 %endmacro
144%endif
145
146
147BEGINCODE
148
149;/**
150; * Prepares for and executes VMLAUNCH
151; *
152; * @note identical to VMXResumeVM, except for the vmlaunch/vmresume opcode
153; *
154; * @returns VBox status code
155; * @param pCtx Guest context
156; */
157BEGINPROC VMXStartVM
158 push xBP
159 mov xBP, xSP
160
161 pushf
162 cli
163
164 ;/* First we have to save some final CPU context registers. */
165%ifdef RT_ARCH_AMD64
166 mov rax, qword .vmlaunch_done
167 push rax
168%else
169 push .vmlaunch_done
170%endif
171 mov eax, VMX_VMCS_HOST_RIP ;/* return address (too difficult to continue after VMLAUNCH?) */
172 vmwrite xAX, [xSP]
173 ;/* @todo assumes success... */
174 add xSP, xS
175
176 ;/* Manual save and restore:
177 ; * - General purpose registers except RIP, RSP
178 ; *
179 ; * Trashed:
180 ; * - CR2 (we don't care)
181 ; * - LDTR (reset to 0)
182 ; * - DRx (presumably not changed at all)
183 ; * - DR7 (reset to 0x400)
184 ; * - EFLAGS (reset to RT_BIT(1); not relevant)
185 ; *
186 ; */
187
188 ;/* Save all general purpose host registers. */
189 MYPUSHAD
190
191 ;/* Save segment registers */
192 MYPUSHSEGS xAX, ax
193
194 ;/* Save the Guest CPU context pointer. */
195%ifdef RT_ARCH_AMD64
196 %ifdef ASM_CALL64_GCC
197 mov rsi, rdi ; pCtx
198 %else
199 mov rsi, rcx ; pCtx
200 %endif
201%else
202 mov esi, [ebp + 8] ; pCtx
203%endif
204 push xSI
205
206 ; Save LDTR
207 xor eax, eax
208 sldt ax
209 push xAX
210
211 ; VMX only saves the base of the GDTR & IDTR and resets the limit to 0xffff; we must restore the limit correctly!
212 sub xSP, xS*2
213 sgdt [xSP]
214
215 sub xSP, xS*2
216 sidt [xSP]
217
218 ; Restore CR2
219 mov ebx, [xSI + CPUMCTX.cr2]
220 mov cr2, xBX
221
222 mov eax, VMX_VMCS_HOST_RSP
223 vmwrite xAX, xSP
224 ;/* @todo assumes success... */
225 ;/* Don't mess with ESP anymore!! */
226
227 ;/* Restore Guest's general purpose registers. */
228 mov eax, [xSI + CPUMCTX.eax]
229 mov ebx, [xSI + CPUMCTX.ebx]
230 mov ecx, [xSI + CPUMCTX.ecx]
231 mov edx, [xSI + CPUMCTX.edx]
232 mov edi, [xSI + CPUMCTX.edi]
233 mov ebp, [xSI + CPUMCTX.ebp]
234 mov esi, [xSI + CPUMCTX.esi]
235
236 vmlaunch
237 jmp .vmlaunch_done; ;/* here if vmlaunch detected a failure. */
238
239ALIGNCODE(16)
240.vmlaunch_done:
241 jc near .vmxstart_invalid_vmxon_ptr
242 jz near .vmxstart_start_failed
243
244 ; Restore base and limit of the IDTR & GDTR
245 lidt [xSP]
246 add xSP, xS*2
247 lgdt [xSP]
248 add xSP, xS*2
249
250 push xDI
251 mov xDI, [xSP + xS * 2] ; pCtx
252
253 mov [ss:xDI + CPUMCTX.eax], eax
254 mov [ss:xDI + CPUMCTX.ebx], ebx
255 mov [ss:xDI + CPUMCTX.ecx], ecx
256 mov [ss:xDI + CPUMCTX.edx], edx
257 mov [ss:xDI + CPUMCTX.esi], esi
258 mov [ss:xDI + CPUMCTX.ebp], ebp
259%ifdef RT_ARCH_AMD64
260 pop xAX ; the guest edi we pushed above
261 mov dword [ss:xDI + CPUMCTX.edi], eax
262%else
263 pop dword [ss:xDI + CPUMCTX.edi] ; the guest edi we pushed above
264%endif
265
266 pop xAX ; saved LDTR
267 lldt ax
268
269 add xSP, xS ; pCtx
270
271 ; Restore segment registers
272 MYPOPSEGS xAX, ax
273
274 ; Restore general purpose registers
275 MYPOPAD
276
277 mov eax, VINF_SUCCESS
278
279.vmstart_end:
280 popf
281 pop xBP
282 ret
283
284
285.vmxstart_invalid_vmxon_ptr:
286 ; Restore base and limit of the IDTR & GDTR
287 lidt [xSP]
288 add xSP, xS*2
289 lgdt [xSP]
290 add xSP, xS*2
291
292 pop xAX ; saved LDTR
293 lldt ax
294
295 add xSP, xS ; pCtx
296
297 ; Restore segment registers
298 MYPOPSEGS xAX, ax
299
300 ; Restore all general purpose host registers.
301 MYPOPAD
302 mov eax, VERR_VMX_INVALID_VMXON_PTR
303 jmp .vmstart_end
304
305.vmxstart_start_failed:
306 ; Restore base and limit of the IDTR & GDTR
307 lidt [xSP]
308 add xSP, xS*2
309 lgdt [xSP]
310 add xSP, xS*2
311
312 pop xAX ; saved LDTR
313 lldt ax
314
315 add xSP, xS ; pCtx
316
317 ; Restore segment registers
318 MYPOPSEGS xAX, ax
319
320 ; Restore all general purpose host registers.
321 MYPOPAD
322 mov eax, VERR_VMX_UNABLE_TO_START_VM
323 jmp .vmstart_end
324
325ENDPROC VMXStartVM
326
327
328;/**
329; * Prepares for and executes VMRESUME
330; *
331; * @note identical to VMXStartVM, except for the vmlaunch/vmresume opcode
332; *
333; * @returns VBox status code
334; * @param pCtx Guest context
335; */
336BEGINPROC VMXResumeVM
337 push xBP
338 mov xBP, xSP
339
340 pushf
341 cli
342
343 ;/* First we have to save some final CPU context registers. */
344%ifdef RT_ARCH_AMD64
345 mov rax, qword .vmresume_done
346 push rax
347%else
348 push .vmresume_done
349%endif
350 mov eax, VMX_VMCS_HOST_RIP ;/* return address (too difficult to continue after VMLAUNCH?) */
351 vmwrite xAX, [xSP]
352 ;/* @todo assumes success... */
353 add xSP, xS
354
355 ;/* Manual save and restore:
356 ; * - General purpose registers except RIP, RSP
357 ; *
358 ; * Trashed:
359 ; * - CR2 (we don't care)
360 ; * - LDTR (reset to 0)
361 ; * - DRx (presumably not changed at all)
362 ; * - DR7 (reset to 0x400)
363 ; * - EFLAGS (reset to RT_BIT(1); not relevant)
364 ; *
365 ; */
366
367 ;/* Save all general purpose host registers. */
368 MYPUSHAD
369
370 ;/* Save segment registers */
371 MYPUSHSEGS xAX, ax
372
373 ;/* Save the Guest CPU context pointer. */
374%ifdef RT_ARCH_AMD64
375 %ifdef ASM_CALL64_GCC
376 mov rsi, rdi ; pCtx
377 %else
378 mov rsi, rcx ; pCtx
379 %endif
380%else
381 mov esi, [ebp + 8] ; pCtx
382%endif
383 push xSI
384
385 ; Save LDTR
386 xor eax, eax
387 sldt ax
388 push xAX
389
390 ; VMX only saves the base of the GDTR & IDTR and resets the limit to 0xffff; we must restore the limit correctly!
391 sub xSP, xS*2
392 sgdt [xSP]
393
394 sub xSP, xS*2
395 sidt [xSP]
396
397 ; Restore CR2
398 mov xBX, [xSI + CPUMCTX.cr2]
399 mov cr2, xBX
400
401 mov eax, VMX_VMCS_HOST_RSP
402 vmwrite xAX, xSP
403 ;/* @todo assumes success... */
404 ;/* Don't mess with ESP anymore!! */
405
406 ;/* Restore Guest's general purpose registers. */
407 mov eax, [xSI + CPUMCTX.eax]
408 mov ebx, [xSI + CPUMCTX.ebx]
409 mov ecx, [xSI + CPUMCTX.ecx]
410 mov edx, [xSI + CPUMCTX.edx]
411 mov edi, [xSI + CPUMCTX.edi]
412 mov ebp, [xSI + CPUMCTX.ebp]
413 mov esi, [xSI + CPUMCTX.esi]
414
415 vmresume
416 jmp .vmresume_done; ;/* here if vmresume detected a failure. */
417
418ALIGNCODE(16)
419.vmresume_done:
420 jc near .vmxresume_invalid_vmxon_ptr
421 jz near .vmxresume_start_failed
422
423 ; Restore base and limit of the IDTR & GDTR
424 lidt [xSP]
425 add xSP, xS*2
426 lgdt [xSP]
427 add xSP, xS*2
428
429 push xDI
430 mov xDI, [xSP + xS * 2] ; pCtx
431
432 mov [ss:xDI + CPUMCTX.eax], eax
433 mov [ss:xDI + CPUMCTX.ebx], ebx
434 mov [ss:xDI + CPUMCTX.ecx], ecx
435 mov [ss:xDI + CPUMCTX.edx], edx
436 mov [ss:xDI + CPUMCTX.esi], esi
437 mov [ss:xDI + CPUMCTX.ebp], ebp
438%ifdef RT_ARCH_AMD64
439 pop xAX ; the guest edi we pushed above
440 mov dword [ss:xDI + CPUMCTX.edi], eax
441%else
442 pop dword [ss:xDI + CPUMCTX.edi] ; the guest edi we pushed above
443%endif
444
445 pop xAX ; saved LDTR
446 lldt ax
447
448 add xSP, xS ; pCtx
449
450 ; Restore segment registers
451 MYPOPSEGS xAX, ax
452
453 ; Restore general purpose registers
454 MYPOPAD
455
456 mov eax, VINF_SUCCESS
457
458.vmresume_end:
459 popf
460 pop xBP
461 ret
462
463.vmxresume_invalid_vmxon_ptr:
464 ; Restore base and limit of the IDTR & GDTR
465 lidt [xSP]
466 add xSP, xS*2
467 lgdt [xSP]
468 add xSP, xS*2
469
470 pop xAX ; saved LDTR
471 lldt ax
472
473 add xSP, xS ; pCtx
474
475 ; Restore segment registers
476 MYPOPSEGS xAX, ax
477
478 ; Restore all general purpose host registers.
479 MYPOPAD
480 mov eax, VERR_VMX_INVALID_VMXON_PTR
481 jmp .vmresume_end
482
483.vmxresume_start_failed:
484 ; Restore base and limit of the IDTR & GDTR
485 lidt [xSP]
486 add xSP, xS*2
487 lgdt [xSP]
488 add xSP, xS*2
489
490 pop xAX ; saved LDTR
491 lldt ax
492
493 add xSP, xS ; pCtx
494
495 ; Restore segment registers
496 MYPOPSEGS xAX, ax
497
498 ; Restore all general purpose host registers.
499 MYPOPAD
500 mov eax, VERR_VMX_UNABLE_TO_RESUME_VM
501 jmp .vmresume_end
502
503ENDPROC VMXResumeVM
504
505
506%ifdef RT_ARCH_AMD64
507;/**
508; * Executes VMWRITE
509; *
510; * @returns VBox status code
511; * @param idxField x86: [ebp + 08h] msc: rcx gcc: edi VMCS index
512; * @param pData x86: [ebp + 0ch] msc: rdx gcc: rsi VM field value
513; */
514BEGINPROC VMXWriteVMCS64
515%ifdef ASM_CALL64_GCC
516 mov eax, 0ffffffffh
517 and rdi, rax
518 xor rax, rax
519 vmwrite rdi, rsi
520%else
521 mov eax, 0ffffffffh
522 and rcx, rax
523 xor rax, rax
524 vmwrite rcx, rdx
525%endif
526 jnc .valid_vmcs
527 mov eax, VERR_VMX_INVALID_VMCS_PTR
528 ret
529.valid_vmcs:
530 jnz .the_end
531 mov eax, VERR_VMX_INVALID_VMCS_FIELD
532.the_end:
533 ret
534ENDPROC VMXWriteVMCS64
535
536;/**
537; * Executes VMREAD
538; *
539; * @returns VBox status code
540; * @param idxField VMCS index
541; * @param pData Ptr to store VM field value
542; */
543;DECLASM(int) VMXReadVMCS64(uint32_t idxField, uint64_t *pData);
544BEGINPROC VMXReadVMCS64
545%ifdef ASM_CALL64_GCC
546 mov eax, 0ffffffffh
547 and rdi, rax
548 xor rax, rax
549 vmread [rsi], rdi
550%else
551 mov eax, 0ffffffffh
552 and rcx, rax
553 xor rax, rax
554 vmread [rdx], rcx
555%endif
556 jnc .valid_vmcs
557 mov eax, VERR_VMX_INVALID_VMCS_PTR
558 ret
559.valid_vmcs:
560 jnz .the_end
561 mov eax, VERR_VMX_INVALID_VMCS_FIELD
562.the_end:
563 ret
564ENDPROC VMXReadVMCS64
565
566
567;/**
568; * Executes VMXON
569; *
570; * @returns VBox status code
571; * @param HCPhysVMXOn Physical address of VMXON structure
572; */
573;DECLASM(int) VMXEnable(RTHCPHYS HCPhysVMXOn);
574BEGINPROC VMXEnable
575%ifdef RT_ARCH_AMD64
576 xor rax, rax
577 %ifdef ASM_CALL64_GCC
578 push rdi
579 %else
580 push rcx
581 %endif
582 vmxon [rsp]
583%else
584 xor eax, eax
585 vmxon [esp + 4]
586%endif
587 jnc .good
588 mov eax, VERR_VMX_INVALID_VMXON_PTR
589 jmp .the_end
590
591.good:
592 jnz .the_end
593 mov eax, VERR_VMX_GENERIC
594
595.the_end:
596%ifdef RT_ARCH_AMD64
597 add rsp, 8
598%endif
599 ret
600ENDPROC VMXEnable
601
602
603;/**
604; * Executes VMXOFF
605; */
606;DECLASM(void) VMXDisable(void);
607BEGINPROC VMXDisable
608 vmxoff
609 ret
610ENDPROC VMXDisable
611
612
613;/**
614; * Executes VMCLEAR
615; *
616; * @returns VBox status code
617; * @param HCPhysVMCS Physical address of VM control structure
618; */
619;DECLASM(int) VMXClearVMCS(RTHCPHYS HCPhysVMCS);
620BEGINPROC VMXClearVMCS
621%ifdef RT_ARCH_AMD64
622 xor rax, rax
623 %ifdef ASM_CALL64_GCC
624 push rdi
625 %else
626 push rcx
627 %endif
628 vmclear [rsp]
629%else
630 xor eax, eax
631 vmclear [esp + 4]
632%endif
633 jnc .the_end
634 mov eax, VERR_VMX_INVALID_VMCS_PTR
635.the_end:
636%ifdef RT_ARCH_AMD64
637 add rsp, 8
638%endif
639 ret
640ENDPROC VMXClearVMCS
641
642
643;/**
644; * Executes VMPTRLD
645; *
646; * @returns VBox status code
647; * @param HCPhysVMCS Physical address of VMCS structure
648; */
649;DECLASM(int) VMXActivateVMCS(RTHCPHYS HCPhysVMCS);
650BEGINPROC VMXActivateVMCS
651%ifdef RT_ARCH_AMD64
652 xor rax, rax
653 %ifdef ASM_CALL64_GCC
654 push rdi
655 %else
656 push rcx
657 %endif
658 vmptrld [rsp]
659%else
660 xor eax, eax
661 vmptrld [esp + 4]
662%endif
663 jnc .the_end
664 mov eax, VERR_VMX_INVALID_VMCS_PTR
665.the_end:
666%ifdef RT_ARCH_AMD64
667 add rsp, 8
668%endif
669 ret
670ENDPROC VMXActivateVMCS
671
672%endif ; RT_ARCH_AMD64
673
674
675;/**
676; * Prepares for and executes VMRUN
677; *
678; * @returns VBox status code
679; * @param HCPhysVMCB Physical address of host VMCB
680; * @param HCPhysVMCB Physical address of guest VMCB
681; * @param pCtx Guest context
682; */
683BEGINPROC SVMVMRun
684%ifdef RT_ARCH_AMD64 ; fake a cdecl stack frame - I'm lazy, sosume.
685 %ifdef ASM_CALL64_GCC
686 push rdx
687 push rsi
688 push rdi
689 %else
690 push r8
691 push rdx
692 push rcx
693 %endif
694 push 0
695%endif
696 push xBP
697 mov xBP, xSP
698
699 ;/* Manual save and restore:
700 ; * - General purpose registers except RIP, RSP, RAX
701 ; *
702 ; * Trashed:
703 ; * - CR2 (we don't care)
704 ; * - LDTR (reset to 0)
705 ; * - DRx (presumably not changed at all)
706 ; * - DR7 (reset to 0x400)
707 ; */
708
709 ;/* Save all general purpose host registers. */
710 MYPUSHAD
711
712 ;/* Save the Guest CPU context pointer. */
713 mov xSI, [xBP + xS*2 + RTHCPHYS_CB*2] ; pCtx
714 push xSI ; push for saving the state at the end
715
716 ; Restore CR2
717 mov ebx, [xSI + CPUMCTX.cr2]
718 mov cr2, xBX
719
720 ; save host fs, gs, sysenter msr etc
721 mov xAX, [xBP + xS*2] ; pVMCBHostPhys (64 bits physical address; x86: take low dword only)
722 push xAX ; save for the vmload after vmrun
723 vmsave
724
725 ; setup eax for VMLOAD
726 mov xAX, [xBP + xS*2 + RTHCPHYS_CB] ; pVMCBPhys (64 bits physical address; take low dword only)
727
728 ;/* Restore Guest's general purpose registers. */
729 ;/* EAX is loaded from the VMCB by VMRUN */
730 mov ebx, [xSI + CPUMCTX.ebx]
731 mov ecx, [xSI + CPUMCTX.ecx]
732 mov edx, [xSI + CPUMCTX.edx]
733 mov edi, [xSI + CPUMCTX.edi]
734 mov ebp, [xSI + CPUMCTX.ebp]
735 mov esi, [xSI + CPUMCTX.esi]
736
737 ; Clear the global interrupt flag & execute sti to make sure external interrupts cause a world switch
738 clgi
739 sti
740
741 ; load guest fs, gs, sysenter msr etc
742 vmload
743 ; run the VM
744 vmrun
745
746 ;/* EAX is in the VMCB already; we can use it here. */
747
748 ; save guest fs, gs, sysenter msr etc
749 vmsave
750
751 ; load host fs, gs, sysenter msr etc
752 pop xAX ; pushed above
753 vmload
754
755 ; Set the global interrupt flag again, but execute cli to make sure IF=0.
756 cli
757 stgi
758
759 pop xAX ; pCtx
760
761 mov [ss:xAX + CPUMCTX.ebx], ebx
762 mov [ss:xAX + CPUMCTX.ecx], ecx
763 mov [ss:xAX + CPUMCTX.edx], edx
764 mov [ss:xAX + CPUMCTX.esi], esi
765 mov [ss:xAX + CPUMCTX.edi], edi
766 mov [ss:xAX + CPUMCTX.ebp], ebp
767
768 ; Restore general purpose registers
769 MYPOPAD
770
771 mov eax, VINF_SUCCESS
772
773 pop xBP
774%ifdef RT_ARCH_AMD64
775 add xSP, 4*xS
776%endif
777 ret
778ENDPROC SVMVMRun
779
780
781;;
782; Executes INVLPGA
783;
784; @param pPageGC msc:ecx gcc:edi x86:[esp+04] Virtual page to invalidate
785; @param uASID msc:edx gcc:esi x86:[esp+08] Tagged TLB id
786;
787;DECLASM(void) SVMInvlpgA(RTGCPTR pPageGC, uint32_t uASID);
788BEGINPROC SVMInvlpgA
789%ifdef RT_ARCH_AMD64
790 %ifdef ASM_CALL64_GCC
791 mov eax, edi ;; @todo 64-bit guest.
792 mov ecx, esi
793 %else
794 mov eax, ecx ;; @todo 64-bit guest.
795 mov ecx, edx
796 %endif
797%else
798 mov eax, [esp + 4]
799 mov ecx, [esp + 8]
800%endif
801 invlpga [xAX], ecx
802 ret
803ENDPROC SVMInvlpgA
804
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette