History

Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc

Pull sparc fix from David Miller: "Build regression fix" * git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc: sparc: Fix VDSO build with older binutils.

Linus Torvalds committed 8 years ago

Commit e5f6d9a2 parents c300af2 caf539c7 files · +335 −62Browse files

Unified · Split

7 files
  1. arch/sparc/include/asm/vdso.h +0 −2
  2. arch/sparc/vdso/vclock_gettime.c +129 −20
  3. arch/sparc/vdso/vdso-layout.lds.S +0 −3
  4. arch/sparc/vdso/vdso.lds.S +2 −0
  5. arch/sparc/vdso/vdso2c.h +1 −16
  6. arch/sparc/vdso/vdso32/vdso32.lds.S +2 −0
  7. arch/sparc/vdso/vma.c +201 −21
arch/sparc/include/asm/vdso.h+0−2
@@ -9,8 +9,6 @@ struct vdso_image { · 8 unmodified lines
9 void *data;9 void *data;
10 unsigned long size; /* Always a multiple of PAGE_SIZE */10 unsigned long size; /* Always a multiple of PAGE_SIZE */
11 11
12 unsigned long tick_patch, tick_patch_len;
13
14 long sym_vvar_start; /* Negative offset to the vvar area */12 long sym_vvar_start; /* Negative offset to the vvar area */
15};13};
16 14
arch/sparc/vdso/vclock_gettime.c+129−20
@@ -90,16 +90,15 @@ notrace static __always_inline u64 vread_tick(void) · 89 unmodified lines
90{90{
91 u64 ret;91 u64 ret;
92 92
93 __asm__ __volatile__("1:\n\t"93 __asm__ __volatile__("rd %%tick, %0" : "=r" (ret));
94 "rd %%tick, %0\n\t"94 return ret;
95 ".pushsection .tick_patch, \"a\"\n\t"95}
96 ".word 1b - ., 1f - .\n\t"96
97 ".popsection\n\t"97notrace static __always_inline u64 vread_tick_stick(void)
98 ".pushsection .tick_patch_replacement, \"ax\"\n\t"98{
99 "1:\n\t"99 u64 ret;
100 "rd %%asr24, %0\n\t"100
101 ".popsection\n"101 __asm__ __volatile__("rd %%asr24, %0" : "=r" (ret));
102 : "=r" (ret));
103 return ret;102 return ret;
104}103}
105#else104#else
@@ -107,16 +106,18 @@ notrace static __always_inline u64 vread_tick(void) · 1 unmodified line
107{106{
108 register unsigned long long ret asm("o4");107 register unsigned long long ret asm("o4");
109 108
110 __asm__ __volatile__("1:\n\t"109 __asm__ __volatile__("rd %%tick, %L0\n\t"
111 "rd %%tick, %L0\n\t"110 "srlx %L0, 32, %H0"
112 "srlx %L0, 32, %H0\n\t"111 : "=r" (ret));
113 ".pushsection .tick_patch, \"a\"\n\t"112 return ret;
114 ".word 1b - ., 1f - .\n\t"113}
115 ".popsection\n\t"114
116 ".pushsection .tick_patch_replacement, \"ax\"\n\t"115notrace static __always_inline u64 vread_tick_stick(void)
117 "1:\n\t"116{
118 "rd %%asr24, %L0\n\t"117 register unsigned long long ret asm("o4");
119 ".popsection\n"118
119 __asm__ __volatile__("rd %%asr24, %L0\n\t"
120 "srlx %L0, 32, %H0"
120 : "=r" (ret));121 : "=r" (ret));
121 return ret;122 return ret;
122}123}
@@ -132,6 +133,16 @@ notrace static __always_inline u64 vgetsns(struct vvar_data *vvar) · 9 unmodified lines
132 return v * vvar->clock.mult;133 return v * vvar->clock.mult;
133}134}
134 135
136notrace static __always_inline u64 vgetsns_stick(struct vvar_data *vvar)
137{
138 u64 v;
139 u64 cycles;
140
141 cycles = vread_tick_stick();
142 v = (cycles - vvar->clock.cycle_last) & vvar->clock.mask;
143 return v * vvar->clock.mult;
144}
145
135notrace static __always_inline int do_realtime(struct vvar_data *vvar,146notrace static __always_inline int do_realtime(struct vvar_data *vvar,
136 struct timespec *ts)147 struct timespec *ts)
137{148{
@@ -152,6 +163,26 @@ notrace static __always_inline int do_realtime(struct vvar_data *vvar, · 14 unmodified lines
152 return 0;163 return 0;
153}164}
154 165
166notrace static __always_inline int do_realtime_stick(struct vvar_data *vvar,
167 struct timespec *ts)
168{
169 unsigned long seq;
170 u64 ns;
171
172 do {
173 seq = vvar_read_begin(vvar);
174 ts->tv_sec = vvar->wall_time_sec;
175 ns = vvar->wall_time_snsec;
176 ns += vgetsns_stick(vvar);
177 ns >>= vvar->clock.shift;
178 } while (unlikely(vvar_read_retry(vvar, seq)));
179
180 ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
181 ts->tv_nsec = ns;
182
183 return 0;
184}
185
155notrace static __always_inline int do_monotonic(struct vvar_data *vvar,186notrace static __always_inline int do_monotonic(struct vvar_data *vvar,
156 struct timespec *ts)187 struct timespec *ts)
157{188{
@@ -172,6 +203,26 @@ notrace static __always_inline int do_monotonic(struct vvar_data *vvar, · 14 unmodified lines
172 return 0;203 return 0;
173}204}
174 205
206notrace static __always_inline int do_monotonic_stick(struct vvar_data *vvar,
207 struct timespec *ts)
208{
209 unsigned long seq;
210 u64 ns;
211
212 do {
213 seq = vvar_read_begin(vvar);
214 ts->tv_sec = vvar->monotonic_time_sec;
215 ns = vvar->monotonic_time_snsec;
216 ns += vgetsns_stick(vvar);
217 ns >>= vvar->clock.shift;
218 } while (unlikely(vvar_read_retry(vvar, seq)));
219
220 ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
221 ts->tv_nsec = ns;
222
223 return 0;
224}
225
175notrace static int do_realtime_coarse(struct vvar_data *vvar,226notrace static int do_realtime_coarse(struct vvar_data *vvar,
176 struct timespec *ts)227 struct timespec *ts)
177{228{
@@ -227,6 +278,31 @@ int · 49 unmodified lines
227clock_gettime(clockid_t, struct timespec *)278clock_gettime(clockid_t, struct timespec *)
228 __attribute__((weak, alias("__vdso_clock_gettime")));279 __attribute__((weak, alias("__vdso_clock_gettime")));
229 280
281notrace int
282__vdso_clock_gettime_stick(clockid_t clock, struct timespec *ts)
283{
284 struct vvar_data *vvd = get_vvar_data();
285
286 switch (clock) {
287 case CLOCK_REALTIME:
288 if (unlikely(vvd->vclock_mode == VCLOCK_NONE))
289 break;
290 return do_realtime_stick(vvd, ts);
291 case CLOCK_MONOTONIC:
292 if (unlikely(vvd->vclock_mode == VCLOCK_NONE))
293 break;
294 return do_monotonic_stick(vvd, ts);
295 case CLOCK_REALTIME_COARSE:
296 return do_realtime_coarse(vvd, ts);
297 case CLOCK_MONOTONIC_COARSE:
298 return do_monotonic_coarse(vvd, ts);
299 }
300 /*
301 * Unknown clock ID ? Fall back to the syscall.
302 */
303 return vdso_fallback_gettime(clock, ts);
304}
305
230notrace int306notrace int
231__vdso_gettimeofday(struct timeval *tv, struct timezone *tz)307__vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
232{308{
@@ -262,3 +338,36 @@ __vdso_gettimeofday(struct timeval *tv, struct timezone *tz) · 29 unmodified lines
262int338int
263gettimeofday(struct timeval *, struct timezone *)339gettimeofday(struct timeval *, struct timezone *)
264 __attribute__((weak, alias("__vdso_gettimeofday")));340 __attribute__((weak, alias("__vdso_gettimeofday")));
341
342notrace int
343__vdso_gettimeofday_stick(struct timeval *tv, struct timezone *tz)
344{
345 struct vvar_data *vvd = get_vvar_data();
346
347 if (likely(vvd->vclock_mode != VCLOCK_NONE)) {
348 if (likely(tv != NULL)) {
349 union tstv_t {
350 struct timespec ts;
351 struct timeval tv;
352 } *tstv = (union tstv_t *) tv;
353 do_realtime_stick(vvd, &tstv->ts);
354 /*
355 * Assign before dividing to ensure that the division is
356 * done in the type of tv_usec, not tv_nsec.
357 *
358 * There cannot be > 1 billion usec in a second:
359 * do_realtime() has already distributed such overflow
360 * into tv_sec. So we can assign it to an int safely.
361 */
362 tstv->tv.tv_usec = tstv->ts.tv_nsec;
363 tstv->tv.tv_usec /= 1000;
364 }
365 if (unlikely(tz != NULL)) {
366 /* Avoid memcpy. Some old compilers fail to inline it */
367 tz->tz_minuteswest = vvd->tz_minuteswest;
368 tz->tz_dsttime = vvd->tz_dsttime;
369 }
370 return 0;
371 }
372 return vdso_fallback_gettimeofday(tv, tz);
373}
arch/sparc/vdso/vdso-layout.lds.S+0−3
@@ -73,9 +73,6 @@ SECTIONS · 72 unmodified lines
73 73
74 .text : { *(.text*) } :text =0x90909090,74 .text : { *(.text*) } :text =0x90909090,
75 75
76 .tick_patch : { *(.tick_patch) } :text
77 .tick_patch_insns : { *(.tick_patch_insns) } :text
78
79 /DISCARD/ : {76 /DISCARD/ : {
80 *(.discard)77 *(.discard)
81 *(.discard.*)78 *(.discard.*)
arch/sparc/vdso/vdso.lds.S+2−0
@@ -18,8 +18,10 @@ VERSION { · 17 unmodified lines
18 global:18 global:
19 clock_gettime;19 clock_gettime;
20 __vdso_clock_gettime;20 __vdso_clock_gettime;
21 __vdso_clock_gettime_stick;
21 gettimeofday;22 gettimeofday;
22 __vdso_gettimeofday;23 __vdso_gettimeofday;
24 __vdso_gettimeofday_stick;
23 local: *;25 local: *;
24 };26 };
25}27}
arch/sparc/vdso/vdso2c.h+1−16
@@ -17,11 +17,9 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len, · 16 unmodified lines
17 unsigned long mapping_size;17 unsigned long mapping_size;
18 int i;18 int i;
19 unsigned long j;19 unsigned long j;
20 ELF(Shdr) *symtab_hdr = NULL, *strtab_hdr, *secstrings_hdr,20 ELF(Shdr) *symtab_hdr = NULL, *strtab_hdr;
21 *patch_sec = NULL;
22 ELF(Ehdr) *hdr = (ELF(Ehdr) *)raw_addr;21 ELF(Ehdr) *hdr = (ELF(Ehdr) *)raw_addr;
23 ELF(Dyn) *dyn = 0, *dyn_end = 0;22 ELF(Dyn) *dyn = 0, *dyn_end = 0;
24 const char *secstrings;
25 INT_BITS syms[NSYMS] = {};23 INT_BITS syms[NSYMS] = {};
26 24
27 ELF(Phdr) *pt = (ELF(Phdr) *)(raw_addr + GET_BE(&hdr->e_phoff));25 ELF(Phdr) *pt = (ELF(Phdr) *)(raw_addr + GET_BE(&hdr->e_phoff));
@@ -64,18 +62,11 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len, · 36 unmodified lines
64 }62 }
65 63
66 /* Walk the section table */64 /* Walk the section table */
67 secstrings_hdr = raw_addr + GET_BE(&hdr->e_shoff) +
68 GET_BE(&hdr->e_shentsize)*GET_BE(&hdr->e_shstrndx);
69 secstrings = raw_addr + GET_BE(&secstrings_hdr->sh_offset);
70 for (i = 0; i < GET_BE(&hdr->e_shnum); i++) {65 for (i = 0; i < GET_BE(&hdr->e_shnum); i++) {
71 ELF(Shdr) *sh = raw_addr + GET_BE(&hdr->e_shoff) +66 ELF(Shdr) *sh = raw_addr + GET_BE(&hdr->e_shoff) +
72 GET_BE(&hdr->e_shentsize) * i;67 GET_BE(&hdr->e_shentsize) * i;
73 if (GET_BE(&sh->sh_type) == SHT_SYMTAB)68 if (GET_BE(&sh->sh_type) == SHT_SYMTAB)
74 symtab_hdr = sh;69 symtab_hdr = sh;
75
76 if (!strcmp(secstrings + GET_BE(&sh->sh_name),
77 ".tick_patch"))
78 patch_sec = sh;
79 }70 }
80 71
81 if (!symtab_hdr)72 if (!symtab_hdr)
@@ -142,12 +133,6 @@ static void BITSFUNC(go)(void *raw_addr, size_t raw_len, · 60 unmodified lines
142 fprintf(outfile, "const struct vdso_image %s_builtin = {\n", name);133 fprintf(outfile, "const struct vdso_image %s_builtin = {\n", name);
143 fprintf(outfile, "\t.data = raw_data,\n");134 fprintf(outfile, "\t.data = raw_data,\n");
144 fprintf(outfile, "\t.size = %lu,\n", mapping_size);135 fprintf(outfile, "\t.size = %lu,\n", mapping_size);
145 if (patch_sec) {
146 fprintf(outfile, "\t.tick_patch = %lu,\n",
147 (unsigned long)GET_BE(&patch_sec->sh_offset));
148 fprintf(outfile, "\t.tick_patch_len = %lu,\n",
149 (unsigned long)GET_BE(&patch_sec->sh_size));
150 }
151 for (i = 0; i < NSYMS; i++) {136 for (i = 0; i < NSYMS; i++) {
152 if (required_syms[i].export && syms[i])137 if (required_syms[i].export && syms[i])
153 fprintf(outfile, "\t.sym_%s = %" PRIi64 ",\n",138 fprintf(outfile, "\t.sym_%s = %" PRIi64 ",\n",
arch/sparc/vdso/vdso32/vdso32.lds.S+2−0
@@ -17,8 +17,10 @@ VERSION { · 16 unmodified lines
17 global:17 global:
18 clock_gettime;18 clock_gettime;
19 __vdso_clock_gettime;19 __vdso_clock_gettime;
20 __vdso_clock_gettime_stick;
20 gettimeofday;21 gettimeofday;
21 __vdso_gettimeofday;22 __vdso_gettimeofday;
23 __vdso_gettimeofday_stick;
22 local: *;24 local: *;
23 };25 };
24}26}
arch/sparc/vdso/vma.c+201−21
@@ -42,24 +42,201 @@ static struct vm_special_mapping vdso_mapping32 = { · 41 unmodified lines
42 42
43struct vvar_data *vvar_data;43struct vvar_data *vvar_data;
44 44
45struct tick_patch_entry {45struct vdso_elfinfo32 {
46 s32 orig, repl;46 Elf32_Ehdr *hdr;
47 Elf32_Sym *dynsym;
48 unsigned long dynsymsize;
49 const char *dynstr;
50 unsigned long text;
47};51};
48 52
49static void stick_patch(const struct vdso_image *image)53struct vdso_elfinfo64 {
54 Elf64_Ehdr *hdr;
55 Elf64_Sym *dynsym;
56 unsigned long dynsymsize;
57 const char *dynstr;
58 unsigned long text;
59};
60
61struct vdso_elfinfo {
62 union {
63 struct vdso_elfinfo32 elf32;
64 struct vdso_elfinfo64 elf64;
65 } u;
66};
67
68static void *one_section64(struct vdso_elfinfo64 *e, const char *name,
69 unsigned long *size)
70{
71 const char *snames;
72 Elf64_Shdr *shdrs;
73 unsigned int i;
74
75 shdrs = (void *)e->hdr + e->hdr->e_shoff;
76 snames = (void *)e->hdr + shdrs[e->hdr->e_shstrndx].sh_offset;
77 for (i = 1; i < e->hdr->e_shnum; i++) {
78 if (!strcmp(snames+shdrs[i].sh_name, name)) {
79 if (size)
80 *size = shdrs[i].sh_size;
81 return (void *)e->hdr + shdrs[i].sh_offset;
82 }
83 }
84 return NULL;
85}
86
87static int find_sections64(const struct vdso_image *image, struct vdso_elfinfo *_e)
88{
89 struct vdso_elfinfo64 *e = &_e->u.elf64;
90
91 e->hdr = image->data;
92 e->dynsym = one_section64(e, ".dynsym", &e->dynsymsize);
93 e->dynstr = one_section64(e, ".dynstr", NULL);
94
95 if (!e->dynsym || !e->dynstr) {
96 pr_err("VDSO64: Missing symbol sections.\n");
97 return -ENODEV;
98 }
99 return 0;
100}
101
102static Elf64_Sym *find_sym64(const struct vdso_elfinfo64 *e, const char *name)
103{
104 unsigned int i;
105
106 for (i = 0; i < (e->dynsymsize / sizeof(Elf64_Sym)); i++) {
107 Elf64_Sym *s = &e->dynsym[i];
108 if (s->st_name == 0)
109 continue;
110 if (!strcmp(e->dynstr + s->st_name, name))
111 return s;
112 }
113 return NULL;
114}
115
116static int patchsym64(struct vdso_elfinfo *_e, const char *orig,
117 const char *new)
118{
119 struct vdso_elfinfo64 *e = &_e->u.elf64;
120 Elf64_Sym *osym = find_sym64(e, orig);
121 Elf64_Sym *nsym = find_sym64(e, new);
122
123 if (!nsym || !osym) {
124 pr_err("VDSO64: Missing symbols.\n");
125 return -ENODEV;
126 }
127 osym->st_value = nsym->st_value;
128 osym->st_size = nsym->st_size;
129 osym->st_info = nsym->st_info;
130 osym->st_other = nsym->st_other;
131 osym->st_shndx = nsym->st_shndx;
132
133 return 0;
134}
135
136static void *one_section32(struct vdso_elfinfo32 *e, const char *name,
137 unsigned long *size)
138{
139 const char *snames;
140 Elf32_Shdr *shdrs;
141 unsigned int i;
142
143 shdrs = (void *)e->hdr + e->hdr->e_shoff;
144 snames = (void *)e->hdr + shdrs[e->hdr->e_shstrndx].sh_offset;
145 for (i = 1; i < e->hdr->e_shnum; i++) {
146 if (!strcmp(snames+shdrs[i].sh_name, name)) {
147 if (size)
148 *size = shdrs[i].sh_size;
149 return (void *)e->hdr + shdrs[i].sh_offset;
150 }
151 }
152 return NULL;
153}
154
155static int find_sections32(const struct vdso_image *image, struct vdso_elfinfo *_e)
156{
157 struct vdso_elfinfo32 *e = &_e->u.elf32;
158
159 e->hdr = image->data;
160 e->dynsym = one_section32(e, ".dynsym", &e->dynsymsize);
161 e->dynstr = one_section32(e, ".dynstr", NULL);
162
163 if (!e->dynsym || !e->dynstr) {
164 pr_err("VDSO32: Missing symbol sections.\n");
165 return -ENODEV;
166 }
167 return 0;
168}
169
170static Elf32_Sym *find_sym32(const struct vdso_elfinfo32 *e, const char *name)
50{171{
51 struct tick_patch_entry *p, *p_end;172 unsigned int i;
173
174 for (i = 0; i < (e->dynsymsize / sizeof(Elf32_Sym)); i++) {
175 Elf32_Sym *s = &e->dynsym[i];
176 if (s->st_name == 0)
177 continue;
178 if (!strcmp(e->dynstr + s->st_name, name))
179 return s;
180 }
181 return NULL;
182}
52 183
53 p = image->data + image->tick_patch;184static int patchsym32(struct vdso_elfinfo *_e, const char *orig,
54 p_end = (void *)p + image->tick_patch_len;185 const char *new)
55 while (p < p_end) {186{
56 u32 *instr = (void *)&p->orig + p->orig;187 struct vdso_elfinfo32 *e = &_e->u.elf32;
57 u32 *repl = (void *)&p->repl + p->repl;188 Elf32_Sym *osym = find_sym32(e, orig);
189 Elf32_Sym *nsym = find_sym32(e, new);
58 190
59 *instr = *repl;191 if (!nsym || !osym) {
60 flushi(instr);192 pr_err("VDSO32: Missing symbols.\n");
61 p++;193 return -ENODEV;
62 }194 }
195 osym->st_value = nsym->st_value;
196 osym->st_size = nsym->st_size;
197 osym->st_info = nsym->st_info;
198 osym->st_other = nsym->st_other;
199 osym->st_shndx = nsym->st_shndx;
200
201 return 0;
202}
203
204static int find_sections(const struct vdso_image *image, struct vdso_elfinfo *e,
205 bool elf64)
206{
207 if (elf64)
208 return find_sections64(image, e);
209 else
210 return find_sections32(image, e);
211}
212
213static int patch_one_symbol(struct vdso_elfinfo *e, const char *orig,
214 const char *new_target, bool elf64)
215{
216 if (elf64)
217 return patchsym64(e, orig, new_target);
218 else
219 return patchsym32(e, orig, new_target);
220}
221
222static int stick_patch(const struct vdso_image *image, struct vdso_elfinfo *e, bool elf64)
223{
224 int err;
225
226 err = find_sections(image, e, elf64);
227 if (err)
228 return err;
229
230 err = patch_one_symbol(e,
231 "__vdso_gettimeofday",
232 "__vdso_gettimeofday_stick", elf64);
233 if (err)
234 return err;
235
236 return patch_one_symbol(e,
237 "__vdso_clock_gettime",
238 "__vdso_clock_gettime_stick", elf64);
239 return 0;
63}240}
64 241
65/*242/*
@@ -67,13 +244,19 @@ static void stick_patch(const struct vdso_image *image) · 1 unmodified line
67 * kernel image.244 * kernel image.
68 */245 */
69int __init init_vdso_image(const struct vdso_image *image,246int __init init_vdso_image(const struct vdso_image *image,
70 struct vm_special_mapping *vdso_mapping)247 struct vm_special_mapping *vdso_mapping, bool elf64)
71{248{
72 int i;249 int cnpages = (image->size) / PAGE_SIZE;
73 struct page *dp, **dpp = NULL;250 struct page *dp, **dpp = NULL;
74 int dnpages = 0;
75 struct page *cp, **cpp = NULL;251 struct page *cp, **cpp = NULL;
76 int cnpages = (image->size) / PAGE_SIZE;252 struct vdso_elfinfo ei;
253 int i, dnpages = 0;
254
255 if (tlb_type != spitfire) {
256 int err = stick_patch(image, &ei, elf64);
257 if (err)
258 return err;
259 }
77 260
78 /*261 /*
79 * First, the vdso text. This is initialied data, an integral number of262 * First, the vdso text. This is initialied data, an integral number of
@@ -88,9 +271,6 @@ int __init init_vdso_image(const struct vdso_image *image, · 8 unmodified lines
88 if (!cpp)271 if (!cpp)
89 goto oom;272 goto oom;
90 273
91 if (tlb_type != spitfire)
92 stick_patch(image);
93
94 for (i = 0; i < cnpages; i++) {274 for (i = 0; i < cnpages; i++) {
95 cp = alloc_page(GFP_KERNEL);275 cp = alloc_page(GFP_KERNEL);
96 if (!cp)276 if (!cp)
@@ -153,13 +333,13 @@ static int __init init_vdso(void) · 56 unmodified lines
153{333{
154 int err = 0;334 int err = 0;
155#ifdef CONFIG_SPARC64335#ifdef CONFIG_SPARC64
156 err = init_vdso_image(&vdso_image_64_builtin, &vdso_mapping64);336 err = init_vdso_image(&vdso_image_64_builtin, &vdso_mapping64, true);
157 if (err)337 if (err)
158 return err;338 return err;
159#endif339#endif
160 340
161#ifdef CONFIG_COMPAT341#ifdef CONFIG_COMPAT
162 err = init_vdso_image(&vdso_image_32_builtin, &vdso_mapping32);342 err = init_vdso_image(&vdso_image_32_builtin, &vdso_mapping32, false);
163#endif343#endif
164 return err;344 return err;
165 345

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t