mksys.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. package main
  10. import (
  11. "encoding/json"
  12. "flag"
  13. "fmt"
  14. "io/ioutil"
  15. "log"
  16. "os"
  17. "path"
  18. "strings"
  19. "text/template"
  20. )
  21. type Syscall struct {
  22. Ret []string
  23. Args []string
  24. Name string
  25. Id uint32
  26. Define string
  27. Sysname string
  28. Libname string
  29. Fudge string `json:"-"`
  30. GoArgs []string `json:"-"`
  31. Ret0 string `json:"-"`
  32. }
  33. type Syserror struct {
  34. Name string
  35. String string
  36. Id uint32
  37. }
  38. type Bootmethods struct {
  39. Name string
  40. Config string
  41. Connect string
  42. Arg string
  43. }
  44. type Sysconf struct {
  45. Syscalls []Syscall
  46. Syserrors []Syserror
  47. Bootmethods []Bootmethods
  48. }
  49. var mode = flag.String("mode", "", "must be one of: sys.h, sysdecl.h, syscallfiles, systab.c, error.h, errstr.h, sys_harvey.s, sysnum.go")
  50. var outpath = flag.String("o", "", "path/to/output.c")
  51. func usage(msg string) {
  52. fmt.Fprintf(os.Stderr, "mksys: invoked via %v\n", os.Args)
  53. fmt.Fprintln(os.Stderr, msg)
  54. fmt.Fprint(os.Stderr, "Usage: mksys [-o outpath] -mode=MODE path/to/sysconf.json\n")
  55. flag.PrintDefaults()
  56. os.Exit(1)
  57. }
  58. func main() {
  59. flag.Parse()
  60. if flag.NArg() != 1 {
  61. usage("no path to sysconf.json")
  62. }
  63. outfile := os.Stdout
  64. if *mode != "syscallfiles" && *outpath != "" {
  65. of, err := os.Create(*outpath)
  66. if err != nil {
  67. log.Fatal(err)
  68. }
  69. outfile = of
  70. }
  71. buf, err := ioutil.ReadFile(flag.Arg(0))
  72. if err != nil {
  73. log.Fatal(err)
  74. }
  75. var sysconf Sysconf
  76. err = json.Unmarshal(buf, &sysconf)
  77. if err != nil {
  78. log.Fatal(err)
  79. }
  80. syscalls := sysconf.Syscalls
  81. syserrors := sysconf.Syserrors
  82. bootmethods := sysconf.Bootmethods
  83. for i := range syscalls {
  84. if syscalls[i].Define == "" {
  85. syscalls[i].Define = strings.ToUpper(syscalls[i].Name)
  86. }
  87. if syscalls[i].Sysname == "" {
  88. syscalls[i].Sysname = "sys" + syscalls[i].Name
  89. }
  90. if syscalls[i].Libname == "" {
  91. syscalls[i].Libname = syscalls[i].Name
  92. }
  93. }
  94. switch *mode {
  95. case "sys_harvey.s":
  96. a := os.Getenv("ARCH")
  97. switch a {
  98. case "aarch64":
  99. usage("aarch64 support is incomplete")
  100. case "amd64":
  101. case "riscv":
  102. usage("riscv support is incomplete")
  103. default:
  104. usage(a + " is not supported.")
  105. }
  106. syscallargs := []string{"DI", "SI", "DX", "R10", "R8", "R9"}
  107. //funcallregs := []string{ "DI", "SI", "DX", "CX", "R8", "R9" };
  108. for i := range syscalls {
  109. goargs := []string{}
  110. fpoff := 0
  111. for k := range syscalls[i].Args {
  112. switch syscalls[i].Args[k] {
  113. case "int32_t", "uint32_t":
  114. goargs = append(goargs, fmt.Sprintf("MOVL arg%d+%d(FP), %s", k, fpoff, syscallargs[k]))
  115. fpoff += 4
  116. case "void*", "char*", "char**", "uint8_t*", "int32_t*", "uint64_t*", "int64_t*", "int64_t":
  117. fpoff = (fpoff + 7) & ^7
  118. goargs = append(goargs, fmt.Sprintf("MOVQ arg%d+%d(FP), %s", k, fpoff, syscallargs[k]))
  119. fpoff += 8
  120. default:
  121. log.Fatalf("unsupported arg %s in syscall: %v", syscalls[i].Args[k], syscalls[i])
  122. }
  123. }
  124. syscalls[i].GoArgs = goargs
  125. switch syscalls[i].Ret[0] {
  126. case "int32_t", "uint32_t":
  127. syscalls[i].Ret0 = fmt.Sprintf("MOVL AX, ret+%d(FP)", fpoff)
  128. fpoff += 4
  129. case "void*", "char*", "char**", "uint8_t*", "int32_t*", "uint64_t*", "int64_t*", "int64_t":
  130. fpoff = (fpoff + 7) & ^7
  131. syscalls[i].Ret0 = fmt.Sprintf("MOVQ AX, ret+%d(FP)", fpoff)
  132. fpoff += 8
  133. default:
  134. log.Fatalf("unsupported Ret[0] in syscall: %v", syscalls[i])
  135. }
  136. }
  137. tmpl, err := template.New("sys_harvey.s").Parse(`/* automatically generated by mksys */
  138. /* System calls for AMD64, Harvey */
  139. #include "go_asm.h"
  140. #include "go_tls.h"
  141. #include "textflag.h"
  142. {{ range . }}
  143. TEXT runtime·{{ .Libname }}(SB),NOSPLIT,$0
  144. {{ range .GoArgs }} {{ . }}
  145. {{ end }} MOVQ ${{ .Id }}, AX
  146. SYSCALL
  147. {{ .Ret0 }}
  148. RET
  149. {{ end }}
  150. `)
  151. if err != nil {
  152. log.Fatal(err)
  153. }
  154. err = tmpl.Execute(outfile, syscalls)
  155. if err != nil {
  156. log.Fatal(err)
  157. }
  158. case "syscallfiles":
  159. var tmpl *template.Template
  160. var err error
  161. a := os.Getenv("ARCH")
  162. switch a {
  163. case "aarch64":
  164. tmpl, err = template.New("syscall.s").Parse(`/* automatically generated by mksys */
  165. .globl {{ .Libname }}
  166. {{ .Libname }}:
  167. mov x8, #{{ .Id }}
  168. svc #0
  169. ret
  170. `)
  171. case "amd64":
  172. tmpl, err = template.New("syscall.s").Parse(`/* automatically generated by mksys */
  173. .globl {{ .Libname }}
  174. {{ .Libname }}:
  175. movq %rcx, %r10 /* rcx gets smashed by systenter. Use r10.*/
  176. movq ${{ .Id }},%rax /* Put the system call into rax, just like linux. */
  177. syscall
  178. ret
  179. `)
  180. if err != nil {
  181. log.Fatal(err)
  182. }
  183. case "riscv":
  184. tmpl, err = template.New("syscall.s").Parse(`/* automatically generated by mksys */
  185. .globl {{ .Libname }}
  186. {{ .Libname }}:
  187. li a7, {{ .Id }} /* Put the system call into a7 so we don't have to move a0-a6 around*/
  188. scall
  189. ret
  190. `)
  191. if err != nil {
  192. log.Fatal(err)
  193. }
  194. default:
  195. usage(a + " is not supported for system call generation.")
  196. }
  197. for i := range syscalls {
  198. path := path.Join(*outpath, syscalls[i].Libname+".s")
  199. file, err := os.Create(path)
  200. if err != nil {
  201. log.Fatal(err)
  202. }
  203. err = tmpl.Execute(file, syscalls[i])
  204. if err != nil {
  205. log.Fatal(err)
  206. }
  207. err = file.Close()
  208. if err != nil {
  209. log.Fatal(err)
  210. }
  211. }
  212. case "sysnum.go":
  213. tmpl, err := template.New("sysnum.go").Parse(`// automatically generated by mksys
  214. package syscall
  215. const(
  216. {{ range . }} SYS_{{ .Define }} = {{ .Id }}
  217. {{ end }}
  218. )
  219. `)
  220. err = tmpl.Execute(outfile, syscalls)
  221. if err != nil {
  222. log.Fatal(err)
  223. }
  224. case "sys.h":
  225. tmpl, err := template.New("sys.h").Parse(`/* automatically generated by mksys */
  226. {{ range . }}#define {{ .Define }} {{ .Id }}
  227. {{ end }}
  228. `)
  229. err = tmpl.Execute(outfile, syscalls)
  230. if err != nil {
  231. log.Fatal(err)
  232. }
  233. case "sysdecl.h":
  234. tmpl, err := template.New("sysdecl.h").Parse(`/* automatically generated by mksys */
  235. {{ range . }}extern {{ .Ret0 }} {{ .Libname }}({{ range $i, $e := .Args }}{{ if $i }}, {{ end }}{{ $e }}{{ end }});
  236. {{ end }}
  237. `)
  238. err = tmpl.Execute(outfile, syscalls)
  239. if err != nil {
  240. log.Fatal(err)
  241. }
  242. case "systab.c":
  243. for i := range syscalls {
  244. var fudge string
  245. switch syscalls[i].Ret[0] {
  246. case "int32_t":
  247. fudge = "{ .i = -1 }"
  248. case "int64_t":
  249. fudge = "{ .vl = -1ll }"
  250. case "void*", "char*":
  251. fudge = "{ .v = (void*)-1ll }"
  252. default:
  253. log.Fatalf("unsupported Ret[0] in syscall: %v", syscalls[i])
  254. }
  255. if syscalls[i].Fudge == "" {
  256. syscalls[i].Fudge = fudge
  257. }
  258. syscalls[i].Ret0 = syscalls[i].Ret[0]
  259. }
  260. tmpl, err := template.New("systab.c").Parse(`/* automatically generated by mksys */
  261. #include "u.h"
  262. #include "../port/lib.h"
  263. #include "mem.h"
  264. #include "dat.h"
  265. #include "fns.h"
  266. #include "../../libc/9syscall/sys.h"
  267. {{ range . }}extern void {{ .Sysname }}(Ar0*, ...);
  268. {{ end }}
  269. Systab systab[] = {
  270. {{ range . }}[{{ .Define }}] = { "{{ .Name }}", {{ .Sysname }}, {{ .Fudge }} },
  271. {{ end }}
  272. };
  273. int nsyscall = nelem(systab);
  274. `)
  275. err = tmpl.Execute(outfile, syscalls)
  276. if err != nil {
  277. log.Fatal(err)
  278. }
  279. case "error.h":
  280. tmpl, err := template.New("error.h").Parse(`/* automatically generated by mksys */
  281. {{ range . }}extern char {{ .Name }}[]; /* {{ .String }} */
  282. {{ end }}
  283. `)
  284. err = tmpl.Execute(outfile, syserrors)
  285. if err != nil {
  286. log.Fatal(err)
  287. }
  288. case "errstr.h":
  289. tmpl, err := template.New("errstr.h").Parse(`/* automatically generated by mksys */
  290. {{ range . }}char {{ .Name }}[] = "{{ .String }}";
  291. {{ end }}
  292. `)
  293. err = tmpl.Execute(outfile, syserrors)
  294. if err != nil {
  295. log.Fatal(err)
  296. }
  297. case "bootcpu.c":
  298. tmpl, err := template.New("bootcpu.c").Parse(`/* automatically generated by mksys */
  299. #include <u.h>
  300. #include <libc.h>
  301. #include "../boot/boot.h"
  302. Method method[] = {
  303. {{ range . }}{ "{{.Name}}", {{.Config}}, {{.Connect}}, "{{.Arg}}", },
  304. {{ end }}
  305. { nil },
  306. };
  307. int cpuflag = 1;
  308. char* rootdir = "/root";
  309. char* bootdisk = "#S/sdE0/";
  310. extern void boot(int, char**);
  311. void
  312. main(int argc, char **argv)
  313. {
  314. boot(argc, argv);
  315. }
  316. int (*cfs)(int) = 0;
  317. `)
  318. err = tmpl.Execute(outfile, bootmethods)
  319. if err != nil {
  320. log.Fatal(err)
  321. }
  322. }
  323. }