VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxService/VBoxServiceCpuHotPlug.cpp@ 58029

Last change on this file since 58029 was 58029, checked in by vboxsync, 10 years ago

VBoxService: Using prefix 'VGSvc', code style/width cleanups. No real changes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.9 KB
Line 
1/* $Id: VBoxServiceCpuHotPlug.cpp 58029 2015-10-05 20:50:18Z vboxsync $ */
2/** @file
3 * VBoxService - Guest Additions CPU Hot Plugging Service.
4 */
5
6/*
7 * Copyright (C) 2010-2015 Oracle Corporation
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/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#include <iprt/assert.h>
23#include <iprt/dir.h>
24#include <iprt/file.h>
25#include <iprt/mem.h>
26#include <iprt/path.h>
27#include <iprt/string.h>
28#include <iprt/thread.h>
29#include <VBox/VBoxGuestLib.h>
30#include "VBoxServiceInternal.h"
31
32#ifdef RT_OS_LINUX
33# include <iprt/linux/sysfs.h>
34# include <errno.h> /* For the sysfs API */
35#endif
36
37
38/*********************************************************************************************************************************
39* Defined Constants And Macros *
40*********************************************************************************************************************************/
41#ifdef RT_OS_LINUX
42
43/** @name Paths to access the CPU device
44 * @{
45 */
46# define SYSFS_ACPI_CPU_PATH "/sys/devices"
47# define SYSFS_CPU_PATH "/sys/devices/system/cpu"
48/** @} */
49
50/** Path component for the ACPI CPU path. */
51typedef struct SYSFSCPUPATHCOMP
52{
53 /** Flag whether the name is suffixed with a number */
54 bool fNumberedSuffix;
55 /** Name of the component */
56 const char *pcszName;
57} SYSFSCPUPATHCOMP, *PSYSFSCPUPATHCOMP;
58/** Pointer to a const component. */
59typedef const SYSFSCPUPATHCOMP *PCSYSFSCPUPATHCOMP;
60
61/**
62 * Structure which defines how the entries are assembled.
63 */
64typedef struct SYSFSCPUPATH
65{
66 /** Id when probing for the correct path. */
67 uint32_t uId;
68 /** Array holding the possible components. */
69 PCSYSFSCPUPATHCOMP aComponentsPossible;
70 /** Number of entries in the array, excluding the terminator. */
71 unsigned cComponents;
72 /** Directory handle */
73 PRTDIR pDir;
74 /** Current directory to try. */
75 char *pszPath;
76} SYSFSCPUPATH, *PSYSFSCPUPATH;
77
78/** Content of uId if the path wasn't probed yet. */
79# define ACPI_CPU_PATH_NOT_PROBED UINT32_MAX
80#endif /* RT_OS_LINUX*/
81
82
83/*********************************************************************************************************************************
84* Global Variables *
85*********************************************************************************************************************************/
86#ifdef RT_OS_LINUX
87/** Possible combinations of all path components for level 1. */
88static const SYSFSCPUPATHCOMP g_aAcpiCpuPathLvl1[] =
89{
90 /** LNXSYSTEM:<id> */
91 { true, "LNXSYSTM:*" }
92};
93
94/** Possible combinations of all path components for level 2. */
95static const SYSFSCPUPATHCOMP g_aAcpiCpuPathLvl2[] =
96{
97 /** device:<id> */
98 {true, "device:*"},
99 /** LNXSYBUS:<id> */
100 {true, "LNXSYBUS:*"}
101};
102
103/** Possible combinations of all path components for level 3 */
104static const SYSFSCPUPATHCOMP g_aAcpiCpuPathLvl3[] =
105{
106 /** ACPI0004:<id> */
107 {true, "ACPI0004:*"}
108};
109
110/** Possible combinations of all path components for level 4 */
111static const SYSFSCPUPATHCOMP g_aAcpiCpuPathLvl4[] =
112{
113 /** LNXCPU:<id> */
114 {true, "LNXCPU:*"},
115 /** ACPI_CPU:<id> */
116 {true, "ACPI_CPU:*"}
117};
118
119/** All possible combinations. */
120static SYSFSCPUPATH g_aAcpiCpuPath[] =
121{
122 /** Level 1 */
123 {ACPI_CPU_PATH_NOT_PROBED, g_aAcpiCpuPathLvl1, RT_ELEMENTS(g_aAcpiCpuPathLvl1), NULL, NULL},
124 /** Level 2 */
125 {ACPI_CPU_PATH_NOT_PROBED, g_aAcpiCpuPathLvl2, RT_ELEMENTS(g_aAcpiCpuPathLvl2), NULL, NULL},
126 /** Level 3 */
127 {ACPI_CPU_PATH_NOT_PROBED, g_aAcpiCpuPathLvl3, RT_ELEMENTS(g_aAcpiCpuPathLvl3), NULL, NULL},
128 /** Level 4 */
129 {ACPI_CPU_PATH_NOT_PROBED, g_aAcpiCpuPathLvl4, RT_ELEMENTS(g_aAcpiCpuPathLvl4), NULL, NULL},
130};
131
132/**
133 * Possible directories to get to the topology directory for reading core and package id.
134 *
135 * @remark: This is not part of the path above because the eject file is not in one of the directories
136 * below and would make the hot unplug code fail.
137 */
138static const char *g_apszTopologyPath[] =
139{
140 "sysdev",
141 "physical_node"
142};
143
144#endif /* RT_OS_LINUX*/
145
146
147#ifdef RT_OS_LINUX
148
149/**
150 * Probes for the correct path to the ACPI CPU object in sysfs for the
151 * various different kernel versions and distro's.
152 *
153 * @returns VBox status code.
154 */
155static int vgsvcCpuHotPlugProbePath(void)
156{
157 int rc = VINF_SUCCESS;
158
159 /* Probe for the correct path if we didn't already. */
160 if (RT_UNLIKELY(g_aAcpiCpuPath[0].uId == ACPI_CPU_PATH_NOT_PROBED))
161 {
162 char *pszPath = NULL; /** < Current path, increasing while we dig deeper. */
163
164 pszPath = RTStrDup(SYSFS_ACPI_CPU_PATH);
165 if (!pszPath)
166 return VERR_NO_MEMORY;
167
168 /*
169 * Simple algorithm to find the path.
170 * Performance is not a real problem because it is
171 * only executed once.
172 */
173 for (unsigned iLvlCurr = 0; iLvlCurr < RT_ELEMENTS(g_aAcpiCpuPath); iLvlCurr++)
174 {
175 PSYSFSCPUPATH pAcpiCpuPathLvl = &g_aAcpiCpuPath[iLvlCurr];
176
177 for (unsigned iCompCurr = 0; iCompCurr < pAcpiCpuPathLvl->cComponents; iCompCurr++)
178 {
179 PCSYSFSCPUPATHCOMP pPathComponent = &pAcpiCpuPathLvl->aComponentsPossible[iCompCurr];
180
181 /* Open the directory */
182 PRTDIR pDirCurr = NULL;
183 char *pszPathTmp = RTPathJoinA(pszPath, pPathComponent->pcszName);
184 if (pszPathTmp)
185 {
186 rc = RTDirOpenFiltered(&pDirCurr, pszPathTmp, RTDIRFILTER_WINNT, 0);
187 RTStrFree(pszPathTmp);
188 }
189 else
190 rc = VERR_NO_STR_MEMORY;
191 if (RT_FAILURE(rc))
192 break;
193
194 /* Search if the current directory contains one of the possible parts. */
195 size_t cchName = strlen(pPathComponent->pcszName);
196 RTDIRENTRY DirFolderContent;
197 bool fFound = false;
198
199 /* Get rid of the * filter which is in the path component. */
200 if (pPathComponent->fNumberedSuffix)
201 cchName--;
202
203 while (RT_SUCCESS(RTDirRead(pDirCurr, &DirFolderContent, NULL))) /* Assumption that szName has always enough space */
204 {
205 if ( DirFolderContent.cbName >= cchName
206 && !strncmp(DirFolderContent.szName, pPathComponent->pcszName, cchName))
207 {
208 /* Found, use the complete name to dig deeper. */
209 fFound = true;
210 pAcpiCpuPathLvl->uId = iCompCurr;
211 char *pszPathLvl = RTPathJoinA(pszPath, DirFolderContent.szName);
212 if (pszPathLvl)
213 {
214 RTStrFree(pszPath);
215 pszPath = pszPathLvl;
216 }
217 else
218 rc = VERR_NO_STR_MEMORY;
219 break;
220 }
221 }
222 RTDirClose(pDirCurr);
223
224 if (fFound)
225 break;
226 } /* For every possible component. */
227
228 /* No matching component for this part, no need to continue */
229 if (RT_FAILURE(rc))
230 break;
231 } /* For every level */
232
233 VGSvcVerbose(1, "Final path after probing %s rc=%Rrc\n", pszPath, rc);
234 RTStrFree(pszPath);
235 }
236
237 return rc;
238}
239
240
241/**
242 * Returns the path of the ACPI CPU device with the given core and package ID.
243 *
244 * @returns VBox status code.
245 * @param ppszPath Where to store the path.
246 * @param idCpuCore The core ID of the CPU.
247 * @param idCpuPackage The package ID of the CPU.
248 */
249static int vgsvcCpuHotPlugGetACPIDevicePath(char **ppszPath, uint32_t idCpuCore, uint32_t idCpuPackage)
250{
251 int rc = VINF_SUCCESS;
252
253 AssertPtrReturn(ppszPath, VERR_INVALID_PARAMETER);
254
255 rc = vgsvcCpuHotPlugProbePath();
256 if (RT_SUCCESS(rc))
257 {
258 /* Build the path from all components. */
259 bool fFound = false;
260 unsigned iLvlCurr = 0;
261 char *pszPath = NULL;
262 char *pszPathDir = NULL;
263 PSYSFSCPUPATH pAcpiCpuPathLvl = &g_aAcpiCpuPath[iLvlCurr];
264
265 /* Init everything. */
266 Assert(pAcpiCpuPathLvl->uId != ACPI_CPU_PATH_NOT_PROBED);
267 pszPath = RTPathJoinA(SYSFS_ACPI_CPU_PATH, pAcpiCpuPathLvl->aComponentsPossible[pAcpiCpuPathLvl->uId].pcszName);
268 if (!pszPath)
269 return VERR_NO_STR_MEMORY;
270
271 pAcpiCpuPathLvl->pszPath = RTStrDup(SYSFS_ACPI_CPU_PATH);
272 if (!pAcpiCpuPathLvl->pszPath)
273 {
274 RTStrFree(pszPath);
275 return VERR_NO_STR_MEMORY;
276 }
277
278 /* Open the directory */
279 rc = RTDirOpenFiltered(&pAcpiCpuPathLvl->pDir, pszPath, RTDIRFILTER_WINNT, 0);
280 if (RT_SUCCESS(rc))
281 {
282 RTStrFree(pszPath);
283
284 /* Search for CPU */
285 while (!fFound)
286 {
287 /* Get the next directory. */
288 RTDIRENTRY DirFolderContent;
289 rc = RTDirRead(pAcpiCpuPathLvl->pDir, &DirFolderContent, NULL);
290 if (RT_SUCCESS(rc))
291 {
292 /* Create the new path. */
293 char *pszPathCurr = RTPathJoinA(pAcpiCpuPathLvl->pszPath, DirFolderContent.szName);
294 if (!pszPathCurr)
295 {
296 rc = VERR_NO_STR_MEMORY;
297 break;
298 }
299
300 /* If this is the last level check for the given core and package id. */
301 if (iLvlCurr == RT_ELEMENTS(g_aAcpiCpuPath) - 1)
302 {
303 /* Get the sysdev */
304 uint32_t idCore = 0;
305 uint32_t idPackage = 0;
306
307 for (unsigned i = 0; i < RT_ELEMENTS(g_apszTopologyPath); i++)
308 {
309 int64_t i64Core = RTLinuxSysFsReadIntFile(10, "%s/%s/topology/core_id",
310 pszPathCurr, g_apszTopologyPath[i]);
311 int64_t i64Package = RTLinuxSysFsReadIntFile(10, "%s/%s/topology/physical_package_id",
312 pszPathCurr, g_apszTopologyPath[i]);
313
314 if ( i64Core != -1
315 && i64Package != -1)
316 {
317 idCore = (uint32_t)i64Core;
318 idPackage = (uint32_t)i64Package;
319 break;
320 }
321 }
322
323 if ( idCore == idCpuCore
324 && idPackage == idCpuPackage)
325 {
326 /* Return the path */
327 pszPath = pszPathCurr;
328 fFound = true;
329 VGSvcVerbose(3, "CPU found\n");
330 break;
331 }
332 else
333 {
334 /* Get the next directory. */
335 RTStrFree(pszPathCurr);
336 VGSvcVerbose(3, "CPU doesn't match, next directory\n");
337 }
338 }
339 else
340 {
341 /* Go deeper */
342 iLvlCurr++;
343
344 VGSvcVerbose(3, "Going deeper (iLvlCurr=%u)\n", iLvlCurr);
345
346 pAcpiCpuPathLvl = &g_aAcpiCpuPath[iLvlCurr];
347
348 Assert(!pAcpiCpuPathLvl->pDir);
349 Assert(!pAcpiCpuPathLvl->pszPath);
350 pAcpiCpuPathLvl->pszPath = pszPathCurr;
351 PCSYSFSCPUPATHCOMP pPathComponent = &pAcpiCpuPathLvl->aComponentsPossible[pAcpiCpuPathLvl->uId];
352
353 Assert(pAcpiCpuPathLvl->uId != ACPI_CPU_PATH_NOT_PROBED);
354
355 pszPathDir = RTPathJoinA(pszPathCurr, pPathComponent->pcszName);
356 if (!pszPathDir)
357 {
358 rc = VERR_NO_STR_MEMORY;
359 break;
360 }
361
362 VGSvcVerbose(3, "New path %s\n", pszPathDir);
363
364 /* Open the directory */
365 rc = RTDirOpenFiltered(&pAcpiCpuPathLvl->pDir, pszPathDir, RTDIRFILTER_WINNT, 0);
366 if (RT_FAILURE(rc))
367 break;
368 }
369 }
370 else
371 {
372 /* Go back one level and try to get the next entry. */
373 Assert(iLvlCurr > 0);
374
375 RTDirClose(pAcpiCpuPathLvl->pDir);
376 RTStrFree(pAcpiCpuPathLvl->pszPath);
377 pAcpiCpuPathLvl->pDir = NULL;
378 pAcpiCpuPathLvl->pszPath = NULL;
379
380 iLvlCurr--;
381 pAcpiCpuPathLvl = &g_aAcpiCpuPath[iLvlCurr];
382 VGSvcVerbose(3, "Directory not found, going back (iLvlCurr=%u)\n", iLvlCurr);
383 }
384 } /* while not found */
385 } /* Successful init */
386
387 /* Cleanup */
388 for (unsigned i = 0; i < RT_ELEMENTS(g_aAcpiCpuPath); i++)
389 {
390 if (g_aAcpiCpuPath[i].pDir)
391 RTDirClose(g_aAcpiCpuPath[i].pDir);
392 if (g_aAcpiCpuPath[i].pszPath)
393 RTStrFree(g_aAcpiCpuPath[i].pszPath);
394 g_aAcpiCpuPath[i].pDir = NULL;
395 g_aAcpiCpuPath[i].pszPath = NULL;
396 }
397 if (pszPathDir)
398 RTStrFree(pszPathDir);
399 if (RT_FAILURE(rc) && pszPath)
400 RTStrFree(pszPath);
401
402 if (RT_SUCCESS(rc))
403 *ppszPath = pszPath;
404 }
405
406 return rc;
407}
408
409#endif /* RT_OS_LINUX */
410
411/**
412 * Handles VMMDevCpuEventType_Plug.
413 *
414 * @param idCpuCore The CPU core ID.
415 * @param idCpuPackage The CPU package ID.
416 */
417static void vgsvcCpuHotPlugHandlePlugEvent(uint32_t idCpuCore, uint32_t idCpuPackage)
418{
419#ifdef RT_OS_LINUX
420 /*
421 * The topology directory (containing the physical and core id properties)
422 * is not available until the CPU is online. So we just iterate over all directories
423 * and enable every CPU which is not online already.
424 * Because the directory might not be available immediately we try a few times.
425 *
426 */
427 /** @todo Maybe use udev to monitor hot-add events from the kernel */
428 bool fCpuOnline = false;
429 unsigned cTries = 5;
430
431 do
432 {
433 PRTDIR pDirDevices = NULL;
434 int rc = RTDirOpen(&pDirDevices, SYSFS_CPU_PATH);
435 if (RT_SUCCESS(rc))
436 {
437 RTDIRENTRY DirFolderContent;
438 while (RT_SUCCESS(RTDirRead(pDirDevices, &DirFolderContent, NULL))) /* Assumption that szName has always enough space */
439 {
440 /** @todo r-bird: This code is bringing all CPUs online; the idCpuCore and
441 * idCpuPackage parameters are unused!
442 * aeichner: These files are not available at this point unfortunately. (see comment above)
443 * bird: Yes, but isn't that easily dealt with by doing:
444 * if (matching_topology() || !have_topology_directory())
445 * bring_cpu_online()
446 * That could save you the cpu0 and cpuidle checks to.
447 */
448 /*
449 * Check if this is a CPU object.
450 * cpu0 is excluded because it is not possible to change the state
451 * of the first CPU on Linux (it doesn't even have an online file)
452 * and cpuidle is no CPU device. Prevents error messages later.
453 */
454 if( !strncmp(DirFolderContent.szName, "cpu", 3)
455 && strncmp(DirFolderContent.szName, "cpu0", 4)
456 && strncmp(DirFolderContent.szName, "cpuidle", 7))
457 {
458 /* Get the sysdev */
459 RTFILE hFileCpuOnline = NIL_RTFILE;
460
461 rc = RTFileOpenF(&hFileCpuOnline, RTFILE_O_WRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
462 "%s/%s/online", SYSFS_CPU_PATH, DirFolderContent.szName);
463 if (RT_SUCCESS(rc))
464 {
465 /* Write a 1 to online the CPU */
466 rc = RTFileWrite(hFileCpuOnline, "1", 1, NULL);
467 RTFileClose(hFileCpuOnline);
468 if (RT_SUCCESS(rc))
469 {
470 VGSvcVerbose(1, "CpuHotPlug: CPU %u/%u was brought online\n", idCpuPackage, idCpuCore);
471 fCpuOnline = true;
472 break;
473 }
474 /* Error means CPU not present or online already */
475 }
476 else
477 VGSvcError("CpuHotPlug: Failed to open '%s/%s/online' rc=%Rrc\n",
478 SYSFS_CPU_PATH, DirFolderContent.szName, rc);
479 }
480 }
481 }
482 else
483 VGSvcError("CpuHotPlug: Failed to open path %s rc=%Rrc\n", SYSFS_CPU_PATH, rc);
484
485 /* Sleep a bit */
486 if (!fCpuOnline)
487 RTThreadSleep(10);
488
489 } while ( !fCpuOnline
490 && cTries-- > 0);
491#else
492# error "Port me"
493#endif
494}
495
496
497/**
498 * Handles VMMDevCpuEventType_Unplug.
499 *
500 * @param idCpuCore The CPU core ID.
501 * @param idCpuPackage The CPU package ID.
502 */
503static void vgsvcCpuHotPlugHandleUnplugEvent(uint32_t idCpuCore, uint32_t idCpuPackage)
504{
505#ifdef RT_OS_LINUX
506 char *pszCpuDevicePath = NULL;
507 int rc = vgsvcCpuHotPlugGetACPIDevicePath(&pszCpuDevicePath, idCpuCore, idCpuPackage);
508 if (RT_SUCCESS(rc))
509 {
510 RTFILE hFileCpuEject;
511 rc = RTFileOpenF(&hFileCpuEject, RTFILE_O_WRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE, "%s/eject", pszCpuDevicePath);
512 if (RT_SUCCESS(rc))
513 {
514 /* Write a 1 to eject the CPU */
515 rc = RTFileWrite(hFileCpuEject, "1", 1, NULL);
516 if (RT_SUCCESS(rc))
517 VGSvcVerbose(1, "CpuHotPlug: CPU %u/%u was ejected\n", idCpuPackage, idCpuCore);
518 else
519 VGSvcError("CpuHotPlug: Failed to eject CPU %u/%u rc=%Rrc\n", idCpuPackage, idCpuCore, rc);
520
521 RTFileClose(hFileCpuEject);
522 }
523 else
524 VGSvcError("CpuHotPlug: Failed to open '%s/eject' rc=%Rrc\n", pszCpuDevicePath, rc);
525 RTStrFree(pszCpuDevicePath);
526 }
527 else
528 VGSvcError("CpuHotPlug: Failed to get CPU device path rc=%Rrc\n", rc);
529#else
530# error "Port me"
531#endif
532}
533
534
535/** @interface_method_impl{VBOXSERVICE,pfnWorker} */
536static DECLCALLBACK(int) vgsvcCpuHotPlugWorker(bool volatile *pfShutdown)
537{
538 /*
539 * Tell the control thread that it can continue spawning services.
540 */
541 RTThreadUserSignal(RTThreadSelf());
542
543 /*
544 * Enable the CPU hotplug notifier.
545 */
546 int rc = VbglR3CpuHotPlugInit();
547 if (RT_FAILURE(rc))
548 return rc;
549
550 /*
551 * The Work Loop.
552 */
553 for (;;)
554 {
555 /* Wait for CPU hot plugging event. */
556 uint32_t idCpuCore;
557 uint32_t idCpuPackage;
558 VMMDevCpuEventType enmEventType;
559 rc = VbglR3CpuHotPlugWaitForEvent(&enmEventType, &idCpuCore, &idCpuPackage);
560 if (RT_SUCCESS(rc))
561 {
562 VGSvcVerbose(3, "CpuHotPlug: Event happened idCpuCore=%u idCpuPackage=%u enmEventType=%d\n",
563 idCpuCore, idCpuPackage, enmEventType);
564 switch (enmEventType)
565 {
566 case VMMDevCpuEventType_Plug:
567 vgsvcCpuHotPlugHandlePlugEvent(idCpuCore, idCpuPackage);
568 break;
569
570 case VMMDevCpuEventType_Unplug:
571 vgsvcCpuHotPlugHandleUnplugEvent(idCpuCore, idCpuPackage);
572 break;
573
574 default:
575 {
576 static uint32_t s_iErrors = 0;
577 if (s_iErrors++ < 10)
578 VGSvcError("CpuHotPlug: Unknown event: idCpuCore=%u idCpuPackage=%u enmEventType=%d\n",
579 idCpuCore, idCpuPackage, enmEventType);
580 break;
581 }
582 }
583 }
584 else if (rc != VERR_INTERRUPTED && rc != VERR_TRY_AGAIN)
585 {
586 VGSvcError("CpuHotPlug: VbglR3CpuHotPlugWaitForEvent returned %Rrc\n", rc);
587 break;
588 }
589
590 if (*pfShutdown)
591 break;
592 }
593
594 VbglR3CpuHotPlugTerm();
595 return rc;
596}
597
598
599/** @interface_method_impl{VBOXSERVICE,pfnStop} */
600static DECLCALLBACK(void) vgsvcCpuHotPlugStop(void)
601{
602 VbglR3InterruptEventWaits();
603 return;
604}
605
606
607/**
608 * The 'CpuHotPlug' service description.
609 */
610VBOXSERVICE g_CpuHotPlug =
611{
612 /* pszName. */
613 "cpuhotplug",
614 /* pszDescription. */
615 "CPU hot plugging monitor",
616 /* pszUsage. */
617 NULL,
618 /* pszOptions. */
619 NULL,
620 /* methods */
621 VGSvcDefaultPreInit,
622 VGSvcDefaultOption,
623 VGSvcDefaultInit,
624 vgsvcCpuHotPlugWorker,
625 vgsvcCpuHotPlugStop,
626 VGSvcDefaultTerm
627};
628
Note: See TracBrowser for help on using the repository browser.

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