1169689Skan/* mingw32 host-specific hook definitions.
2169689Skan   Copyright (C) 2004 Free Software Foundation, Inc.
3169689Skan
4169689Skan   This file is part of GCC.
5169689Skan
6169689Skan   GCC is free software; you can redistribute it and/or modify it
7169689Skan   under the terms of the GNU General Public License as published
8169689Skan   by the Free Software Foundation; either version 2, or (at your
9169689Skan   option) any later version.
10169689Skan
11169689Skan   GCC is distributed in the hope that it will be useful, but WITHOUT
12169689Skan   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13169689Skan   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
14169689Skan   License for more details.
15169689Skan
16169689Skan   You should have received a copy of the GNU General Public License
17169689Skan   along with GCC; see the file COPYING.  If not, write to the
18169689Skan   Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
19169689Skan   MA 02110-1301, USA.  */
20169689Skan
21169689Skan#include "config.h"
22169689Skan#include "system.h"
23169689Skan#include "coretypes.h"
24169689Skan#include "hosthooks.h"
25169689Skan#include "hosthooks-def.h"
26169689Skan#include "toplev.h"
27169689Skan#include "diagnostic.h"
28169689Skan
29169689Skan
30169689Skan#define WIN32_LEAN_AND_MEAN  /* Not so important if we have windows.h.gch.  */
31169689Skan#include <windows.h>
32169689Skan
33169689Skanstatic void * mingw32_gt_pch_get_address (size_t, int);
34169689Skanstatic int mingw32_gt_pch_use_address (void *, size_t, int, size_t);
35169689Skanstatic size_t mingw32_gt_pch_alloc_granularity (void);
36169689Skan
37169689Skan#undef HOST_HOOKS_GT_PCH_GET_ADDRESS
38169689Skan#define HOST_HOOKS_GT_PCH_GET_ADDRESS mingw32_gt_pch_get_address
39169689Skan#undef HOST_HOOKS_GT_PCH_USE_ADDRESS
40169689Skan#define HOST_HOOKS_GT_PCH_USE_ADDRESS mingw32_gt_pch_use_address
41169689Skan#undef HOST_HOOKS_GT_PCH_ALLOC_GRANULARITY
42169689Skan#define HOST_HOOKS_GT_PCH_ALLOC_GRANULARITY mingw32_gt_pch_alloc_granularity
43169689Skan
44169689Skanstatic inline void w32_error(const char*, const char*, int, const char*);
45169689Skan
46169689Skan/* FIXME: Is this big enough?  */
47169689Skanstatic const size_t pch_VA_max_size  = 128 * 1024 * 1024;
48169689Skan
49169689Skan/* Granularity for reserving address space.  */
50169689Skanstatic const size_t va_granularity = 0x10000;
51169689Skan
52169689Skan/* Print out the GetLastError() translation.  */
53169689Skanstatic inline void
54169689Skanw32_error (const char* function, const char* file, int line,
55169689Skan	   const char* my_msg)
56169689Skan{
57169689Skan  LPSTR w32_msgbuf;
58169689Skan  FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER
59169689Skan		  | FORMAT_MESSAGE_FROM_SYSTEM
60169689Skan		  | FORMAT_MESSAGE_IGNORE_INSERTS
61169689Skan		  | FORMAT_MESSAGE_MAX_WIDTH_MASK,
62169689Skan    		  NULL, GetLastError(),
63169689Skan		  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
64169689Skan		  (LPSTR) &w32_msgbuf, 0, NULL);
65169689Skan  fprintf(stderr, "internal error in %s, at %s:%d: %s: %s\n",
66169689Skan	  function, trim_filename (file), line, my_msg, w32_msgbuf);
67169689Skan  LocalFree ((HLOCAL)w32_msgbuf);
68169689Skan}
69169689Skan
70169689Skan/* Granularity for reserving address space.  */
71169689Skanstatic size_t mingw32_gt_pch_alloc_granularity (void)
72169689Skan{
73169689Skan  return va_granularity;
74169689Skan}
75169689Skan
76169689Skan/* Identify an address that's likely to be free in a subsequent invocation
77169689Skan   of the compiler.  The area should be able to hold SIZE bytes.  FD is an
78169689Skan   open file descriptor if the host would like to probe with mmap.  */
79169689Skan
80169689Skanstatic void *
81169689Skanmingw32_gt_pch_get_address (size_t size, int fd  ATTRIBUTE_UNUSED)
82169689Skan{
83169689Skan  void* res;
84169689Skan  size = (size + va_granularity - 1) & ~(va_granularity - 1);
85169689Skan  if (size > pch_VA_max_size)
86169689Skan    return NULL;
87169689Skan
88169689Skan  /* FIXME: We let system determine base by setting first arg to NULL.
89169689Skan     Allocating at top of available address space avoids unnecessary
90169689Skan     fragmentation of "ordinary" (malloc's)  address space but may not be safe
91169689Skan     with delayed load of system dll's. Preferred addresses for NT system
92169689Skan     dlls is in 0x70000000 to 0x78000000 range.
93169689Skan     If we allocate at bottom we need to reserve the address as early as possible
94169689Skan     and at the same point in each invocation. */
95169689Skan
96169689Skan  res = VirtualAlloc (NULL, pch_VA_max_size,
97169689Skan		      MEM_RESERVE | MEM_TOP_DOWN,
98169689Skan		      PAGE_NOACCESS);
99169689Skan  if (!res)
100169689Skan    w32_error (__FUNCTION__, __FILE__, __LINE__, "VirtualAlloc");
101169689Skan  else
102169689Skan    /* We do not need the address space for now, so free it.  */
103169689Skan    VirtualFree (res, 0, MEM_RELEASE);
104169689Skan
105169689Skan  return res;
106169689Skan}
107169689Skan
108169689Skan/* ADDR is an address returned by gt_pch_get_address.  Attempt to allocate
109169689Skan   SIZE bytes at the same address and load it with the data from FD at
110169689Skan   OFFSET.  Return -1 if we couldn't allocate memory at ADDR, return 0
111169689Skan   if the memory is allocated but the data not loaded, return 1 if done.  */
112169689Skan
113169689Skanstatic int
114169689Skanmingw32_gt_pch_use_address (void *addr, size_t size, int fd,
115169689Skan			    size_t offset)
116169689Skan{
117169689Skan  void * mmap_addr;
118169689Skan  static HANDLE mmap_handle;
119169689Skan
120169689Skan  if (size == 0)
121169689Skan    return 0;
122169689Skan
123169689Skan  /* Offset must be also be a multiple of allocation granularity for
124169689Skan     this to work.  We can't change the offset. */
125169689Skan  if ((offset & (va_granularity - 1)) != 0 || size > pch_VA_max_size)
126169689Skan    return -1;
127169689Skan
128169689Skan  mmap_handle = CreateFileMapping ((HANDLE) _get_osfhandle (fd),
129169689Skan				   NULL, PAGE_WRITECOPY | SEC_COMMIT,
130169689Skan				   0, 0,  NULL);
131169689Skan  if (mmap_handle == NULL)
132169689Skan    {
133169689Skan      w32_error (__FUNCTION__,  __FILE__, __LINE__, "CreateFileMapping");
134169689Skan      return -1;
135169689Skan    }
136169689Skan  mmap_addr = MapViewOfFileEx (mmap_handle, FILE_MAP_COPY, 0, offset,
137169689Skan			       size, addr);
138169689Skan  if (mmap_addr != addr)
139169689Skan    {
140169689Skan      w32_error (__FUNCTION__, __FILE__, __LINE__, "MapViewOfFileEx");
141169689Skan      CloseHandle(mmap_handle);
142169689Skan      return  -1;
143169689Skan    }
144169689Skan
145169689Skan  return 1;
146169689Skan}
147169689Skan
148169689Skanconst struct host_hooks host_hooks = HOST_HOOKS_INITIALIZER;
149