Commit | Line | Data |
---|---|---|
027f891f JH |
1 | /* |
2 | * tbistring.c | |
3 | * | |
4 | * Copyright (C) 2001, 2002, 2003, 2005, 2007, 2012 Imagination Technologies. | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify it under | |
7 | * the terms of the GNU General Public License version 2 as published by the | |
8 | * Free Software Foundation. | |
9 | * | |
10 | * String table functions provided as part of the thread binary interface for | |
11 | * Meta processors | |
12 | */ | |
13 | ||
14 | #include <linux/export.h> | |
15 | #include <linux/string.h> | |
16 | #include <asm/tbx.h> | |
17 | ||
18 | /* | |
19 | * There are not any functions to modify the string table currently, if these | |
20 | * are required at some later point I suggest having a seperate module and | |
21 | * ensuring that creating new entries does not interfere with reading old | |
22 | * entries in any way. | |
23 | */ | |
24 | ||
25 | const TBISTR *__TBIFindStr(const TBISTR *start, | |
26 | const char *str, int match_len) | |
27 | { | |
28 | const TBISTR *search = start; | |
29 | bool exact = true; | |
30 | const TBISEG *seg; | |
31 | ||
32 | if (match_len < 0) { | |
33 | /* Make match_len always positive for the inner loop */ | |
34 | match_len = -match_len; | |
35 | exact = false; | |
36 | } else { | |
37 | /* | |
38 | * Also support historic behaviour, which expected match_len to | |
39 | * include null terminator | |
40 | */ | |
41 | if (match_len && str[match_len-1] == '\0') | |
42 | match_len--; | |
43 | } | |
44 | ||
45 | if (!search) { | |
46 | /* Find global string table segment */ | |
47 | seg = __TBIFindSeg(NULL, TBID_SEG(TBID_THREAD_GLOBAL, | |
48 | TBID_SEGSCOPE_GLOBAL, | |
49 | TBID_SEGTYPE_STRING)); | |
50 | ||
51 | if (!seg || seg->Bytes < sizeof(TBISTR)) | |
52 | /* No string table! */ | |
53 | return NULL; | |
54 | ||
55 | /* Start of string table */ | |
56 | search = seg->pGAddr; | |
57 | } | |
58 | ||
59 | for (;;) { | |
60 | while (!search->Tag) | |
61 | /* Allow simple gaps which are just zero initialised */ | |
62 | search = (const TBISTR *)((const char *)search + 8); | |
63 | ||
64 | if (search->Tag == METAG_TBI_STRE) { | |
65 | /* Reached the end of the table */ | |
66 | search = NULL; | |
67 | break; | |
68 | } | |
69 | ||
70 | if ((search->Len >= match_len) && | |
71 | (!exact || (search->Len == match_len + 1)) && | |
72 | (search->Tag != METAG_TBI_STRG)) { | |
73 | /* Worth searching */ | |
74 | if (!strncmp(str, (const char *)search->String, | |
75 | match_len)) | |
76 | break; | |
77 | } | |
78 | ||
79 | /* Next entry */ | |
80 | search = (const TBISTR *)((const char *)search + search->Bytes); | |
81 | } | |
82 | ||
83 | return search; | |
84 | } | |
85 | ||
86 | const void *__TBITransStr(const char *str, int len) | |
87 | { | |
88 | const TBISTR *search = NULL; | |
89 | const void *res = NULL; | |
90 | ||
91 | for (;;) { | |
92 | /* Search onwards */ | |
93 | search = __TBIFindStr(search, str, len); | |
94 | ||
95 | /* No translation returns NULL */ | |
96 | if (!search) | |
97 | break; | |
98 | ||
99 | /* Skip matching entries with no translation data */ | |
100 | if (search->TransLen != METAG_TBI_STRX) { | |
101 | /* Calculate base of translation string */ | |
102 | res = (const char *)search->String + | |
103 | ((search->Len + 7) & ~7); | |
104 | break; | |
105 | } | |
106 | ||
107 | /* Next entry */ | |
108 | search = (const TBISTR *)((const char *)search + search->Bytes); | |
109 | } | |
110 | ||
111 | /* Return base address of translation data or NULL */ | |
112 | return res; | |
113 | } | |
114 | EXPORT_SYMBOL(__TBITransStr); |