source: svn/trunk/newcon3bcm2_21bu/magnum/commonutils/mrc/7552/bmrc_monitor.c

Last change on this file was 2, checked in by jglee, 11 years ago

first commit

  • Property svn:executable set to *
File size: 63.2 KB
Line 
1/***************************************************************************
2 *     Copyright (c) 2004-2012, Broadcom Corporation
3 *     All Rights Reserved
4 *     Confidential Property of Broadcom Corporation
5 *
6 *  THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE
7 *  AGREEMENT  BETWEEN THE USER AND BROADCOM.  YOU HAVE NO RIGHT TO USE OR
8 *  EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT.
9 *
10 * $brcm_Workfile: bmrc_monitor.c $
11 * $brcm_Revision: Hydra_Software_Devel/87 $
12 * $brcm_Date: 1/24/12 6:20p $
13 *
14 * Module Description:
15 *
16 * Implementation of the Realtime Memory Monitor for 7038
17 *
18 * Revision History:
19 *
20 * $brcm_Log: /magnum/commonutils/mrc/7420/bmrc_monitor.c $
21 *
22 * Hydra_Software_Devel/87   1/24/12 6:20p albertl
23 * SW7425-2184: Fixed warning.
24 *
25 * Hydra_Software_Devel/86   1/24/12 6:17p albertl
26 * SW7425-2184: Fixed debug message warning for release builds.
27 *
28 * Hydra_Software_Devel/85   1/23/12 5:04p albertl
29 * SW7425-2184: Fixed incorrect address comparison when removing address
30 * from previous addr table.
31 *
32 * Hydra_Software_Devel/84   1/20/12 7:07p albertl
33 * SW7425-2184: Fixed bug in removing addresses from previous addr table.
34 *
35 * Hydra_Software_Devel/83   1/10/12 4:10p albertl
36 * SW7405-5349: Updated messages for unknown files for clarity.
37 *
38 * Hydra_Software_Devel/82   12/8/11 5:00p albertl
39 * SW7408-305: Fixed BMRC_Monitor_JailDefault.
40 *
41 * Hydra_Software_Devel/81   9/27/11 6:37p albertl
42 * SW7408-305: Fixed optimization to handle overlapping regions.  Defaults
43 * to standard update if no optimization found.
44 *
45 * Hydra_Software_Devel/80   9/12/11 4:34p albertl
46 * SW7346-479: Added asserts to check overflow of region prev array.
47 *
48 * Hydra_Software_Devel/79   8/30/11 12:58p albertl
49 * SW7405-5349: Fixed to use proper array size in
50 * BMRC_P_Monitor_ListRemoveRegion.
51 *
52 * Hydra_Software_Devel/78   8/24/11 5:35p albertl
53 * SW7405-5349:  Added line parameter to memory monitor interface. Made
54 * fixes to optimization code.
55 *
56 * Hydra_Software_Devel/77   8/23/11 4:20p albertl
57 * SW7405-5349:  Added and adjusted optimization factor constant.
58 *
59 * Hydra_Software_Devel/76   8/23/11 3:59p albertl
60 * SW7405-5349:  Rolled back monitor interface changes until mastership
61 * issues are resolved.
62 *
63 * Hydra_Software_Devel/74   8/18/11 7:39p albertl
64 * SW7405-5349: Temporarily rolled back optimizations to resolve handling
65 * of new violations.
66 *
67 * Hydra_Software_Devel/73   8/17/11 1:46p albertl
68 * SW7405-5349: Made several optimizations to list handling and update to
69 * speed up allocs and frees for large numbers of allocations.
70 *
71 * Hydra_Software_Devel/72   3/22/11 3:50p albertl
72 * SW7344-37: Added changes for SCB Protocal 4.2.  Fixed transfer size
73 * message.
74 *
75 * Hydra_Software_Devel/71   3/18/11 5:10p albertl
76 * SW7422-168: Added mutexes to make BMRC_Monitor calls threadsafe.
77 *
78 * Hydra_Software_Devel/70   1/13/11 6:36p albertl
79 * SW7422-168: Fixed bug with -1 checkers in user settings.
80 *
81 * Hydra_Software_Devel/69   1/13/11 5:20p albertl
82 * SW7422-168: Default number of checkers set to -1 in
83 * BMRC_Monitor_Settings, handled as maximum available.
84 *
85 * Hydra_Software_Devel/68   1/13/11 2:05p albertl
86 * SW7422-168: Changed debug messages to BDBG_MSG.
87 *
88 * Hydra_Software_Devel/67   1/12/11 2:50p albertl
89 * SW7422-168: Changed BMRC_Monitor_Open to take settings structure.
90 * Removed BMRC_Monitor_SetSettings().  Added ability to configure how
91 * many checkers BMRC_Monitor uses to support more than one monitor on
92 * same MEMC.
93 *
94 * Hydra_Software_Devel/66   1/5/11 9:02p albertl
95 * SW7422-106, SW7422-168 : Fixed MRC bugs pertaining to handling multiple
96 * MEMCs and rewrote portions of BMRC_Monitor logic.  Client masks now
97 * stored to match hardware.
98 *
99 * Hydra_Software_Devel/65   12/29/10 3:18p pntruong
100 * SW7422-168: Remove bogus warning msg.
101 *
102 * Hydra_Software_Devel/64   12/14/10 7:45p albertl
103 * SW7400-2973: Disabled memory access blocking temporarily to bypass
104 * client permission issues on MEMCs other than 0.
105 *
106 * Hydra_Software_Devel/63   12/6/10 6:10p albertl
107 * SW7405-4047: Removed printf messages.
108 *
109 * Hydra_Software_Devel/62   12/6/10 4:25p albertl
110 * SWBLURAY-23672: Added 7640 support.
111 *
112 * Hydra_Software_Devel/61   11/19/10 7:56p albertl
113 * SW7422-106: Added error message when high memory is not greater than
114 * low memory.
115 *
116 * Hydra_Software_Devel/60   10/7/10 11:31a vsilyaev
117 * SW7405-4924: Block write for all out-of-bound accesses
118 *
119 * Hydra_Software_Devel/59   7/8/10 6:28p albertl
120 * SW7405-4047: Fixed build warning with new debug define.
121 *
122 * Hydra_Software_Devel/58   7/8/10 3:30p albertl
123 * SW7405-4047: Removed warning.
124 *
125 * Hydra_Software_Devel/56   6/30/10 6:11p albertl
126 * SW7405-4047: Added BMRC_Monitor_JailByFilename.
127 *
128 * Hydra_Software_Devel/55   6/16/10 6:23p albertl
129 * SW3548-2836: Renamed client field in BMRC_MonitorContext to clients.
130 *
131 * Hydra_Software_Devel/54   3/29/10 1:00p albertl
132 * SW3548-2836: Fixed logic bug in threshold comparison.
133 *
134 * Hydra_Software_Devel/53   3/26/10 7:22p albertl
135 * SW7405-4059: Fixed pointer assignment for empty filenames.
136 *
137 * Hydra_Software_Devel/52   3/26/10 1:30p albertl
138 * SW7405-4059: Updated debug messages to be more helpful.  Included link
139 * to SCB specs documentation, also available in this JIRA.
140 *
141 *
142 * Hydra_Software_Devel/51   3/17/10 5:07p erickson
143 * SW7405-3892: improve ARC0 warning
144 *
145 * Hydra_Software_Devel/50   3/17/10 4:46p erickson
146 * SW7405-3892: ARC0 now blocks writes to kernel memory
147 *
148 * Hydra_Software_Devel/49   3/17/10 2:19p erickson
149 * SW7405-3892: BDBG_WRN whenever the ARC0 range is reprogrammed
150 *
151 * Hydra_Software_Devel/48   3/2/10 1:25p erickson
152 * SW7405-3892: add BMRC_Monitor_PrintClients for debug, fix
153 * BMRC_Monitor_RemoveCustomTag name, add sample code for blocking
154 * unwanted kernel writes
155 *
156 * Hydra_Software_Devel/47   9/14/09 7:43p albertl
157 * SW7630-7: Added 7630 support.
158 *
159 * Hydra_Software_Devel/46   6/16/09 6:21p albertl
160 * PR55764, PR55875, PR55993: Refactored MRC to keep chip specific
161 * definitions in bmrc_priv.h and for maintainability.  Updated support
162 * for 7420 b0, 7430, 35130, and 7550.
163 *
164 * Hydra_Software_Devel/45   6/4/09 7:05p albertl
165 * PR55641: Allowed MRC to report maximum number of checkers and changed
166 * BMRC_Monitor to use that instead of hardcoded maximums.
167 *
168 * Hydra_Software_Devel/44   3/30/09 5:26p albertl
169 * PR52965: Fixed missing 7635 MRC support.
170 *
171 * Hydra_Software_Devel/43   2/17/09 6:43p albertl
172 * PR51612: Updated to correct naming conventions.
173 *
174 * Hydra_Software_Devel/42   7/23/08 1:34p albertl
175 * PR33688:  Fixed 7601 mrc build errors.
176 *
177 * Hydra_Software_Devel/41   6/24/08 6:14p albertl
178 * PR43294:  Optimized to run BMRC_P_Monitor_BuildClientIdMaskBits only
179 * when necessary for debug messages.
180 *
181 * Hydra_Software_Devel/40   6/23/08 3:44p albertl
182 * PR43294:  Changed client_masks array to be bitfields for more efficient
183 * updating.  Previously caused too much delay during updates.
184 *
185 * Hydra_Software_Devel/39   4/18/08 10:22a mward
186 * PR41160:  Don't return without freeing allocated memory.
187 *
188 * Hydra_Software_Devel/38   4/8/08 6:52p albertl
189 * PR41160:  Fixed coverity issue by using heap memory for regions in
190 * BMRC_Monitor_Update.
191 *
192 * Hydra_Software_Devel/37   4/4/08 6:31p albertl
193 * PR41261:  Fixed coverity issue by initializing hChecker to NULL.
194 *
195 * Hydra_Software_Devel/36   2/25/08 7:04p albertl
196 * PR36876:  Rewrote MRC to abstract client names and streamline adding of
197 * future chips.  3548 support added.
198 *
199 * Hydra_Software_Devel/35   2/14/08 6:34p albertl
200 * PR35322:  Fixed BMRC_P_Monitor_RemoveMask client mask bug that caused
201 * JailRemove to fail.
202 *
203 * Hydra_Software_Devel/34   11/14/07 1:50p albertl
204 * PR35322:  Updated mrc monitor to properly support 128 clients.
205 *
206 * Hydra_Software_Devel/32   3/9/07 7:19p albertl
207 * PR28182:  No longer programs ARC when aligned size is 0.  Memc id now
208 * reported on violations.
209 *
210 * Hydra_Software_Devel/31   2/7/07 7:39p albertl
211 * PR25898:  Changed BMRC_MONITOR range checking to JWord (256 byte)
212 * granularity to eliminate false violations from clients with JWord
213 * minimum access sizes.
214 *
215 * Hydra_Software_Devel/30   2/1/07 12:54p mward
216 * PR26646: Temporarily disable messages for GFX client for 7118, too, as
217 * for 7401/7403.
218 *
219 * Hydra_Software_Devel/29   1/17/07 7:56p albertl
220 * PR19101:  Fixed missing defines for viol_start and viol_end.
221 *
222 * Hydra_Software_Devel/28   1/17/07 6:39p albertl
223 * PR19101:  Updated violation messages to indicate exclusive mode for
224 * clarity.
225 *
226 * Hydra_Software_Devel/27   12/28/06 9:42a erickson
227 * PR25898: temp checkin for release. the false error messages were
228 * getting in the way of system debug. please remove this change when the
229 * issue is fixed.
230 *
231 * Hydra_Software_Devel/26   11/27/06 7:23p albertl
232 * PR13641:  Updated violation messages for clarity.
233 *
234 * Hydra_Software_Devel/25   10/26/06 2:39p syang
235 * PR13641: fix compile error (aligned_end not defined)
236 *
237 * Hydra_Software_Devel/24   10/25/06 4:15p albertl
238 * PR13641:  Corrected calculation of aligned_size.
239 *
240 * Hydra_Software_Devel/23   10/24/06 10:54p albertl
241 * PR24997:  Fixed error calculating aligned starting address.
242 *
243 * Hydra_Software_Devel/21   10/19/06 3:13p albertl
244 * PR25004:  Fixed improper splitting of macros with #if.
245 *
246 * Hydra_Software_Devel/20   10/13/06 9:27p albertl
247 * PR23361:  Added mrc support for 3563.
248 *
249 * Hydra_Software_Devel/19   10/13/06 8:12p albertl
250 * PR19101:   NMBX value now returned upon violation.
251 *
252 * Hydra_Software_Devel/18   6/16/06 3:29p albertl
253 * PR20489:  Start addresses are now aligned in BMRC_P_Monitor_Program.
254 *
255 * Hydra_Software_Devel/17   4/11/06 2:51p albertl
256 * PR20489:  Fixed bug updating incorrect client list with defaults.
257 *
258 * Hydra_Software_Devel/16   4/3/06 4:25p albertl
259 * PR20489:  Added BMRC_Monitor_JailDefault function.
260 *
261 * Hydra_Software_Devel/15   3/7/06 6:36p albertl
262 * PR19498:  Added SCB Command decoding in error messages, and NMB is
263 * printed only when relevant.  Checker ranges no longer cover extra
264 * bytes that exceed 8 byte size alignment.
265 *
266 * Hydra_Software_Devel/14   3/3/06 7:23p albertl
267 * PR18701:  Added functions to disable and enable a checker's callback.
268 * Fixed to disable a checker's interrupt upon violation.
269 *
270 * Hydra_Software_Devel/13   3/1/06 5:26p albertl
271 * PR18701:  Updated to include RMM updates.
272 *
273 * Hydra_Software_Devel/12   2/16/06 7:39p albertl
274 * PR19101:  Moved chip specific tables to bmrc_monitor_clients.c.
275 *
276 * Hydra_Software_Devel/11   1/17/06 4:53p hongtaoz
277 * PR19082: support 7400;
278 *
279 * Hydra_Software_Devel/10   11/29/05 1:20p albertl
280 * PR18307:  BMRC_Monitor_Open now immediately returns with an error when
281 * BMRC_Checker_Create fails.
282 *
283 * Hydra_Software_Devel/9   11/7/05 5:05p albertl
284 * PR17403:  Fixed build errors on 97401.  Renamed clients to be
285 * consistent with RTS architecture client documentation.
286 *
287 * Hydra_Software_Devel/8   11/4/05 6:49p albertl
288 * PR17403:  Added BMRC_Client_eAVD_ILA_0 and BMRC_Client_eAVD_OLA_0
289 * clients to xpt module.  Renamed client enums to standard names.
290 *
291 * Hydra_Software_Devel/7   10/7/05 4:36p hongtaoz
292 * PR17460: adapted to the new RDB header files;
293 *
294 * Hydra_Software_Devel/6   9/23/05 7:06p hongtaoz
295 * PR17131: added BMRC support for 7401;
296 *
297 * Hydra_Software_Devel/5   8/8/05 9:52p albertl
298 * PR13641:  Fixed debug module name.
299 *
300 * Hydra_Software_Devel/4   8/4/05 6:50p albertl
301 * PR13641:  Fixed incorrect PR numbers in chagelog.
302 *
303 * Hydra_Software_Devel/2   8/3/05 8:34p albertl
304 * PR13641:  Removed shifting of addresses.  Now handled in BMRC_Checker
305 * module.
306 *
307 * Hydra_Software_Devel/1   8/1/05 10:14p albertl
308 * PR13641:  Initial Revision, based on RMM module.
309 *
310 ***************************************************************************/
311
312#include "bstd.h"
313#include "bmrc_monitor.h"
314#include "bmrc_monitor_priv.h"
315#include "bkni.h"
316#include "bkni_multi.h"          /* for semaphores */
317#include "blst_list.h"
318
319BDBG_MODULE(BMRC_MONITOR);
320
321#if (BCHP_CHIP == 7038) || (BCHP_CHIP == 7438) || (BCHP_CHIP == 3560)
322    #define BMRC_P_MONITOR_USE_NMBX_ID 1
323#else
324    #define BMRC_P_MONITOR_USE_NMBX_ID 0
325#endif
326#define BMRC_P_MONITOR_MAX_RANGES 4
327#define BMRC_P_MONITOR_CLIENT_MASK_ARRAY_ELEMENT_SIZE 32
328#define BMRC_P_MONITOR_CLIENT_MASK_ARRAY_SIZE  (BMRC_Client_eMaxCount + (BMRC_P_MONITOR_CLIENT_MASK_ARRAY_ELEMENT_SIZE-1)) / BMRC_P_MONITOR_CLIENT_MASK_ARRAY_ELEMENT_SIZE
329
330#define BMRC_P_MONITOR_DBG_TRACE 0
331
332#if BMRC_P_MONITOR_DBG_TRACE
333#define BDBG_MSG_TRACE(x) BDBG_MSG(x)
334#else
335#define BDBG_MSG_TRACE(x)
336#endif
337
338/* externs */
339extern const BMRC_P_Monitor_FileClientInfo BMRC_P_Monitor_astFileClients[];
340extern const uint32_t BMRC_P_Monitor_FileClientsTblSize;
341extern const BMRC_Client BMRC_P_Monitor_astHwClients[];
342
343/* Definitions for word sizes.
344
345    Dword (or Word)  32 bits
346    Oword  64 bits
347    Gword  128 bits
348    Jword  256 bits (J for Jumbo, if you like.)
349*/
350#define BMRC_P_MONITOR_DWORD_BYTES 4
351#define BMRC_P_MONITOR_OWORD_BYTES 8
352#define BMRC_P_MONITOR_GWORD_BYTES 16
353#define BMRC_P_MONITOR_JWORD_BYTES 32
354
355#if (BCHP_CHIP!=7440) && (BCHP_CHIP!=7601) && (BCHP_CHIP!=7635) && (BCHP_CHIP!=7630) && (BCHP_CHIP!=7640)
356/* SCB Protocol Specifications the following table was derived from are available at
357   http://www.blr.broadcom.com/projects/DVT_BLR/Memc_Arch/.  These specs are also used
358   in BMRC_P_Monitor_Dump_isr below. */
359
360/* SCB Command Table */
361static const BMRC_P_Monitor_ScbCommandInfo g_ScbCommandInfoTbl[] =
362{
363    {BMRC_P_Monitor_ScbCommand_eLR,   BMRC_P_MONITOR_SCB_COMMAND_LR,   BMRC_P_MONITOR_SCB_TRANSFER_ACCESS_MASK,   "Linear Read - LR"},
364    {BMRC_P_Monitor_ScbCommand_eLW,   BMRC_P_MONITOR_SCB_COMMAND_LW,   BMRC_P_MONITOR_SCB_TRANSFER_ACCESS_MASK,   "Linear Write - LW"},
365    {BMRC_P_Monitor_ScbCommand_eREF,  BMRC_P_MONITOR_SCB_COMMAND_REF,  BMRC_P_MONITOR_SCB_INTERNAL_MASK,          "Refresh - REF"},
366    {BMRC_P_Monitor_ScbCommand_eMRS,  BMRC_P_MONITOR_SCB_COMMAND_MRS,  BMRC_P_MONITOR_SCB_INTERNAL_MASK,          "Mode Register Set - MRS"},
367    {BMRC_P_Monitor_ScbCommand_eEMRS, BMRC_P_MONITOR_SCB_COMMAND_EMRS, BMRC_P_MONITOR_SCB_INTERNAL_MASK,          "Extended Mode Reg Set - EMRS"},
368    {BMRC_P_Monitor_ScbCommand_ePALL, BMRC_P_MONITOR_SCB_COMMAND_PALL, BMRC_P_MONITOR_SCB_INTERNAL_MASK,          "Precharge All Banks - PALL"},
369    {BMRC_P_Monitor_ScbCommand_eDR,   BMRC_P_MONITOR_SCB_COMMAND_DR,   BMRC_P_MONITOR_SCB_TRANSFER_ACCESS_MASK,   "Video Raster Read - DR"},
370    {BMRC_P_Monitor_ScbCommand_eDW,   BMRC_P_MONITOR_SCB_COMMAND_DW,   BMRC_P_MONITOR_SCB_TRANSFER_ACCESS_MASK,   "Video Raster Write - DW"},
371    {BMRC_P_Monitor_ScbCommand_eMR,   BMRC_P_MONITOR_SCB_COMMAND_MR,   BMRC_P_MONITOR_SCB_MPEG_BLOCK_ACCESS_MASK, "MPEG Block Read - MR"},
372    {BMRC_P_Monitor_ScbCommand_eMW,   BMRC_P_MONITOR_SCB_COMMAND_MW,   BMRC_P_MONITOR_SCB_MPEG_BLOCK_ACCESS_MASK, "MPEG Block Write - MW"},
373    {BMRC_P_Monitor_ScbCommand_eCR4,  BMRC_P_MONITOR_SCB_COMMAND_CR4,  BMRC_P_MONITOR_SCB_CACHE_ACCESS_MASK,      "Cache Read, 4 Jwords/128 bytes - CR4"},
374    {BMRC_P_Monitor_ScbCommand_eCR8,  BMRC_P_MONITOR_SCB_COMMAND_CR8,  BMRC_P_MONITOR_SCB_CACHE_ACCESS_MASK,      "Cache Read, 8 Jwords/256 bytes - CR8"}
375};
376#define BMRC_P_MONITOR_SCB_ACCESS_TABLE_SIZE (sizeof(g_ScbCommandInfoTbl)/sizeof(BMRC_P_Monitor_ScbCommandInfo))
377#endif /* (BCHP_CHIP!=7440) && (BCHP_CHIP!=7601) && (BCHP_CHIP!=7635) */
378
379#define BMRC_P_MONITOR_ALIGNED_RANGE_START(start_addr, exclusive) \
380    ((start_addr + (exclusive ? 0 : ~(BMRC_P_MONITOR_CHECKER_ADDR_ALIGN))) & \
381     BMRC_P_MONITOR_CHECKER_ADDR_ALIGN)
382
383#define BMRC_P_MONITOR_ALIGNED_RANGE_END(end_addr, exclusive) \
384    ((end_addr + (exclusive ? ~(BMRC_P_MONITOR_CHECKER_ADDR_ALIGN) : 0)) & \
385     BMRC_P_MONITOR_CHECKER_ADDR_ALIGN)
386
387#define BMRC_P_MONITOR_CLIENT_MASK(client_id)      (1 << ((client_id) % BMRC_P_MONITOR_CLIENT_MASK_ARRAY_ELEMENT_SIZE))
388#define BMRC_P_MONITOR_CLIENT_MASK_IDX(client_id)  ((client_id) / BMRC_P_MONITOR_CLIENT_MASK_ARRAY_ELEMENT_SIZE)
389#define BMRC_P_MONITOR_CLIENT_MASK_IS_SET(client_mask, client_id) \
390    client_mask[BMRC_P_MONITOR_CLIENT_MASK_IDX(client_id)] & BMRC_P_MONITOR_CLIENT_MASK(client_id)
391#define BMRC_P_MONITOR_CLIENT_MASK_SET(client_mask, client_id) \
392    client_mask[BMRC_P_MONITOR_CLIENT_MASK_IDX(client_id)] |= BMRC_P_MONITOR_CLIENT_MASK(client_id);
393#define BMRC_P_MONITOR_CLIENT_MASK_UNSET(client_mask, client_id) \
394    client_mask[BMRC_P_MONITOR_CLIENT_MASK_IDX(client_id)] &= ~BMRC_P_MONITOR_CLIENT_MASK(client_id);
395
396#define BMRC_P_MONITOR_OPTIMIZE_THRESHOLD 100
397#define BMRC_P_MONITOR_OPTIMIZE_SKIP_FACTOR 10
398#define BMRC_P_MONITOR_REGION_HASH_SIZE       (9999)  /* odd to avoid possible alignment issues spoiling hash */
399#define BMRC_P_MONITOR_REGION_PREV_SIZE       (10000)
400#define BMRC_P_MONITOR_REGION_PREV_SLOT_SIZE  (hMonitor->mem_high / BMRC_P_MONITOR_REGION_PREV_SIZE)
401#define BMRC_P_MONITOR_REGION_PREV_GET_IDX(addr) ((((addr) / BMRC_P_MONITOR_REGION_PREV_SLOT_SIZE) >= BMRC_P_MONITOR_REGION_PREV_SIZE) ? \
402                                                  (BMRC_P_MONITOR_REGION_PREV_SIZE - 1) : ((addr) / BMRC_P_MONITOR_REGION_PREV_SLOT_SIZE))
403
404
405/* default settings */
406static const BMRC_Monitor_Settings s_stDefaultSettings = {
407    BMRC_AccessType_eWrite,  /* kernel violation access block */
408        BMRC_AccessType_eNone,   /* regular violation access block */
409        UINT32_C(-1)             /* maximum number of checkers to use. -1 means use all available. */
410};
411
412static void BMRC_P_Monitor_Update(BMRC_Monitor_Handle hMonitor, bool bCombine);
413static void BMRC_P_Monitor_isr( void *cnxt, int no, BMRC_CheckerInfo *pInfo);
414BERR_Code BMRC_Monitor_ValidateRegionList(BMRC_Monitor_Handle hMonitor);
415BERR_Code BMRC_Monitor_DumpRegionPrevByAddrTable(BMRC_Monitor_Handle hMonitor);
416
417typedef struct BMRC_Monitor_Clients {
418    uint32_t client_masks[BMRC_P_MONITOR_CLIENT_MASK_ARRAY_SIZE];
419}BMRC_Monitor_Clients;
420
421
422typedef struct BMRC_Monitor_Region {
423        const char *fname;
424        int line;
425    BLST_D_ENTRY(BMRC_Monitor_Region) list;
426        BLST_D_ENTRY(BMRC_Monitor_Region) hash;
427    uint32_t addr;
428    size_t size;
429    BMRC_Monitor_Clients clients;
430    BMRC_Monitor_Clients user_clients_allowed;
431}BMRC_Monitor_Region;
432
433typedef struct BMRC_P_MonitorContext {
434    BMRC_Settings mrcSettings;
435    BMRC_Monitor_Settings stSettings;
436    BMRC_Handle mrc;
437    BREG_Handle reg;
438    BINT_Handle isr;
439    uint32_t mem_low, mem_high; /* memory region what would be monitored */
440    uint32_t max_ranges; /* maximum number of checkers */
441        uint32_t max_regions;
442        uint32_t num_regions;
443        uint32_t num_combined_regions;
444    BLST_D_HEAD(parent, BMRC_Monitor_Region) regions; /* list of all known memory regions, sorted by their adreess, from low to high */
445        BLST_D_HEAD(hash_parent, BMRC_Monitor_Region) region_hash[BMRC_P_MONITOR_REGION_HASH_SIZE];
446    BLST_D_HEAD(custom_parent, BMRC_Monitor_Region) custom_regions; /* list of exclusive regions */
447        BMRC_Monitor_Region *combined_regions;
448        BMRC_Monitor_Region *region_prev_by_addr[BMRC_P_MONITOR_REGION_PREV_SIZE];
449    BMRC_Monitor_Clients clients; /* current clients used to setup range checker */
450    BINT_CallbackHandle irq[BMRC_P_MONITOR_MAX_RANGES];
451    BMRC_Monitor_Clients user_clients_jailed;
452    BMRC_Checker_Handle ahCheckers[BMRC_P_MONITOR_MAX_RANGES];
453        bool protect_mem_low;
454        BKNI_MutexHandle pMutex; /* Semaphore to lock this monitor */
455}BMRC_P_MonitorContext;
456
457
458/* client mask manipulation functions */
459static void
460BMRC_P_Monitor_MasksClear(BMRC_Monitor_Clients *mask)
461{
462    BKNI_Memset(mask->client_masks, 0, sizeof(mask->client_masks));
463}
464
465static void
466BMRC_P_Monitor_MasksFill(BMRC_Monitor_Clients *mask)
467{
468    BKNI_Memset(mask->client_masks, 0xFFFFFFFF, sizeof(mask->client_masks));
469}
470
471
472static void
473BMRC_P_Monitor_MasksInverse(BMRC_Monitor_Clients *mask, const BMRC_Monitor_Clients *neg_mask)
474{
475    int i = 0;
476    for (i=0;i<BMRC_P_MONITOR_CLIENT_MASK_ARRAY_SIZE;i++)
477        mask->client_masks[i] = ~neg_mask->client_masks[i];
478}
479
480
481static bool
482BMRC_P_Monitor_MasksIsClear(const BMRC_Monitor_Clients *mask)
483{
484    int i = 0;
485    for (i=0;i<BMRC_P_MONITOR_CLIENT_MASK_ARRAY_SIZE;i++)
486        if (mask->client_masks[i])
487            return false;
488    return true;
489}
490
491
492static bool
493BMRC_P_Monitor_MasksHasCommon(const BMRC_Monitor_Clients *mask, const BMRC_Monitor_Clients *cmp_mask)
494{
495    int i = 0;
496    for (i=0;i<BMRC_P_MONITOR_CLIENT_MASK_ARRAY_SIZE;i++)
497        if (mask->client_masks[i] & cmp_mask->client_masks[i])
498            return true;
499    return false;
500}
501
502
503static void
504BMRC_P_Monitor_MaskAdd(BMRC_Monitor_Clients *mask, BMRC_Client client)
505{
506    BMRC_P_MONITOR_CLIENT_MASK_SET(mask->client_masks, client);
507}
508
509
510static void
511BMRC_P_Monitor_MaskRemove(BMRC_Monitor_Clients *mask, BMRC_Client client)
512{
513    BMRC_P_MONITOR_CLIENT_MASK_UNSET(mask->client_masks, client);
514}
515
516
517/* this function builds a client map using given client list */
518static void
519BMRC_P_Monitor_MaskBuild(BMRC_Monitor_Clients *mask, const BMRC_Client *clients)
520{
521    /* clear clients, and then get clients from the table */
522    BMRC_P_Monitor_MasksClear(mask);
523
524    for(;*clients!=BMRC_Client_eMaxCount;clients++) {
525        BMRC_P_Monitor_MaskAdd(mask, *clients);
526    }
527    return;
528}
529
530
531/* this function builds the hardware client id bit mask */
532static void
533BMRC_P_Monitor_BuildClientIdMaskBits(BMRC_Monitor_Handle hMonitor, const BMRC_Monitor_Clients *mask, uint32_t mask_bits[4])
534{
535    int i;
536    BMRC_ClientInfo client_info;
537    BKNI_Memset(mask_bits, 0xFFFFFFFF, sizeof(uint32_t) * 4);
538    for (i = 0; i < BMRC_Client_eMaxCount; i++)
539    {
540        BMRC_Checker_GetClientInfo(hMonitor->mrc, i, &client_info);
541        if ((client_info.usClientId != BMRC_Client_eInvalid) &&
542            !(BMRC_P_MONITOR_CLIENT_MASK_IS_SET(mask->client_masks, i)))
543        {
544            BMRC_P_MONITOR_CLIENT_MASK_UNSET(mask_bits, client_info.usClientId);
545        }
546    }
547}
548
549/* this function builds the hardware client id bit string */
550const char *BMRC_P_Monitor_BuildClientIdString(BMRC_Monitor_Handle hMonitor, const BMRC_Monitor_Clients *mask, char *buffer, uint32_t len)
551{
552        uint32_t mask_bits[4];
553        BMRC_P_Monitor_BuildClientIdMaskBits(hMonitor, mask, mask_bits);
554        BKNI_Snprintf(buffer, len, "%#.8x %#.8x %#.8x %#.8x", mask_bits[3], mask_bits[2], mask_bits[1], mask_bits[0]);
555
556        return buffer;
557}
558
559
560BMRC_Monitor_Region *BMRC_P_Monitor_ListGetPrevRegionByAddr(BMRC_Monitor_Handle hMonitor, uint32_t addr)
561{
562        int32_t prev_idx = BMRC_P_MONITOR_REGION_PREV_GET_IDX(addr - 1);
563        BMRC_Monitor_Region *prev;
564        BMRC_Monitor_Region *cur;
565
566        prev = hMonitor->region_prev_by_addr[prev_idx];
567
568        while((!prev || (prev->addr >= addr)) && (prev_idx > 0))
569        {
570                prev = hMonitor->region_prev_by_addr[--prev_idx];
571        }
572
573        if(!prev)
574        {
575                return NULL;
576        }
577
578        cur = BLST_D_NEXT(prev, list);
579
580        while(cur && (cur->addr < addr))
581        {
582                prev = cur;
583                cur = BLST_D_NEXT(prev, list);
584        }
585
586        return prev;
587}
588
589void BMRC_P_Monitor_ListAddRegion(BMRC_Monitor_Handle hMonitor, BMRC_Monitor_Region *region)
590{
591        BMRC_Monitor_Region *prev = BMRC_P_Monitor_ListGetPrevRegionByAddr(hMonitor, region->addr);
592        BMRC_Monitor_Region *next;
593        uint32_t cur_idx = BMRC_P_MONITOR_REGION_PREV_GET_IDX(region->addr);
594        uint32_t prev_idx = 0;
595        uint32_t next_idx = BMRC_P_MONITOR_REGION_PREV_SIZE; /* if no next, next would be just outside of array */
596        uint32_t i;
597
598    if (prev) {
599        BLST_D_INSERT_AFTER(&hMonitor->regions, prev, region, list);
600                prev_idx = BMRC_P_MONITOR_REGION_PREV_GET_IDX(prev->addr);
601    } else {
602        BLST_D_INSERT_HEAD(&hMonitor->regions, region, list);
603    }
604
605        next = BLST_D_NEXT(region, list);
606
607        if(next)
608        {
609                next_idx = BMRC_P_MONITOR_REGION_PREV_GET_IDX(next->addr);
610        }
611
612        BDBG_ASSERT(next_idx <= BMRC_P_MONITOR_REGION_PREV_SIZE);
613
614        /* now we add current region's address to previous address map */
615
616        /* region is lowest in this address slot */
617        if(!prev || (prev_idx < cur_idx))
618        {
619                hMonitor->region_prev_by_addr[cur_idx] = region;
620        }
621
622        /* mark all addresses between start of current and next region with current region as previous */
623        for (i = cur_idx+1; i < next_idx; i++)
624        {
625                hMonitor->region_prev_by_addr[i] = region;
626        }
627}
628
629void BMRC_P_Monitor_ListRemoveRegion(BMRC_Monitor_Handle hMonitor, BMRC_Monitor_Region *region)
630{
631        BMRC_Monitor_Region *prev = BMRC_P_Monitor_ListGetPrevRegionByAddr(hMonitor, region->addr);
632        BMRC_Monitor_Region *next = BLST_D_NEXT(region, list);
633        uint32_t cur_idx = BMRC_P_MONITOR_REGION_PREV_GET_IDX(region->addr);
634        uint32_t prev_idx = 0;
635        uint32_t next_idx = BMRC_P_MONITOR_REGION_PREV_SIZE;
636        uint32_t i;
637
638        BLST_D_REMOVE(&hMonitor->regions, region, list);
639
640        if(prev)
641        {
642                prev_idx = BMRC_P_MONITOR_REGION_PREV_GET_IDX(prev->addr);
643        }
644
645        if(next)
646        {
647                next_idx = BMRC_P_MONITOR_REGION_PREV_GET_IDX(next->addr);
648        }
649
650        BDBG_ASSERT(next_idx <= BMRC_P_MONITOR_REGION_PREV_SIZE);
651
652        /* now we remove current region's address from previous address map */
653
654        /* update if current is same as removed region */
655        if ((uint32_t)hMonitor->region_prev_by_addr[cur_idx]->addr == (uint32_t)region->addr)
656        {
657                /* replace current with previous if appropriate, or with next otherwise */
658                if(((prev_idx == cur_idx) && prev) || !next || (next_idx > cur_idx))
659                {
660                        hMonitor->region_prev_by_addr[cur_idx] = prev;
661                }
662                else
663                {
664                        hMonitor->region_prev_by_addr[cur_idx] = next;
665                }
666        }
667
668        /* replace all addresses between start of current and next region with previous */
669        for (i = cur_idx+1; i < next_idx; i++)
670        {
671                hMonitor->region_prev_by_addr[i] = prev;
672        }
673
674}
675
676BMRC_Monitor_Region *BMRC_P_Monitor_HashGetRegionByAddr(BMRC_Monitor_Handle hMonitor, uint32_t addr)
677{
678        uint32_t hash_idx = addr % BMRC_P_MONITOR_REGION_HASH_SIZE;
679    BMRC_Monitor_Region *cur;
680
681    for(cur=BLST_D_FIRST(&hMonitor->region_hash[hash_idx]);cur;cur=BLST_D_NEXT(cur, hash))
682        {
683                if(cur->addr == addr)
684                {
685                        return cur;
686                }
687        }
688
689        return NULL;
690}
691
692void BMRC_P_Monitor_HashAddRegion(BMRC_Monitor_Handle hMonitor, BMRC_Monitor_Region *region)
693{
694        uint32_t hash_idx = region->addr % BMRC_P_MONITOR_REGION_HASH_SIZE;
695    BLST_D_INSERT_HEAD(&hMonitor->region_hash[hash_idx], region, hash);
696
697}
698
699void BMRC_P_Monitor_HashRemoveRegion(BMRC_Monitor_Handle hMonitor, BMRC_Monitor_Region *region)
700{
701        uint32_t hash_idx = region->addr % BMRC_P_MONITOR_REGION_HASH_SIZE;
702        BLST_D_REMOVE(&hMonitor->region_hash[hash_idx], region, hash);
703}
704
705
706BERR_Code
707BMRC_Monitor_Open(BMRC_Monitor_Handle *phMonitor, BREG_Handle hReg, BINT_Handle hIsr, BCHP_Handle hChp, BMRC_Handle hMrc, uint32_t ulMemLow, uint32_t ulMemHigh, BMRC_Monitor_Settings *pSettings)
708{
709    BMRC_Monitor_Handle hMonitor;
710    BERR_Code rc;
711    unsigned i;
712        uint32_t max_checkers;
713
714    BSTD_UNUSED(hChp);
715    BDBG_ASSERT(hReg);
716    BDBG_ASSERT(hIsr);
717    BDBG_ASSERT(hChp);
718
719    if (ulMemLow >= ulMemHigh)
720    {
721        BDBG_ERR(("High memory address must be greater than low memory address."));
722        return BERR_TRACE(BERR_INVALID_PARAMETER);
723    }
724
725    hMonitor = (BMRC_Monitor_Handle) BKNI_Malloc(sizeof(BMRC_P_MonitorContext));
726    if (!hMonitor) {
727        return BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
728    }
729
730        BMRC_GetMaxCheckers(hMrc, &max_checkers);
731
732        if (pSettings)
733        {
734                if ((pSettings->ulNumCheckersToUse != UINT32_C(-1)) &&
735                        (pSettings->ulNumCheckersToUse > max_checkers))
736                {
737                        rc = BERR_INVALID_PARAMETER;
738                        BDBG_ERR(("Not enough checkers available. Num checkers: %d, Max checkers: %d",
739                                      pSettings->ulNumCheckersToUse, max_checkers));
740                        BKNI_Free(hMonitor);
741                        return rc;
742                }
743
744                hMonitor->stSettings = *pSettings;
745        }
746        else
747        {
748            hMonitor->stSettings = s_stDefaultSettings;
749        }
750
751        /* create mutex for re-entrant control */
752        rc = BERR_TRACE(BKNI_CreateMutex(&(hMonitor->pMutex)));
753        if (rc != BERR_SUCCESS)
754        {
755                BDBG_ERR(("Failed to create mutex."));
756                BKNI_Free(hMonitor);
757                return rc;
758        }
759
760    hMonitor->mrc = hMrc;
761    BMRC_GetSettings(hMonitor->mrc, &hMonitor->mrcSettings);
762    hMonitor->reg = hReg;
763    hMonitor->isr = hIsr;
764    hMonitor->mem_high = ulMemHigh;
765    hMonitor->mem_low = ulMemLow;
766        hMonitor->max_ranges = (hMonitor->stSettings.ulNumCheckersToUse == UINT32_C(-1)) ?
767                                                   max_checkers : hMonitor->stSettings.ulNumCheckersToUse;
768        hMonitor->max_regions = hMonitor->max_ranges+1;
769        hMonitor->combined_regions = BKNI_Malloc(sizeof(BMRC_Monitor_Region) * hMonitor->max_regions);
770        hMonitor->num_combined_regions = 0;
771        hMonitor->num_regions = 0;
772
773    BLST_D_INIT(&hMonitor->regions);
774    BLST_D_INIT(&hMonitor->regions);
775    BLST_D_INIT(&hMonitor->custom_regions);
776        for (i=0; i<BMRC_P_MONITOR_REGION_HASH_SIZE; i++)
777        {
778            BLST_D_INIT(&hMonitor->region_hash[i]);
779        }
780
781        BKNI_Memset(hMonitor->region_prev_by_addr, (uint32_t)NULL, sizeof(hMonitor->region_prev_by_addr));
782
783    BMRC_P_Monitor_MaskBuild(&hMonitor->clients, BMRC_P_Monitor_astHwClients);
784        /* inverse because we want clients mask bits to be on for allowed clients to match hardware */
785    BMRC_P_Monitor_MasksInverse(&hMonitor->clients, &hMonitor->clients);
786    BMRC_P_Monitor_MasksClear(&hMonitor->user_clients_jailed);
787        hMonitor->protect_mem_low = false;
788
789    for (i=0;i<hMonitor->max_ranges;i++) {
790        BMRC_Checker_Handle hChecker = NULL;
791
792        rc = BMRC_Checker_Create(hMrc, &hChecker);
793        if (rc!=BERR_SUCCESS) {
794            BKNI_Free(hMonitor);
795                        BDBG_ERR(("Out of checkers on checker create."));
796            return rc;
797        }
798
799        rc = BMRC_Checker_SetCallback(hChecker, BMRC_P_Monitor_isr, hMonitor, i);
800        if (rc!=BERR_SUCCESS) {
801            BKNI_Free(hMonitor);
802            return rc;
803        }
804
805        rc = BMRC_Checker_EnableCallback(hChecker);
806        if (rc!=BERR_SUCCESS) {
807            BKNI_Free(hMonitor);
808            return rc;
809        }
810
811        hMonitor->ahCheckers[i] = hChecker;
812    }
813
814    BMRC_P_Monitor_Update(hMonitor, true);
815
816    *phMonitor = hMonitor;
817
818    return BERR_SUCCESS;
819}
820
821void
822BMRC_Monitor_Close(BMRC_Monitor_Handle hMonitor)
823{
824    BMRC_Monitor_Region *region;
825    unsigned i;
826    BERR_Code rc;
827
828    for (i=0;i<hMonitor->max_ranges;i++) {
829        rc = BMRC_Checker_Destroy(hMonitor->ahCheckers[i]);
830        if (rc!=BERR_SUCCESS) {
831            BDBG_ERR(("BMRC_Checker_Destroy returned error %#x, ignored"));
832        }
833    }
834
835        for (i=0;i<BMRC_P_MONITOR_REGION_HASH_SIZE; i++)
836        {
837            while (NULL != (region = BLST_D_FIRST(&hMonitor->region_hash[i]))) {
838                    BLST_D_REMOVE_HEAD(&hMonitor->region_hash[i], hash);
839                }
840    }
841
842    while (NULL != (region = BLST_D_FIRST(&hMonitor->regions))) {
843        BLST_D_REMOVE_HEAD(&hMonitor->regions, list);
844        BKNI_Free(region);
845    }
846
847        BKNI_Free(hMonitor->combined_regions);
848
849        /* destroy mutex */
850        BKNI_DestroyMutex(hMonitor->pMutex);
851    BKNI_Free(hMonitor);
852    return;
853}
854
855BERR_Code
856BMRC_Monitor_GetDefaultSettings(BMRC_Monitor_Settings *pDefSettings)
857{
858    if (!pDefSettings)
859    {
860        return BERR_INVALID_PARAMETER;
861    }
862
863    *pDefSettings = s_stDefaultSettings;
864
865    return BERR_SUCCESS;
866}
867
868BERR_Code
869BMRC_Monitor_GetSettings(BMRC_Monitor_Handle hMonitor, BMRC_Monitor_Settings *pSettings)
870{
871    if (!pSettings)
872    {
873        return BERR_INVALID_PARAMETER;
874    }
875
876    *pSettings = hMonitor->stSettings;
877
878    return BERR_SUCCESS;
879}
880
881/* cheap version of toupper */
882#define B_TOUPPER(x) ((x)&(~0x20))
883
884/* return true if client found */
885static bool
886BMRC_P_Monitor_GetClientsByFname(const char *fname, BMRC_Monitor_Clients *clients)
887{
888    const char *ptr;
889    unsigned i,j;
890
891    if (fname==NULL) { /* filename is unknown */
892        goto not_found;
893    }
894
895    for(ptr=fname;*ptr!='\0';ptr++) { } /* scan to the end of string */
896
897    for(;*ptr!='\\' && *ptr!='/';ptr--) { /* back track to found \ or / */
898        if (ptr==fname) { /* no directory */
899            goto no_dir;
900        }
901    }
902    ptr++;
903no_dir:
904    for(fname = ptr, i=0;i<BMRC_P_Monitor_FileClientsTblSize;i++) {
905        for(j=0;B_TOUPPER(BMRC_P_Monitor_astFileClients[i].prefix[j])==B_TOUPPER(fname[j]);) { /* do strncmp type of stuff */
906            j++;
907            if (BMRC_P_Monitor_astFileClients[i].prefix[j]=='\0') {
908                /* bingo!!! found match */
909                                BDBG_MSG_TRACE(("allocation from %s matched to %s clients", fname, BMRC_P_Monitor_astFileClients[i].prefix));
910                BMRC_P_Monitor_MaskBuild(clients, BMRC_P_Monitor_astFileClients[i].clients);
911                return true;
912            }
913        }
914    }
915    BDBG_MSG_TRACE(("allocation from %s not matched to known file, access allowed for all HW clients", fname));
916not_found:
917        /* allow all clients to access memory allocated by unknown files. */
918    BMRC_P_Monitor_MasksFill(clients);
919
920    return false;
921}
922
923
924static void
925BMRC_P_Monitor_Alloc(void *cnxt, uint32_t addr, size_t size, const char *fname, int line)
926{
927    BMRC_Monitor_Handle hMonitor = cnxt;
928    BMRC_Monitor_Region *region;
929        BMRC_Monitor_Clients jailed_clients;
930        BMRC_Monitor_Clients clients;
931    bool found;
932        uint32_t i;
933
934        static uint32_t iSkipCount = 0;
935
936    BDBG_MSG_TRACE(("alloc: addr %#x size %#x file %s", (unsigned)addr, (unsigned)size, fname?fname:""));
937
938    found = BMRC_P_Monitor_GetClientsByFname(fname, &clients);
939   
940    region = BKNI_Malloc(sizeof(*region));
941    region->clients = clients;
942   
943    BMRC_P_Monitor_MasksClear(&region->user_clients_allowed);
944    region->addr = addr;
945    region->size = size;
946        region->fname = fname;
947        region->line = line;
948
949        BKNI_AcquireMutex(hMonitor->pMutex);
950
951        BMRC_P_Monitor_HashAddRegion(hMonitor, region);
952        BMRC_P_Monitor_ListAddRegion(hMonitor, region);
953        hMonitor->num_regions++;
954
955/* validation code */
956#if 0
957        BMRC_Monitor_ValidateRegionList(hMonitor);
958/*     
959        BMRC_Monitor_DumpRegionPrevByAddrTable(hMonitor);
960*/
961#endif
962
963/* optimization code */
964#if 1
965        /* inverse to get jailed clients */
966        BMRC_P_Monitor_MasksInverse(&jailed_clients, &hMonitor->clients);
967
968        if (BMRC_P_Monitor_MasksHasCommon(&region->clients, &jailed_clients))
969        {
970                /* optimize when number of regions get large */
971                if ((hMonitor->num_combined_regions > 0) &&
972                        (hMonitor->num_regions >= BMRC_P_MONITOR_OPTIMIZE_THRESHOLD) &&
973                        (iSkipCount < (hMonitor->num_regions/BMRC_P_MONITOR_OPTIMIZE_THRESHOLD) * BMRC_P_MONITOR_OPTIMIZE_SKIP_FACTOR))
974                {
975                        iSkipCount++;
976
977                        /* don't need full update if new region fits in existing regions */
978                        for (i=0; i < hMonitor->num_combined_regions; i++)
979                        {
980                                if ((region->addr >= hMonitor->combined_regions[i].addr) &&
981                                        (region->addr + region->size <= hMonitor->combined_regions[i].addr + hMonitor->combined_regions[i].size))
982                                {
983                                        goto done;
984                                }
985                        }
986
987                        /* grow expanded regions, simplified for speed when dealing with many regions */
988                        for (i = 0; i <= hMonitor->num_combined_regions; i++)
989                        {
990                                uint32_t prev_region_start = (i==0)? 0 : hMonitor->combined_regions[i-1].addr;
991                                uint32_t prev_region_end   = (i==0)? 0 : ((hMonitor->combined_regions[i-1].addr + hMonitor->combined_regions[i-1].size) - 1);
992                                uint32_t cur_region_start  = (i==hMonitor->num_combined_regions)? 0xFFFFFFFF : hMonitor->combined_regions[i].addr;
993                                uint32_t cur_region_end    = (i==hMonitor->num_combined_regions)? 0xFFFFFFFF : ((hMonitor->combined_regions[i].addr + hMonitor->combined_regions[i].size) - 1);
994                                uint32_t region_start = region->addr;
995                                uint32_t region_end = region->addr + region->size - 1;
996
997                                if (((region_start >= prev_region_start) && (region_end > prev_region_end) && (region_end < cur_region_start - 1)) ||
998                                        ((region_start > prev_region_end + 1) && (region_start < cur_region_start) && (region_end <= cur_region_end)))
999                                {
1000                                        if ((i > 0) &&
1001                                                ((i == hMonitor->num_combined_regions) ||
1002                                                 (region_start <= prev_region_end) || /* new region starts in prev */
1003                                                 (region_start - (prev_region_end + 1)) < (cur_region_start - (region_end + 1))))  /* new region is closer to prev or cur region? */
1004                                        {
1005                                                /* add to end of previous region */
1006                                                hMonitor->combined_regions[i-1].size = (region_start + region->size) - hMonitor->combined_regions[i-1].addr;
1007                                        }
1008                                        else 
1009                                        {
1010                                                /* add to front of current region */
1011                                                hMonitor->combined_regions[i].size += hMonitor->combined_regions[i].addr - region_start;
1012                                                hMonitor->combined_regions[i].addr = region_start;
1013                                        }
1014                                        BMRC_P_Monitor_Update(hMonitor, false);
1015                                        goto done;
1016                                }
1017                        }
1018                        BDBG_MSG(("New region not combined with any existing region."));
1019                }
1020
1021                BMRC_P_Monitor_Update(hMonitor, true);
1022                iSkipCount = 0;
1023        }
1024
1025#else
1026        BMRC_P_Monitor_Update(hMonitor, true);
1027#endif
1028
1029done:
1030        BKNI_ReleaseMutex(hMonitor->pMutex);
1031
1032    return;
1033}
1034
1035static void
1036BMRC_P_Monitor_Free(void *cnxt, uint32_t addr)
1037{
1038    BMRC_Monitor_Handle hMonitor = cnxt;
1039    BMRC_Monitor_Region *region;
1040        static uint32_t iSkipCount = 0;
1041
1042    BDBG_MSG_TRACE(("free: addr %#x", (unsigned)addr));
1043
1044        BKNI_AcquireMutex(hMonitor->pMutex);
1045
1046        region = BMRC_P_Monitor_HashGetRegionByAddr(hMonitor, addr);
1047        if (region)
1048        {
1049                BMRC_P_Monitor_HashRemoveRegion(hMonitor, region);
1050                BMRC_P_Monitor_ListRemoveRegion(hMonitor, region);
1051                BKNI_Free(region);
1052                hMonitor->num_regions--;
1053
1054/* validation code */
1055#if 0
1056                BMRC_Monitor_ValidateRegionList(hMonitor);
1057/*
1058                BMRC_Monitor_DumpRegionPrevByAddrTable(hMonitor);
1059*/
1060#endif
1061       
1062                if ((hMonitor->num_regions < BMRC_P_MONITOR_OPTIMIZE_THRESHOLD) ||
1063                        (iSkipCount >= (hMonitor->num_regions/BMRC_P_MONITOR_OPTIMIZE_THRESHOLD) * BMRC_P_MONITOR_OPTIMIZE_SKIP_FACTOR))
1064                {
1065                    BMRC_P_Monitor_Update(hMonitor, true);
1066                        iSkipCount = 0;
1067                }
1068                else
1069                {
1070                        iSkipCount++;
1071                }
1072        }
1073        else
1074        {
1075                BDBG_ERR(("Trying to free unknown block"));
1076        }
1077
1078        BKNI_ReleaseMutex(hMonitor->pMutex);
1079    return;
1080}
1081
1082
1083/* this function combines all memory regions, what are accessible to the given clients, into the set of continious regions, using selected threshold_ */
1084static bool
1085BMRC_P_Monitor_Combine(BMRC_Monitor_Handle hMonitor, const BMRC_Monitor_Clients *clients, uint32_t threshold, BMRC_Monitor_Region *regions, unsigned max_regions, unsigned *num_regions)
1086{
1087    int i;
1088    BMRC_Monitor_Region *cur;
1089#if BMRC_P_MONITOR_DBG_TRACE
1090    char buffer[256];
1091#endif
1092
1093        for(i=-1, cur=BLST_D_FIRST(&hMonitor->regions);cur;cur=BLST_D_NEXT(cur, list))
1094        {
1095                /* check if clients exist in region */
1096        if ( !(BMRC_P_Monitor_MasksHasCommon(&cur->clients, clients))) {
1097                        /* this region not matched */
1098            continue;
1099        }
1100
1101        BDBG_MSG_TRACE(("region(%d) %p %s addr %#x size %#x", i, cur, BMRC_P_Monitor_BuildClientIdString(hMonitor, &cur->clients, mask_bits), cur->addr, cur->size, buffer, sizeof(buffer)));
1102
1103        if (i<0) {
1104            regions[0] = *cur;
1105            i=0;
1106        } else {
1107            BDBG_MSG_TRACE(("region(%d) (%#x..%#x) <-> (%#x..%#x)", i, cur->addr, cur->addr+cur->size, regions[i].addr, regions[i].addr+regions[i].size+threshold));
1108                        /* join two regions */
1109#if 0
1110                        next = BMRC_P_Monitor_ListGetPrevRegionByAddr(hMonitor, regions[i].addr + regions[i].size + threshold);
1111                        if(next && (next->addr+next->size > regions[i].addr+regions[i].size))
1112                        {
1113                                regions[i].size = (next->addr + next->size) - regions[i].addr;
1114                                cur = next;
1115#else
1116            if ((regions[i].addr + regions[i].size+threshold) >= cur->addr ) {
1117                regions[i].size = (cur->addr + cur->size) - regions[i].addr;
1118#endif
1119            } else { /* create new region */
1120                i++;
1121                if ((unsigned)i>=max_regions) { /* too many regions */
1122                    *num_regions=(unsigned)i;
1123                    return false;
1124                }
1125                regions[i] = *cur;
1126            }
1127        }
1128    }
1129    *num_regions = i+1;
1130
1131#if 0
1132        /* useful for seeing state of combined regions */
1133        {
1134                unsigned i;
1135                char buffer[256];
1136                BDBG_WRN(("Combined: max_regions %d, threshold 0x%x", max_regions, threshold));
1137                for(i=0; i < *num_regions; i++){
1138                        BDBG_WRN(("          region %d, %x..%x, clients %s", i, regions[i].addr, regions[i].addr + regions[i].size,
1139                                BMRC_P_Monitor_BuildClientIdString(hMonitor, &regions[i].clients, buffer, sizeof(buffer))));
1140                }
1141        }
1142#endif
1143
1144    return true;
1145}
1146
1147static void
1148BMRC_P_Monitor_Disable(BMRC_Monitor_Handle hMonitor, unsigned arc_no)
1149{
1150    BMRC_Checker_Handle hChecker = hMonitor->ahCheckers[arc_no];
1151    BMRC_Checker_Disable(hChecker);
1152    return;
1153}
1154
1155static void
1156BMRC_P_Monitor_Program(BMRC_Monitor_Handle hMonitor, unsigned arc_no, uint32_t addr, size_t size, const BMRC_Monitor_Clients *clients, bool exclusive)
1157{
1158    BMRC_Checker_Handle hChecker = hMonitor->ahCheckers[arc_no];
1159    BMRC_Client client_id;
1160    uint32_t aligned_addr;
1161    uint32_t aligned_end;
1162    uint32_t aligned_size;
1163        uint32_t memc_id = hMonitor->mrcSettings.usMemcId;
1164    static uint32_t low_size = 0, high_size=0; /* These is a safe non-const static. It is used for diagnostics only. */
1165
1166    /* disable read and write check first */
1167    BMRC_Checker_Disable(hChecker);
1168
1169    BDBG_MSG(("MEMC%d: programming ARC %u with %#x...%#x", memc_id, arc_no, (unsigned) addr, (unsigned) (addr+size)));
1170        /* assuming kernel is only on MEMC 0 */
1171    if (memc_id == 0 && arc_no == 0 && hMonitor->protect_mem_low)
1172        {
1173        if (addr == hMonitor->mem_low && size != low_size) {
1174            low_size = size;
1175            /* Ensure that the console shows when ARC0 is protecting the kernel. See below for protection code. */
1176            BDBG_WRN(("MEMC%d: ARC0 is protecting low memory for range %#x...%#x (%d MB)", memc_id, (unsigned) addr, (unsigned) (addr+size), size/1024/1024));
1177        } else if (addr+size == hMonitor->mem_high && size != high_size) {
1178            high_size = size;
1179            BDBG_MSG(("MEMC%d: ARC0 is protecting high memory for range %#x...%#x (%d MB)", memc_id, (unsigned) addr, (unsigned) (addr+size), size/1024/1024)); /* BMEM grows head toward high addresses, therefore  BDBG_WRN causes to much noise */
1180        }
1181    }
1182
1183#if 0
1184    /* useful for seeing client state when programming */
1185    {
1186                char buffer[256];
1187                BDBG_WRN(("ARC %d %s", arc_no, BMRC_P_Monitor_BuildClientIdString(hMonitor, clients, buffer, sizeof(buffer))));
1188    }
1189#endif
1190
1191    /*
1192    ** Program up to, but do not include, the last address in the range. In some cases, calls to alloc() will
1193    ** will return memory that starts at that last, protected address. Accesses to that address could be a
1194    ** violation. In the 7038/3560, a bug in the ARC allowed those violations to go undetected. That bug is
1195    ** fixed in the 7401. See PR 13737.
1196    */
1197
1198    aligned_addr = BMRC_P_MONITOR_ALIGNED_RANGE_START(addr, exclusive);
1199    aligned_end = BMRC_P_MONITOR_ALIGNED_RANGE_END(addr + size, exclusive);
1200
1201 /* alignment may have changed starting or end addresses, size adjusted */
1202    aligned_size = aligned_end - aligned_addr;
1203
1204    if (!aligned_size)
1205    {
1206        /* size is 0, arc not enabled */
1207        return;
1208    }
1209
1210    BMRC_Checker_SetRange(hChecker, aligned_addr, aligned_size);
1211
1212    /* program clients */
1213
1214    for (client_id = 0; client_id < BMRC_Client_eMaxCount; client_id++)
1215    {
1216        BMRC_ClientInfo client_info;
1217        BMRC_Checker_GetClientInfo(hMonitor->mrc, client_id, &client_info);
1218
1219        if (client_info.usClientId != BMRC_Client_eInvalid)
1220        {
1221            (BMRC_P_MONITOR_CLIENT_MASK_IS_SET(clients->client_masks, client_id)) ?
1222                BMRC_Checker_SetClient(hChecker, (BMRC_Client)client_id, BMRC_AccessType_eBoth) :
1223                BMRC_Checker_SetClient(hChecker, (BMRC_Client)client_id, BMRC_AccessType_eNone);
1224        }
1225    }
1226
1227    /* activate range checker */
1228    BMRC_Checker_SetAccessCheck(hChecker, BMRC_AccessType_eBoth);
1229
1230    /*
1231    By default, block mode is set to BMRC_AccessType_eWrite for all memory violations.
1232
1233    BMRC_AccessType_eWrite prevents memory corruption by HW cores that shouldn't access it.
1234    If you believe write access was blocked in error, please inspect BMRC_P_Monitor_astHwClients[] in bmrc_monitor_clients.c,
1235    BMRC_P_astClientTbl[] in bmrc_clienttable_priv.c
1236
1237    Read will not be blocked, but you will see a BDBG_ERR if a violation occurs.
1238
1239    This can be configured separately for kernel and non-kernel memory to block only reads, only writes, both, or neither
1240    when a violation occurs with the BMRC_Monitor_Settings structure used in BMRC_Monitor_Open().
1241    */
1242
1243        /* assuming kernel is only on MEMC 0 */
1244    if (hMonitor->mrcSettings.usMemcId == 0 && arc_no == 0 && hMonitor->protect_mem_low)
1245    {
1246        BMRC_Checker_SetBlock(hChecker, hMonitor->stSettings.eKernelBlockMode);
1247    }
1248    else
1249    {
1250        BMRC_Checker_SetBlock(hChecker, hMonitor->stSettings.eBlockMode);
1251    }
1252
1253    BMRC_Checker_SetExclusive(hChecker, exclusive);
1254    BMRC_Checker_Enable(hChecker);
1255
1256    return;
1257}
1258
1259/* Monitor checker error messages are based on the SCB Protocol specifications at
1260   http://www.blr.broadcom.com/projects/DVT_BLR/Memc_Arch/. */
1261#if (BCHP_CHIP==7440) || (BCHP_CHIP==7601) || (BCHP_CHIP==7635) || (BCHP_CHIP==7630) || (BCHP_CHIP==7640)
1262static void
1263BMRC_P_Monitor_Dump_isr(BMRC_Monitor_Handle hMonitor, unsigned arc_no, BMRC_CheckerInfo *pCheckerInfo)
1264{
1265    uint32_t viol_start;
1266    uint32_t start, size;
1267
1268    BSTD_UNUSED(hMonitor);
1269    BSTD_UNUSED(arc_no);
1270
1271    start = pCheckerInfo->ulStart;
1272    size = pCheckerInfo->ulSize;
1273    viol_start = pCheckerInfo->ulAddress;
1274
1275    BDBG_ERR(("Address Range Checker %d (ARC%d) has detected a memory access violation in MEMC %d", arc_no, arc_no, pCheckerInfo->usMemcId));
1276
1277    if (pCheckerInfo->bExclusive)
1278    {
1279        BDBG_ERR(("violating access outside of exclusive range: %#x..%#x", (unsigned)start, (unsigned)(start+size)));
1280    }
1281    else
1282    {
1283        BDBG_ERR(("violation access in prohibited range: %#x..%#x", (unsigned)start, (unsigned)(start+size)));
1284    }
1285
1286    BDBG_ERR(("violation start address: %#x", (unsigned)viol_start));
1287    BDBG_ERR(("violation client: %d(%s)", pCheckerInfo->usClientId, pCheckerInfo->pchClientName));
1288    BDBG_ERR(("transfer length:  %d", pCheckerInfo->ulLength));
1289
1290    switch(pCheckerInfo->ulMode)
1291    {
1292    case BMRC_P_MONITOR_CCB_LINEAR_ACCESS:
1293        BDBG_ERR(("request type:     0x%03x(Linear Access)", pCheckerInfo->ulMode));
1294        break;
1295
1296    case BMRC_P_MONITOR_CCB_CACHE_ACCESS:
1297        BDBG_ERR(("request type:     0x%03x(Cache Access)", pCheckerInfo->ulMode));
1298        break;
1299
1300    case BMRC_P_MONITOR_CCB_DISPLAY_ACCESS:
1301        BDBG_ERR(("request type:     0x%03x(Display Access)",  pCheckerInfo->ulMode));
1302        break;
1303
1304    default:
1305        BDBG_ERR(("request type:     0x%03x(Unknown Command Type)", pCheckerInfo->ulMode));
1306        break;
1307    }
1308}
1309#else
1310
1311static void
1312BMRC_P_Monitor_Dump_isr(BMRC_Monitor_Handle hMonitor, unsigned arc_no, BMRC_CheckerInfo *pCheckerInfo)
1313{
1314    uint32_t viol_start, viol_end;
1315    uint32_t start, size;
1316    BMRC_P_Monitor_ScbCommand eScbCommand = BMRC_P_Monitor_ScbCommand_eUnknown;
1317    uint32_t i = 0;
1318        BMRC_Monitor_Region *cur;
1319
1320    BSTD_UNUSED(hMonitor);
1321    BSTD_UNUSED(arc_no);
1322
1323    start = pCheckerInfo->ulStart;
1324    size = pCheckerInfo->ulSize;
1325    viol_start = pCheckerInfo->ulAddress;
1326    viol_end = pCheckerInfo->ulAddressEnd;
1327
1328    BDBG_ERR(("Address Range Checker %d (ARC%d) has detected a memory access violation in MEMC %d", arc_no, arc_no, pCheckerInfo->usMemcId));
1329
1330    if (pCheckerInfo->bExclusive)
1331    {
1332        BDBG_ERR(("violating access outside of exclusive range: %#x..%#x", (unsigned)start, (unsigned)(start+size)));
1333    }
1334    else
1335    {
1336        BDBG_ERR(("violation access in prohibited range: %#x..%#x", (unsigned)start, (unsigned)(start+size)));
1337    }
1338
1339    BDBG_ERR(("violation start address: %#x", (unsigned)viol_start));
1340#if BMRC_CHECKER_USE_NEW_NAME_SUFFIX
1341    BDBG_ERR(("violation end address:   %#x", (unsigned)viol_end));
1342#endif
1343
1344    for (i = 0; i < BMRC_P_MONITOR_SCB_ACCESS_TABLE_SIZE; i++)
1345    {
1346        if ((pCheckerInfo->ulReqType & g_ScbCommandInfoTbl[i].ulMask) == g_ScbCommandInfoTbl[i].ulCommand)
1347        {
1348            eScbCommand = g_ScbCommandInfoTbl[i].eScbCommand;
1349            break;
1350        }
1351    }
1352
1353    if (eScbCommand == BMRC_P_Monitor_ScbCommand_eUnknown)
1354    {
1355        BDBG_ERR(("violation client: %d(%s)  request type: 0x%03x(Unknown Command Type)", pCheckerInfo->usClientId, pCheckerInfo->pchClientName,  pCheckerInfo->ulReqType));
1356        return;
1357    }
1358
1359    BDBG_ERR(("violation client: %d(%s)  request type: 0x%03x(%s)", pCheckerInfo->usClientId, pCheckerInfo->pchClientName,  pCheckerInfo->ulReqType, g_ScbCommandInfoTbl[i].pName));
1360
1361    switch(eScbCommand)
1362    {
1363    uint32_t ulTransferSize, ulXSize, ulYLines;
1364    bool bFrameAccess;
1365
1366    case BMRC_P_Monitor_ScbCommand_eLR:
1367    case BMRC_P_Monitor_ScbCommand_eLW:
1368        ulTransferSize = (pCheckerInfo->ulReqType & BMRC_P_MONITOR_SCB_TRANSFER_SIZE_MASK);
1369                ulTransferSize = (ulTransferSize == 0)? BMRC_P_MONITOR_SCB_TRANSFER_SIZE_MAX : ulTransferSize;
1370
1371        BDBG_ERR(("transfer length %d bytes (%d Jwords)",
1372                 ulTransferSize * BMRC_P_MONITOR_JWORD_BYTES, ulTransferSize));
1373        break;
1374
1375    case BMRC_P_Monitor_ScbCommand_eDR:
1376    case BMRC_P_Monitor_ScbCommand_eDW:
1377        ulTransferSize = (pCheckerInfo->ulReqType & BMRC_P_MONITOR_SCB_TRANSFER_SIZE_MASK);
1378        ulTransferSize = (ulTransferSize == 0)? BMRC_P_MONITOR_SCB_TRANSFER_SIZE_MAX : ulTransferSize;
1379#if BMRC_P_MONITOR_USE_NMBX_ID
1380        BDBG_ERR(("transfer length %d bytes (%d Gwords) %d NMBX_ID %d NMBX %d",
1381                 ulTransferSize * BMRC_P_MONITOR_GWORD_BYTES, ulTransferSize,
1382                 pCheckerInfo->ulNmbxId, pCheckerInfo->ulNmbx));
1383#else
1384        BDBG_ERR(("transfer length %d butes (%d Gwords) %d NMBX %d",
1385                 ulTransferSize * BMRC_P_MONITOR_GWORD_BYTES, ulTransferSize,
1386                 pCheckerInfo->ulNmbx));
1387#endif
1388        break;
1389
1390    case BMRC_P_Monitor_ScbCommand_eMR:
1391    case BMRC_P_Monitor_ScbCommand_eMW:
1392        ulXSize      = (pCheckerInfo->ulReqType & BMRC_P_MONITOR_SCB_MPEG_X_BIT)? 3: 2;
1393        ulYLines     = (pCheckerInfo->ulReqType & BMRC_P_MONITOR_SCB_MPEG_Y_MASK);
1394                ulYLines     = (ulYLines == 0)? BMRC_P_MONITOR_SCB_YLINES_MAX : ulYLines;
1395        bFrameAccess = (pCheckerInfo->ulReqType & BMRC_P_MONITOR_SCB_MPEG_T_BIT);
1396
1397#if BMRC_P_MONITOR_USE_NMBX_ID
1398        BDBG_ERR(("X:%d bytes (%d Owords) Y:%d lines T:%s NMBX_ID %d NMBX %d",
1399                 ulXSize * BMRC_P_MONITOR_OWORD_BYTES, ulXSize, ulYLines,
1400                 bFrameAccess ? "frame access" : "field access",
1401                 pCheckerInfo->ulNmbxId, pCheckerInfo->ulNmbx));
1402#else
1403        BDBG_ERR(("X:%d bytes (%d Owords) Y:%d lines T:%s NMBX %d",
1404                 ulXSize * BMRC_P_MONITOR_OWORD_BYTES, ulXSize, ulYLines,
1405                 bFrameAccess ? "frame access" : "field access",
1406                 pCheckerInfo->ulNmbx));
1407#endif
1408        break;
1409
1410    default:
1411        break;
1412    }
1413       
1414        for(cur=BLST_D_FIRST(&hMonitor->regions);cur;cur=BLST_D_NEXT(cur, list))
1415        {
1416                if (((viol_start >= cur->addr) && (viol_start <= (cur->addr + cur->size))) ||
1417                        ((viol_end >= cur->addr) && (viol_end <= (cur->addr + cur->size))))
1418                {
1419                        BDBG_ERR(("violated region: 0x%x..0x%x,", cur->addr, cur->addr + cur->size, cur->fname, cur->line));
1420                        BDBG_ERR(("allocated by %s:%d", cur->fname, cur->line));
1421                }
1422        }
1423
1424#if 0
1425    /* useful for seeing state of all regions at interrupt time */
1426    {
1427        int i;
1428        char buffer[256];
1429        const BMRC_Monitor_Region *cur;
1430        for(i=0,cur=BLST_D_FIRST(&hMonitor->regions);cur;cur=BLST_D_NEXT(cur, list)) {
1431            BDBG_WRN(("region %d, %x..%x, clients %s", i++, cur->addr, cur->addr + cur->size,
1432            BMRC_P_Monitor_BuildClientIdString(hMonitor, &cur->clients, buffer, sizeof(buffer))));
1433        }
1434    }
1435#endif
1436
1437    return;
1438}
1439#endif /* (BCHP_CHIP==7440) || (BCHP_CHIP==7601) || (BCHP_CHIP==7635) */
1440
1441/* this function updates current range checker programming based on current memory map and jail */
1442static void
1443BMRC_P_Monitor_Update(BMRC_Monitor_Handle hMonitor, bool bCombine)
1444{
1445    BMRC_Monitor_Region *combined_regions = hMonitor->combined_regions;
1446    bool success, protect_low = false;
1447    uint32_t threshold=16;
1448    unsigned num_regions = hMonitor->num_combined_regions;
1449        unsigned max_regions = hMonitor->max_regions;
1450    unsigned i, j;
1451    uint32_t addr;
1452    unsigned last, first = 0;
1453#if BDBG_DEBUG_BUILD
1454        uint32_t memc_id = hMonitor->mrcSettings.usMemcId;
1455#endif
1456
1457        BMRC_Monitor_Clients jailed_clients;
1458
1459        /* inverse to get jailed clients */
1460        BMRC_P_Monitor_MasksInverse(&jailed_clients, &hMonitor->clients);
1461
1462    for(i=0;i<hMonitor->max_ranges;i++) {
1463        BMRC_P_Monitor_Disable(hMonitor, i);
1464    }
1465
1466    if (BLST_D_FIRST(&hMonitor->custom_regions)) {
1467        const BMRC_Monitor_Region *region;
1468
1469        BDBG_MSG_TRACE(("use custom ARC mapping"));
1470        for(i=0,region=BLST_D_FIRST(&hMonitor->custom_regions);region;i++,region=BLST_D_NEXT(region,list)) {
1471            uint32_t size = BMRC_P_MONITOR_ALIGNED_RANGE_END(region->addr+region->size, false) -
1472                                                        BMRC_P_MONITOR_ALIGNED_RANGE_START(region->addr, false);
1473
1474            if (size == 0)
1475            {
1476                BDBG_WRN(("aligned size %#x is 0, ARC %u will not be enabled", size, i));
1477            }
1478            BMRC_P_Monitor_Program(hMonitor, i, region->addr, region->size, &hMonitor->clients, false);
1479        }
1480        goto done;
1481    }
1482
1483        hMonitor->protect_mem_low = false;
1484
1485        if(bCombine)
1486        {
1487    for(;threshold<hMonitor->mem_high - hMonitor->mem_low;threshold<<=1) {
1488        success = BMRC_P_Monitor_Combine(hMonitor, &jailed_clients, threshold, combined_regions, max_regions, &num_regions);
1489                protect_low = false;
1490                first = 0;
1491
1492                BDBG_MSG_TRACE(("combine %u regions status %d(%#x)", num_regions, (int)success, threshold));
1493
1494                for(i=0;i<num_regions;i++) {
1495            BDBG_MSG_TRACE(("region %d addr=%#x size=%#x", i, (unsigned)combined_regions[i].addr, (unsigned)combined_regions[i].size));
1496        }
1497
1498        if (!success) {
1499            continue;
1500        }
1501
1502                /* using first ARC to disable hardware access to low memory if necessary */
1503                if (combined_regions[first].addr - hMonitor->mem_low> 0)
1504                {
1505                        protect_low = true;
1506                        first++;
1507                }
1508
1509                if (((num_regions-1)+first <= hMonitor->max_ranges) || (num_regions==0)) {
1510                        break;
1511                }
1512                else
1513                {
1514                        BDBG_MSG_TRACE(("not enough ranges. regions: %d, max_ranges %d, first %d\n", num_regions, hMonitor->max_ranges, first));
1515                }
1516    }
1517        }
1518
1519#if 0
1520        for(i=0; i < num_regions; i++){
1521                BDBG_WRN(("region %d, %x..%x", i, combined_regions[i].addr, combined_regions[i].addr + combined_regions[i].size));
1522        }
1523#endif
1524
1525        if (num_regions)
1526        {
1527                /* using first ARC to disable hardware access to low memory if necessary */
1528                if (protect_low)
1529                {
1530            BDBG_MSG(("MEMC %d: ARC0 is protecting low memory for range %#x...%#x (%d MB)", memc_id, hMonitor->mem_low, combined_regions[0].addr, (combined_regions[0].addr - hMonitor->mem_low)/1024/1024)); /* BMEM grows head toward high addresses, therefore  BDBG_WRN causes to much noise */
1531                        BMRC_P_Monitor_Program(hMonitor, 0, hMonitor->mem_low, combined_regions[0].addr - hMonitor->mem_low, &hMonitor->clients, false);
1532                        hMonitor->protect_mem_low = true;
1533                }
1534
1535                last = hMonitor->max_ranges - 1;
1536                addr = (combined_regions[num_regions-1].addr + combined_regions[num_regions-1].size);
1537                BDBG_MSG_TRACE(("addr %#x mem_high %#x", addr, hMonitor->mem_high));
1538                /* using last ARC to disable hardware access to high memory */
1539                if (addr+threshold < hMonitor->mem_high)
1540                {
1541            BDBG_MSG(("MEMC %d: ARC%d is protecting high memory for range %#x...%#x (%d MB)", memc_id, last, addr, hMonitor->mem_high, (hMonitor->mem_high - addr)/1024/1024)); /* BMEM grows head toward high addresses, therefore  BDBG_WRN causes to much noise */
1542                        BMRC_P_Monitor_Program(hMonitor, last, addr, hMonitor->mem_high - addr, &hMonitor->clients, false);
1543                        last--;
1544                }
1545               
1546                /* use other range checkers to program all regions which are not in the map.
1547                   we actually program to protect the memory in between regions using same client
1548                   list that protects kernel memory and high memory.  */
1549                for(i=first, j=0;i<=last && j<num_regions-1;i++, j++) {
1550                        addr = combined_regions[j].addr + combined_regions[j].size;
1551                        BMRC_P_Monitor_Program(hMonitor, i, addr, combined_regions[j+1].addr - addr, &hMonitor->clients, false);
1552                }
1553
1554                hMonitor->num_combined_regions = num_regions;
1555
1556        BDBG_MSG_TRACE(("use custom ARC mapping, threshold %#x", threshold));
1557        }
1558        else
1559        {
1560            BDBG_MSG_TRACE(("use standard ARC mapping"));
1561            /* using first ARC to disable hardware access to all memory */
1562                BMRC_P_Monitor_Program(hMonitor, 0, hMonitor->mem_low, hMonitor->mem_high - hMonitor->mem_low, &hMonitor->clients, false);
1563        }
1564
1565done:
1566    return;
1567}
1568
1569BERR_Code
1570BMRC_Monitor_GetMemoryInterface(BMRC_Monitor_Handle hMonitor, BMEM_MonitorInterface *pInterface)
1571{
1572    pInterface->cnxt = hMonitor;
1573    pInterface->alloc = BMRC_P_Monitor_Alloc;
1574    pInterface->free = BMRC_P_Monitor_Free;
1575
1576    return BERR_SUCCESS;
1577}
1578
1579static void
1580BMRC_P_Monitor_isr( void *cnxt, int no, BMRC_CheckerInfo *pInfo)
1581{
1582    BMRC_Monitor_Handle hMonitor = cnxt;
1583    BERR_Code rc;
1584
1585    rc = BMRC_Checker_DisableCallback_isr(hMonitor->ahCheckers[no]);
1586    if (rc !=BERR_SUCCESS) {
1587        BDBG_ERR(("BMRC_Checker_DisableCallback_isr failed with rc %#x, ignored", (unsigned)rc));
1588    }
1589    BMRC_P_Monitor_Dump_isr(hMonitor, no, pInfo);
1590
1591    return;
1592}
1593
1594BERR_Code
1595BMRC_Monitor_JailDefault(BMRC_Monitor_Handle hMonitor)
1596{
1597    BMRC_Monitor_Clients clients;
1598
1599        BKNI_AcquireMutex(hMonitor->pMutex);
1600
1601        /* BMRC_P_Monitor_astHwClients are default allowed. inverse is default jailed. */
1602    BMRC_P_Monitor_MaskBuild(&clients, BMRC_P_Monitor_astHwClients);
1603        BMRC_P_Monitor_MasksInverse(&hMonitor->user_clients_jailed, &clients);
1604
1605        BKNI_ReleaseMutex(hMonitor->pMutex);
1606    return BERR_SUCCESS;
1607}
1608
1609BERR_Code
1610BMRC_Monitor_JailByFilename(BMRC_Monitor_Handle hMonitor, const char *filename)
1611{
1612    BMRC_Monitor_Clients clients;
1613
1614        BKNI_AcquireMutex(hMonitor->pMutex);
1615
1616    BMRC_P_Monitor_GetClientsByFname(filename, &clients);
1617    hMonitor->user_clients_jailed = clients;
1618
1619        BKNI_ReleaseMutex(hMonitor->pMutex);
1620    return BERR_SUCCESS;
1621}
1622
1623BERR_Code
1624BMRC_Monitor_JailAdd(BMRC_Monitor_Handle hMonitor, BMRC_Monitor_MemoryClientId client)
1625{
1626        BKNI_AcquireMutex(hMonitor->pMutex);
1627
1628        BMRC_P_Monitor_MaskAdd(&hMonitor->user_clients_jailed, client);
1629
1630        BKNI_ReleaseMutex(hMonitor->pMutex);
1631    return BERR_SUCCESS;
1632}
1633
1634BERR_Code
1635BMRC_Monitor_JailRemove(BMRC_Monitor_Handle hMonitor, BMRC_Monitor_MemoryClientId client)
1636{
1637        BKNI_AcquireMutex(hMonitor->pMutex);
1638
1639        BMRC_P_Monitor_MaskRemove(&hMonitor->user_clients_jailed, client);
1640
1641        BKNI_ReleaseMutex(hMonitor->pMutex);
1642    return BERR_SUCCESS;
1643}
1644
1645BERR_Code
1646BMRC_Monitor_JailUpdate(BMRC_Monitor_Handle hMonitor)
1647{
1648    unsigned i;
1649    BERR_Code rc;
1650
1651        BKNI_AcquireMutex(hMonitor->pMutex);
1652
1653        if (BMRC_P_Monitor_MasksIsClear(&hMonitor->user_clients_jailed)) {
1654        BDBG_MSG_TRACE(("all clients were removed from the jail, using standard configuration"));
1655        BMRC_P_Monitor_MaskBuild(&hMonitor->clients, BMRC_P_Monitor_astHwClients);
1656    } else {
1657                /* inverse because we want clients mask bits to be on for allowed clients to match hardware */
1658                BMRC_P_Monitor_MasksInverse(&hMonitor->clients, &hMonitor->user_clients_jailed);
1659    }
1660    BMRC_P_Monitor_Update(hMonitor, true);
1661
1662    BDBG_MSG_TRACE(("[re]enabling RMM interrupts"));
1663    for (i=0;i<hMonitor->max_ranges;i++) {
1664        rc = BMRC_Checker_EnableCallback(hMonitor->ahCheckers[i]);
1665        if (rc!=BERR_SUCCESS) {
1666                        BKNI_ReleaseMutex(hMonitor->pMutex);
1667            return rc;
1668        }
1669    }
1670
1671        BKNI_ReleaseMutex(hMonitor->pMutex);
1672    return BERR_SUCCESS;
1673}
1674
1675BERR_Code
1676BMRC_Monitor_BlockTag(BMRC_Monitor_Handle hMonitor, uint32_t ulAddr, size_t size, BMRC_Monitor_MemoryClientId client)
1677{
1678    BMRC_Monitor_Region *region;
1679
1680    BSTD_UNUSED(size);
1681
1682        BKNI_AcquireMutex(hMonitor->pMutex);
1683
1684        for(region = BLST_D_FIRST(&hMonitor->regions);region;region=BLST_D_NEXT(region, list)) {
1685        if (region->addr == ulAddr) {
1686            BMRC_P_Monitor_MaskAdd(&region->user_clients_allowed, client);
1687            region->clients = region->user_clients_allowed;
1688            BMRC_P_Monitor_Update(hMonitor, true);
1689
1690                        BKNI_ReleaseMutex(hMonitor->pMutex);
1691            return BERR_SUCCESS;
1692        }
1693    }
1694
1695        BKNI_ReleaseMutex(hMonitor->pMutex);
1696    return BERR_TRACE(BERR_INVALID_PARAMETER);
1697}
1698
1699BERR_Code
1700BMRC_Monitor_AddCustomTag(BMRC_Monitor_Handle hMonitor, uint32_t ulAddr, size_t size, BMRC_Monitor_MemoryClientId client)
1701{
1702    BMRC_Monitor_Region *region;
1703    unsigned i;
1704
1705        BKNI_AcquireMutex(hMonitor->pMutex);
1706
1707        for(i=0,region = BLST_D_FIRST(&hMonitor->custom_regions);region;region=BLST_D_NEXT(region, list),i++) {
1708        if (ulAddr == region->addr && size == region->size) {
1709            /* bingo */
1710            goto add_client;
1711        }
1712        if ( (ulAddr >= region->addr && ulAddr <= region->addr+region->size) ||
1713             (ulAddr+size >= region->addr && ulAddr+size <= region->addr+region->size)) {
1714            /* detected overlap */
1715
1716                        BKNI_ReleaseMutex(hMonitor->pMutex);
1717            return BERR_TRACE(BERR_INVALID_PARAMETER);
1718        }
1719    }
1720    if (i>=hMonitor->max_ranges) {
1721
1722                BKNI_ReleaseMutex(hMonitor->pMutex);
1723        return BERR_TRACE(BERR_NOT_SUPPORTED);
1724    }
1725    region = BKNI_Malloc(sizeof(*region));
1726    if (!region) {
1727
1728                BKNI_ReleaseMutex(hMonitor->pMutex);
1729        return BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
1730    }
1731
1732    BMRC_P_Monitor_MasksClear(&region->user_clients_allowed);
1733
1734    region->addr = ulAddr;
1735    region->size = size;
1736    BLST_D_INSERT_HEAD(&hMonitor->custom_regions, region, list);
1737add_client:
1738    BMRC_P_Monitor_MaskAdd(&region->user_clients_allowed, client);
1739        region->clients = region->user_clients_allowed;
1740
1741        BKNI_ReleaseMutex(hMonitor->pMutex);
1742    return BERR_SUCCESS;
1743}
1744
1745BERR_Code
1746BMRC_Monitor_RemoveCustomTag(BMRC_Monitor_Handle hMonitor, uint32_t ulAddr, size_t size,  BMRC_Monitor_MemoryClientId client)
1747{
1748    BMRC_Monitor_Region *region;
1749
1750        BKNI_AcquireMutex(hMonitor->pMutex);
1751
1752        for(region=BLST_D_FIRST(&hMonitor->custom_regions);region;region=BLST_D_NEXT(region, list)) {
1753        if (ulAddr == region->addr && size == region->size) {
1754            BMRC_P_Monitor_MaskRemove(&region->user_clients_allowed, client);
1755                        region->clients = region->user_clients_allowed;
1756
1757            if (BMRC_P_Monitor_MasksIsClear(&region->user_clients_allowed)) {
1758                BLST_D_REMOVE(&hMonitor->regions, region, list);
1759            }
1760
1761                        BKNI_ReleaseMutex(hMonitor->pMutex);
1762            return BERR_SUCCESS;
1763        }
1764    }
1765    /* block is nowhere to found */
1766
1767        BKNI_ReleaseMutex(hMonitor->pMutex);
1768    return BERR_TRACE(BERR_INVALID_PARAMETER);
1769}
1770
1771BERR_Code
1772BMRC_Monitor_PrintClients(BMRC_Monitor_Handle hMonitor, uint32_t clients0, uint32_t clients1, uint32_t clients2, uint32_t clients3)
1773{
1774    BMRC_Client client_id;
1775    BKNI_Printf("Clients: ");
1776    for (client_id = 0; client_id < BMRC_Client_eMaxCount; client_id++)
1777    {
1778        BMRC_ClientInfo client_info;
1779        BMRC_Checker_GetClientInfo(hMonitor->mrc, client_id, &client_info);
1780        if (client_info.usClientId != BMRC_Client_eInvalid)
1781        {
1782            bool set;
1783            if (client_info.usClientId < 32) {
1784                set = (clients0 & (1<<client_info.usClientId));
1785            }
1786            else if (client_info.usClientId < 64) {
1787                set = (clients1 & (1<<(client_info.usClientId-32)));
1788            }
1789            else if (client_info.usClientId < 96) {
1790                set = (clients2 & (1<<(client_info.usClientId-64)));
1791            }
1792            else {
1793                set = (clients3 & (1<<(client_info.usClientId-96)));
1794            }
1795            if (set) {
1796                BKNI_Printf("%s(%d) \n", client_info.pchClientName, client_info.usClientId);
1797            }
1798        }
1799    }
1800    BKNI_Printf("\n");
1801    return 0;
1802}
1803
1804BERR_Code
1805BMRC_Monitor_ValidateRegionList(BMRC_Monitor_Handle hMonitor)
1806{
1807        /* validation code */
1808        uint32_t prev_addr = 0;
1809        BMRC_Monitor_Region *cur, *prev;
1810
1811    for(cur=BLST_D_FIRST(&hMonitor->regions);cur;cur=BLST_D_NEXT(cur, list)) {
1812                if (prev_addr >= cur->addr)
1813                {
1814                        BKNI_Printf("regions out of order.  prev: 0x%x cur: 0x%x\n", prev_addr, cur->addr);
1815                }
1816
1817                prev_addr = cur->addr;
1818                prev = BMRC_P_Monitor_ListGetPrevRegionByAddr(hMonitor, cur->addr);
1819                if(prev && (prev->addr >= cur->addr))
1820                {
1821                        BKNI_Printf("prev is bad. prev: 0x%x cur: 0x%x\n", prev->addr, cur->addr);
1822                }
1823        }
1824
1825        return 0;
1826}
1827
1828BERR_Code
1829BMRC_Monitor_DumpRegionPrevByAddrTable(BMRC_Monitor_Handle hMonitor)
1830{
1831        uint32_t prev_addr = 0;
1832        int i;
1833
1834        BKNI_Printf("slot size %d\n", BMRC_P_MONITOR_REGION_PREV_SLOT_SIZE);
1835        BKNI_Printf("prev size %d\n", BMRC_P_MONITOR_REGION_PREV_SIZE);
1836
1837        for (i = 0; i < BMRC_P_MONITOR_REGION_PREV_SIZE; i++)
1838        {
1839                if (hMonitor->region_prev_by_addr[i] && (uint32_t)hMonitor->region_prev_by_addr[i] != (uint32_t)prev_addr)
1840                {
1841                        if (hMonitor->region_prev_by_addr[i])
1842                        {
1843                                BKNI_Printf("MEMC%d: slot idx: %d prev: 0x%x\n", hMonitor->mrcSettings.usMemcId, i, hMonitor->region_prev_by_addr[i]->addr);
1844                        }
1845                }
1846                prev_addr = (uint32_t)hMonitor->region_prev_by_addr[i];
1847        }
1848
1849        return 0;
1850}
1851
1852/* End of file */
Note: See TracBrowser for help on using the repository browser.