diff --git Makefile.cross Makefile.cross index 1cafb20ff3e..2b23627b952 100644 --- Makefile.cross +++ Makefile.cross @@ -25,7 +25,7 @@ TARGET_CPU?= ${TARGET_ARCH} # List of LP64 archs # XXX move to bsd.*.mk? -LP64_ARCH = aarch64 amd64 alpha mips64 riscv64 sparc64 powerpc64 +LP64_ARCH = aarch64 amd64 alpha mips64 riscv64 sparc64 powerpc64 loongarch64 TARGET_IS_LP64 = MACHINE_IS_LP64 = @@ -92,6 +92,8 @@ CXX=clang++ .if !empty(LLD_ARCH:M${_arch}) LINKER_VERSION=lld .else +echo "BFD!!!!" +sleep 100000 LINKER_VERSION=bfd .endif diff --git distrib/sets/lists/base/md.loongarch64 distrib/sets/lists/base/md.loongarch64 new file mode 100644 index 00000000000..e74e1bff83d --- /dev/null +++ distrib/sets/lists/base/md.loongarch64 @@ -0,0 +1,430 @@ +./etc/examples/wsconsctl.conf +./sbin/kbd +./sbin/wsconsctl +./usr/bin/clang +./usr/bin/clang++ +./usr/bin/clang-cpp +./usr/bin/ld.lld +./usr/lib/libLLVM.so.10.0 +./usr/lib/libc++.so.13.0 +./usr/lib/libc++abi.so.10.0 +./usr/lib/libcompiler_rt.a +./usr/libdata/perl5/loongarch64-openbsd +./usr/libdata/perl5/loongarch64-openbsd/.packlist +./usr/libdata/perl5/loongarch64-openbsd/B +./usr/libdata/perl5/loongarch64-openbsd/B.pm +./usr/libdata/perl5/loongarch64-openbsd/B/Concise.pm +./usr/libdata/perl5/loongarch64-openbsd/B/Showlex.pm +./usr/libdata/perl5/loongarch64-openbsd/B/Terse.pm +./usr/libdata/perl5/loongarch64-openbsd/B/Xref.pm +./usr/libdata/perl5/loongarch64-openbsd/CORE +./usr/libdata/perl5/loongarch64-openbsd/CORE/EXTERN.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/INTERN.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/XSUB.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/av.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/bitcount.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/charclass_invlists.inc +./usr/libdata/perl5/loongarch64-openbsd/CORE/config.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/cop.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/cv.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/dosish.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/ebcdic_tables.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/embed.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/embedvar.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/fakesdio.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/feature.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/form.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/git_version.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/gv.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/handy.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/hv.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/hv_func.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/hv_macro.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/inline.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/intrpvar.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/invlist_inline.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/iperlsys.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/keywords.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/l1_char_class_tab.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/locale_table.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/malloc_ctl.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/metaconfig.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/mg.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/mg_data.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/mg_names.inc +./usr/libdata/perl5/loongarch64-openbsd/CORE/mg_raw.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/mg_vtable.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/mydtrace.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/nostdio.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/op.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/op_reg_common.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/opcode.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/opnames.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/overload.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/overload.inc +./usr/libdata/perl5/loongarch64-openbsd/CORE/packsizetables.inc +./usr/libdata/perl5/loongarch64-openbsd/CORE/pad.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/parser.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/patchlevel.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/perl.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/perl_inc_macro.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/perl_langinfo.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/perl_siphash.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/perlapi.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/perlio.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/perliol.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/perlsdio.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/perlstatic.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/perlvars.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/perly.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/pp.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/pp_proto.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/proto.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/reentr.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/regcharclass.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/regcomp.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/regcomp_internal.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/regexp.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/regexp_constants.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/reginline.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/regnodes.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/sbox32_hash.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/scope.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/scope_types.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/sv.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/sv_inline.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/syscall_emulator.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/thread.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/time64.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/time64_config.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/uni_keywords.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/unicode_constants.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/unixish.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/utf8.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/utfebcdic.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/util.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/uudmap.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/vutil.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/vxs.inc +./usr/libdata/perl5/loongarch64-openbsd/CORE/warnings.h +./usr/libdata/perl5/loongarch64-openbsd/CORE/zaphod32_hash.h +./usr/libdata/perl5/loongarch64-openbsd/Compress +./usr/libdata/perl5/loongarch64-openbsd/Compress/Raw +./usr/libdata/perl5/loongarch64-openbsd/Compress/Raw/Bzip2.pm +./usr/libdata/perl5/loongarch64-openbsd/Compress/Raw/Zlib.pm +./usr/libdata/perl5/loongarch64-openbsd/Compress/Zlib.pm +./usr/libdata/perl5/loongarch64-openbsd/Config.pm +./usr/libdata/perl5/loongarch64-openbsd/Config.pod +./usr/libdata/perl5/loongarch64-openbsd/Config_git.pl +./usr/libdata/perl5/loongarch64-openbsd/Config_heavy.pl +./usr/libdata/perl5/loongarch64-openbsd/Cwd.pm +./usr/libdata/perl5/loongarch64-openbsd/DB_File.pm +./usr/libdata/perl5/loongarch64-openbsd/Data +./usr/libdata/perl5/loongarch64-openbsd/Data/Dumper.pm +./usr/libdata/perl5/loongarch64-openbsd/Devel +./usr/libdata/perl5/loongarch64-openbsd/Devel/PPPort.pm +./usr/libdata/perl5/loongarch64-openbsd/Devel/Peek.pm +./usr/libdata/perl5/loongarch64-openbsd/Digest +./usr/libdata/perl5/loongarch64-openbsd/Digest/MD5.pm +./usr/libdata/perl5/loongarch64-openbsd/Digest/SHA.pm +./usr/libdata/perl5/loongarch64-openbsd/DynaLoader.pm +./usr/libdata/perl5/loongarch64-openbsd/Encode +./usr/libdata/perl5/loongarch64-openbsd/Encode.pm +./usr/libdata/perl5/loongarch64-openbsd/Encode/Alias.pm +./usr/libdata/perl5/loongarch64-openbsd/Encode/Byte.pm +./usr/libdata/perl5/loongarch64-openbsd/Encode/CJKConstants.pm +./usr/libdata/perl5/loongarch64-openbsd/Encode/CN +./usr/libdata/perl5/loongarch64-openbsd/Encode/CN.pm +./usr/libdata/perl5/loongarch64-openbsd/Encode/CN/HZ.pm +./usr/libdata/perl5/loongarch64-openbsd/Encode/Config.pm +./usr/libdata/perl5/loongarch64-openbsd/Encode/EBCDIC.pm +./usr/libdata/perl5/loongarch64-openbsd/Encode/Encoder.pm +./usr/libdata/perl5/loongarch64-openbsd/Encode/Encoding.pm +./usr/libdata/perl5/loongarch64-openbsd/Encode/GSM0338.pm +./usr/libdata/perl5/loongarch64-openbsd/Encode/Guess.pm +./usr/libdata/perl5/loongarch64-openbsd/Encode/JP +./usr/libdata/perl5/loongarch64-openbsd/Encode/JP.pm +./usr/libdata/perl5/loongarch64-openbsd/Encode/JP/H2Z.pm +./usr/libdata/perl5/loongarch64-openbsd/Encode/JP/JIS7.pm +./usr/libdata/perl5/loongarch64-openbsd/Encode/KR +./usr/libdata/perl5/loongarch64-openbsd/Encode/KR.pm +./usr/libdata/perl5/loongarch64-openbsd/Encode/KR/2022_KR.pm +./usr/libdata/perl5/loongarch64-openbsd/Encode/MIME +./usr/libdata/perl5/loongarch64-openbsd/Encode/MIME/Header +./usr/libdata/perl5/loongarch64-openbsd/Encode/MIME/Header.pm +./usr/libdata/perl5/loongarch64-openbsd/Encode/MIME/Header/ISO_2022_JP.pm +./usr/libdata/perl5/loongarch64-openbsd/Encode/MIME/Name.pm +./usr/libdata/perl5/loongarch64-openbsd/Encode/Symbol.pm +./usr/libdata/perl5/loongarch64-openbsd/Encode/TW.pm +./usr/libdata/perl5/loongarch64-openbsd/Encode/Unicode +./usr/libdata/perl5/loongarch64-openbsd/Encode/Unicode.pm +./usr/libdata/perl5/loongarch64-openbsd/Encode/Unicode/UTF7.pm +./usr/libdata/perl5/loongarch64-openbsd/Errno.pm +./usr/libdata/perl5/loongarch64-openbsd/Fcntl.pm +./usr/libdata/perl5/loongarch64-openbsd/File +./usr/libdata/perl5/loongarch64-openbsd/File/DosGlob.pm +./usr/libdata/perl5/loongarch64-openbsd/File/Glob.pm +./usr/libdata/perl5/loongarch64-openbsd/File/GlobMapper.pm +./usr/libdata/perl5/loongarch64-openbsd/File/Spec +./usr/libdata/perl5/loongarch64-openbsd/File/Spec.pm +./usr/libdata/perl5/loongarch64-openbsd/File/Spec/AmigaOS.pm +./usr/libdata/perl5/loongarch64-openbsd/File/Spec/Cygwin.pm +./usr/libdata/perl5/loongarch64-openbsd/File/Spec/Epoc.pm +./usr/libdata/perl5/loongarch64-openbsd/File/Spec/Functions.pm +./usr/libdata/perl5/loongarch64-openbsd/File/Spec/Mac.pm +./usr/libdata/perl5/loongarch64-openbsd/File/Spec/OS2.pm +./usr/libdata/perl5/loongarch64-openbsd/File/Spec/Unix.pm +./usr/libdata/perl5/loongarch64-openbsd/File/Spec/VMS.pm +./usr/libdata/perl5/loongarch64-openbsd/File/Spec/Win32.pm +./usr/libdata/perl5/loongarch64-openbsd/Filter +./usr/libdata/perl5/loongarch64-openbsd/Filter/Util +./usr/libdata/perl5/loongarch64-openbsd/Filter/Util/Call.pm +./usr/libdata/perl5/loongarch64-openbsd/Hash +./usr/libdata/perl5/loongarch64-openbsd/Hash/Util +./usr/libdata/perl5/loongarch64-openbsd/Hash/Util.pm +./usr/libdata/perl5/loongarch64-openbsd/Hash/Util/FieldHash.pm +./usr/libdata/perl5/loongarch64-openbsd/I18N +./usr/libdata/perl5/loongarch64-openbsd/I18N/Langinfo.pm +./usr/libdata/perl5/loongarch64-openbsd/IO +./usr/libdata/perl5/loongarch64-openbsd/IO.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Compress +./usr/libdata/perl5/loongarch64-openbsd/IO/Compress.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Compress/Adapter +./usr/libdata/perl5/loongarch64-openbsd/IO/Compress/Adapter/Bzip2.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Compress/Adapter/Deflate.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Compress/Adapter/Identity.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Compress/Base +./usr/libdata/perl5/loongarch64-openbsd/IO/Compress/Base.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Compress/Base/Common.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Compress/Bzip2.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Compress/Deflate.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Compress/Gzip +./usr/libdata/perl5/loongarch64-openbsd/IO/Compress/Gzip.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Compress/Gzip/Constants.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Compress/RawDeflate.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Compress/Zip +./usr/libdata/perl5/loongarch64-openbsd/IO/Compress/Zip.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Compress/Zip/Constants.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Compress/Zlib +./usr/libdata/perl5/loongarch64-openbsd/IO/Compress/Zlib/Constants.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Compress/Zlib/Extra.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Dir.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/File.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Handle.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Pipe.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Poll.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Seekable.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Select.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Socket +./usr/libdata/perl5/loongarch64-openbsd/IO/Socket.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Socket/INET.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Socket/UNIX.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Uncompress +./usr/libdata/perl5/loongarch64-openbsd/IO/Uncompress/Adapter +./usr/libdata/perl5/loongarch64-openbsd/IO/Uncompress/Adapter/Bunzip2.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Uncompress/Adapter/Identity.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Uncompress/Adapter/Inflate.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Uncompress/AnyInflate.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Uncompress/AnyUncompress.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Uncompress/Base.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Uncompress/Bunzip2.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Uncompress/Gunzip.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Uncompress/Inflate.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Uncompress/RawInflate.pm +./usr/libdata/perl5/loongarch64-openbsd/IO/Uncompress/Unzip.pm +./usr/libdata/perl5/loongarch64-openbsd/IPC +./usr/libdata/perl5/loongarch64-openbsd/IPC/Msg.pm +./usr/libdata/perl5/loongarch64-openbsd/IPC/Semaphore.pm +./usr/libdata/perl5/loongarch64-openbsd/IPC/SharedMem.pm +./usr/libdata/perl5/loongarch64-openbsd/IPC/SysV.pm +./usr/libdata/perl5/loongarch64-openbsd/List +./usr/libdata/perl5/loongarch64-openbsd/List/Util +./usr/libdata/perl5/loongarch64-openbsd/List/Util.pm +./usr/libdata/perl5/loongarch64-openbsd/List/Util/XS.pm +./usr/libdata/perl5/loongarch64-openbsd/MIME +./usr/libdata/perl5/loongarch64-openbsd/MIME/Base64.pm +./usr/libdata/perl5/loongarch64-openbsd/MIME/QuotedPrint.pm +./usr/libdata/perl5/loongarch64-openbsd/Math +./usr/libdata/perl5/loongarch64-openbsd/Math/BigInt +./usr/libdata/perl5/loongarch64-openbsd/Math/BigInt/FastCalc.pm +./usr/libdata/perl5/loongarch64-openbsd/NDBM_File.pm +./usr/libdata/perl5/loongarch64-openbsd/O.pm +./usr/libdata/perl5/loongarch64-openbsd/Opcode.pm +./usr/libdata/perl5/loongarch64-openbsd/OpenBSD +./usr/libdata/perl5/loongarch64-openbsd/OpenBSD/MkTemp.pm +./usr/libdata/perl5/loongarch64-openbsd/OpenBSD/Pledge.pm +./usr/libdata/perl5/loongarch64-openbsd/OpenBSD/Unveil.pm +./usr/libdata/perl5/loongarch64-openbsd/POSIX.pm +./usr/libdata/perl5/loongarch64-openbsd/POSIX.pod +./usr/libdata/perl5/loongarch64-openbsd/PerlIO +./usr/libdata/perl5/loongarch64-openbsd/PerlIO/encoding.pm +./usr/libdata/perl5/loongarch64-openbsd/PerlIO/mmap.pm +./usr/libdata/perl5/loongarch64-openbsd/PerlIO/via.pm +./usr/libdata/perl5/loongarch64-openbsd/SDBM_File.pm +./usr/libdata/perl5/loongarch64-openbsd/Scalar +./usr/libdata/perl5/loongarch64-openbsd/Scalar/List +./usr/libdata/perl5/loongarch64-openbsd/Scalar/List/Utils.pm +./usr/libdata/perl5/loongarch64-openbsd/Scalar/Util.pm +./usr/libdata/perl5/loongarch64-openbsd/Socket.pm +./usr/libdata/perl5/loongarch64-openbsd/Storable.pm +./usr/libdata/perl5/loongarch64-openbsd/Sub +./usr/libdata/perl5/loongarch64-openbsd/Sub/Util.pm +./usr/libdata/perl5/loongarch64-openbsd/Sys +./usr/libdata/perl5/loongarch64-openbsd/Sys/Hostname.pm +./usr/libdata/perl5/loongarch64-openbsd/Sys/Syslog.pm +./usr/libdata/perl5/loongarch64-openbsd/Term +./usr/libdata/perl5/loongarch64-openbsd/Term/ReadKey.pm +./usr/libdata/perl5/loongarch64-openbsd/Time +./usr/libdata/perl5/loongarch64-openbsd/Time/HiRes.pm +./usr/libdata/perl5/loongarch64-openbsd/Time/Piece.pm +./usr/libdata/perl5/loongarch64-openbsd/Time/Seconds.pm +./usr/libdata/perl5/loongarch64-openbsd/Unicode +./usr/libdata/perl5/loongarch64-openbsd/Unicode/Collate +./usr/libdata/perl5/loongarch64-openbsd/Unicode/Collate.pm +./usr/libdata/perl5/loongarch64-openbsd/Unicode/Collate/Locale.pm +./usr/libdata/perl5/loongarch64-openbsd/Unicode/Normalize.pm +./usr/libdata/perl5/loongarch64-openbsd/attributes.pm +./usr/libdata/perl5/loongarch64-openbsd/auto +./usr/libdata/perl5/loongarch64-openbsd/auto/B +./usr/libdata/perl5/loongarch64-openbsd/auto/B/B.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Compress +./usr/libdata/perl5/loongarch64-openbsd/auto/Compress/Raw +./usr/libdata/perl5/loongarch64-openbsd/auto/Compress/Raw/Bzip2 +./usr/libdata/perl5/loongarch64-openbsd/auto/Compress/Raw/Bzip2/Bzip2.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Compress/Raw/Zlib +./usr/libdata/perl5/loongarch64-openbsd/auto/Compress/Raw/Zlib/Zlib.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Cwd +./usr/libdata/perl5/loongarch64-openbsd/auto/Cwd/Cwd.so +./usr/libdata/perl5/loongarch64-openbsd/auto/DB_File +./usr/libdata/perl5/loongarch64-openbsd/auto/DB_File/DB_File.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Data +./usr/libdata/perl5/loongarch64-openbsd/auto/Data/Dumper +./usr/libdata/perl5/loongarch64-openbsd/auto/Data/Dumper/Dumper.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Devel +./usr/libdata/perl5/loongarch64-openbsd/auto/Devel/Peek +./usr/libdata/perl5/loongarch64-openbsd/auto/Devel/Peek/Peek.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Digest +./usr/libdata/perl5/loongarch64-openbsd/auto/Digest/MD5 +./usr/libdata/perl5/loongarch64-openbsd/auto/Digest/MD5/MD5.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Digest/SHA +./usr/libdata/perl5/loongarch64-openbsd/auto/Digest/SHA/SHA.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Encode +./usr/libdata/perl5/loongarch64-openbsd/auto/Encode/Byte +./usr/libdata/perl5/loongarch64-openbsd/auto/Encode/Byte/Byte.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Encode/CN +./usr/libdata/perl5/loongarch64-openbsd/auto/Encode/CN/CN.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Encode/EBCDIC +./usr/libdata/perl5/loongarch64-openbsd/auto/Encode/EBCDIC/EBCDIC.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Encode/Encode.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Encode/JP +./usr/libdata/perl5/loongarch64-openbsd/auto/Encode/JP/JP.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Encode/KR +./usr/libdata/perl5/loongarch64-openbsd/auto/Encode/KR/KR.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Encode/Symbol +./usr/libdata/perl5/loongarch64-openbsd/auto/Encode/Symbol/Symbol.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Encode/TW +./usr/libdata/perl5/loongarch64-openbsd/auto/Encode/TW/TW.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Encode/Unicode +./usr/libdata/perl5/loongarch64-openbsd/auto/Encode/Unicode/Unicode.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Fcntl +./usr/libdata/perl5/loongarch64-openbsd/auto/Fcntl/Fcntl.so +./usr/libdata/perl5/loongarch64-openbsd/auto/File +./usr/libdata/perl5/loongarch64-openbsd/auto/File/DosGlob +./usr/libdata/perl5/loongarch64-openbsd/auto/File/DosGlob/DosGlob.so +./usr/libdata/perl5/loongarch64-openbsd/auto/File/Glob +./usr/libdata/perl5/loongarch64-openbsd/auto/File/Glob/Glob.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Filter +./usr/libdata/perl5/loongarch64-openbsd/auto/Filter/Util +./usr/libdata/perl5/loongarch64-openbsd/auto/Filter/Util/Call +./usr/libdata/perl5/loongarch64-openbsd/auto/Filter/Util/Call/Call.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Hash +./usr/libdata/perl5/loongarch64-openbsd/auto/Hash/Util +./usr/libdata/perl5/loongarch64-openbsd/auto/Hash/Util/FieldHash +./usr/libdata/perl5/loongarch64-openbsd/auto/Hash/Util/FieldHash/FieldHash.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Hash/Util/Util.so +./usr/libdata/perl5/loongarch64-openbsd/auto/I18N +./usr/libdata/perl5/loongarch64-openbsd/auto/I18N/Langinfo +./usr/libdata/perl5/loongarch64-openbsd/auto/I18N/Langinfo/Langinfo.so +./usr/libdata/perl5/loongarch64-openbsd/auto/IO +./usr/libdata/perl5/loongarch64-openbsd/auto/IO/IO.so +./usr/libdata/perl5/loongarch64-openbsd/auto/IPC +./usr/libdata/perl5/loongarch64-openbsd/auto/IPC/SysV +./usr/libdata/perl5/loongarch64-openbsd/auto/IPC/SysV/SysV.so +./usr/libdata/perl5/loongarch64-openbsd/auto/List +./usr/libdata/perl5/loongarch64-openbsd/auto/List/Util +./usr/libdata/perl5/loongarch64-openbsd/auto/List/Util/Util.so +./usr/libdata/perl5/loongarch64-openbsd/auto/MIME +./usr/libdata/perl5/loongarch64-openbsd/auto/MIME/Base64 +./usr/libdata/perl5/loongarch64-openbsd/auto/MIME/Base64/Base64.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Math +./usr/libdata/perl5/loongarch64-openbsd/auto/Math/BigInt +./usr/libdata/perl5/loongarch64-openbsd/auto/Math/BigInt/FastCalc +./usr/libdata/perl5/loongarch64-openbsd/auto/Math/BigInt/FastCalc/FastCalc.so +./usr/libdata/perl5/loongarch64-openbsd/auto/NDBM_File +./usr/libdata/perl5/loongarch64-openbsd/auto/NDBM_File/NDBM_File.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Opcode +./usr/libdata/perl5/loongarch64-openbsd/auto/Opcode/Opcode.so +./usr/libdata/perl5/loongarch64-openbsd/auto/OpenBSD +./usr/libdata/perl5/loongarch64-openbsd/auto/OpenBSD/MkTemp +./usr/libdata/perl5/loongarch64-openbsd/auto/OpenBSD/MkTemp/MkTemp.so +./usr/libdata/perl5/loongarch64-openbsd/auto/OpenBSD/Pledge +./usr/libdata/perl5/loongarch64-openbsd/auto/OpenBSD/Pledge/Pledge.so +./usr/libdata/perl5/loongarch64-openbsd/auto/OpenBSD/Unveil +./usr/libdata/perl5/loongarch64-openbsd/auto/OpenBSD/Unveil/Unveil.so +./usr/libdata/perl5/loongarch64-openbsd/auto/POSIX +./usr/libdata/perl5/loongarch64-openbsd/auto/POSIX/POSIX.so +./usr/libdata/perl5/loongarch64-openbsd/auto/PerlIO +./usr/libdata/perl5/loongarch64-openbsd/auto/PerlIO/encoding +./usr/libdata/perl5/loongarch64-openbsd/auto/PerlIO/encoding/encoding.so +./usr/libdata/perl5/loongarch64-openbsd/auto/PerlIO/mmap +./usr/libdata/perl5/loongarch64-openbsd/auto/PerlIO/mmap/mmap.so +./usr/libdata/perl5/loongarch64-openbsd/auto/PerlIO/via +./usr/libdata/perl5/loongarch64-openbsd/auto/PerlIO/via/via.so +./usr/libdata/perl5/loongarch64-openbsd/auto/SDBM_File +./usr/libdata/perl5/loongarch64-openbsd/auto/SDBM_File/SDBM_File.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Socket +./usr/libdata/perl5/loongarch64-openbsd/auto/Socket/Socket.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Storable +./usr/libdata/perl5/loongarch64-openbsd/auto/Storable/Storable.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Sys +./usr/libdata/perl5/loongarch64-openbsd/auto/Sys/Hostname +./usr/libdata/perl5/loongarch64-openbsd/auto/Sys/Hostname/Hostname.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Sys/Syslog +./usr/libdata/perl5/loongarch64-openbsd/auto/Sys/Syslog/Syslog.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Term +./usr/libdata/perl5/loongarch64-openbsd/auto/Term/ReadKey +./usr/libdata/perl5/loongarch64-openbsd/auto/Term/ReadKey/ReadKey.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Time +./usr/libdata/perl5/loongarch64-openbsd/auto/Time/HiRes +./usr/libdata/perl5/loongarch64-openbsd/auto/Time/HiRes/HiRes.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Time/Piece +./usr/libdata/perl5/loongarch64-openbsd/auto/Time/Piece/Piece.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Unicode +./usr/libdata/perl5/loongarch64-openbsd/auto/Unicode/Collate +./usr/libdata/perl5/loongarch64-openbsd/auto/Unicode/Collate/Collate.so +./usr/libdata/perl5/loongarch64-openbsd/auto/Unicode/Normalize +./usr/libdata/perl5/loongarch64-openbsd/auto/Unicode/Normalize/Normalize.so +./usr/libdata/perl5/loongarch64-openbsd/auto/attributes +./usr/libdata/perl5/loongarch64-openbsd/auto/attributes/attributes.so +./usr/libdata/perl5/loongarch64-openbsd/auto/mro +./usr/libdata/perl5/loongarch64-openbsd/auto/mro/mro.so +./usr/libdata/perl5/loongarch64-openbsd/auto/re +./usr/libdata/perl5/loongarch64-openbsd/auto/re/re.so +./usr/libdata/perl5/loongarch64-openbsd/auto/threads +./usr/libdata/perl5/loongarch64-openbsd/auto/threads/shared +./usr/libdata/perl5/loongarch64-openbsd/auto/threads/shared/shared.so +./usr/libdata/perl5/loongarch64-openbsd/auto/threads/threads.so +./usr/libdata/perl5/loongarch64-openbsd/encoding.pm +./usr/libdata/perl5/loongarch64-openbsd/lib.pm +./usr/libdata/perl5/loongarch64-openbsd/mro.pm +./usr/libdata/perl5/loongarch64-openbsd/ops.pm +./usr/libdata/perl5/loongarch64-openbsd/re.pm +./usr/libdata/perl5/loongarch64-openbsd/threads +./usr/libdata/perl5/loongarch64-openbsd/threads.pm +./usr/libdata/perl5/loongarch64-openbsd/threads/shared.pm +./usr/local/libdata/perl5/site_perl/loongarch64-openbsd +./usr/mdec/BOOTLOONGARCH64.EFI +./usr/sbin/eeprom +./usr/sbin/gpioctl +./usr/sbin/pcidump +./usr/sbin/wsconscfg diff --git distrib/sets/lists/comp/md.loongarch64 distrib/sets/lists/comp/md.loongarch64 new file mode 100644 index 00000000000..b105fb587fa --- /dev/null +++ distrib/sets/lists/comp/md.loongarch64 @@ -0,0 +1,51 @@ +./usr/include/loongarch64 +./usr/include/loongarch64/_float.h +./usr/include/loongarch64/_types.h +./usr/include/loongarch64/apmvar.h +./usr/include/loongarch64/asm.h +./usr/include/loongarch64/atomic.h +./usr/include/loongarch64/bootconfig.h +./usr/include/loongarch64/bus.h +./usr/include/loongarch64/cdefs.h +./usr/include/loongarch64/conf.h +./usr/include/loongarch64/cpu.h +./usr/include/loongarch64/cpufunc.h +./usr/include/loongarch64/db_machdep.h +./usr/include/loongarch64/disklabel.h +./usr/include/loongarch64/elf.h +./usr/include/loongarch64/endian.h +./usr/include/loongarch64/exec.h +./usr/include/loongarch64/fdt.h +./usr/include/loongarch64/fenv.h +./usr/include/loongarch64/frame.h +./usr/include/loongarch64/ieee.h +./usr/include/loongarch64/ieeefp.h +./usr/include/loongarch64/intr.h +./usr/include/loongarch64/kcore.h +./usr/include/loongarch64/limits.h +./usr/include/loongarch64/loadfile_machdep.h +./usr/include/loongarch64/mplock.h +./usr/include/loongarch64/mutex.h +./usr/include/loongarch64/openpromio.h +./usr/include/loongarch64/param.h +./usr/include/loongarch64/pcb.h +./usr/include/loongarch64/pci_machdep.h +./usr/include/loongarch64/pmap.h +./usr/include/loongarch64/proc.h +./usr/include/loongarch64/profile.h +./usr/include/loongarch64/pte.h +./usr/include/loongarch64/ptrace.h +./usr/include/loongarch64/reg.h +./usr/include/loongarch64/reloc.h +./usr/include/loongarch64/loongarchreg.h +./usr/include/loongarch64/sbi.h +./usr/include/loongarch64/setjmp.h +./usr/include/loongarch64/signal.h +./usr/include/loongarch64/simplebusvar.h +./usr/include/loongarch64/spinlock.h +./usr/include/loongarch64/sysarch.h +./usr/include/loongarch64/syscall.h +./usr/include/loongarch64/tcb.h +./usr/include/loongarch64/timetc.h +./usr/include/loongarch64/trap.h +./usr/include/loongarch64/vmparam.h diff --git distrib/sets/lists/etc/md.loongarch64 distrib/sets/lists/etc/md.loongarch64 new file mode 100644 index 00000000000..e69de29bb2d diff --git distrib/sets/lists/game/md.loongarch64 distrib/sets/lists/game/md.loongarch64 new file mode 100644 index 00000000000..e69de29bb2d diff --git distrib/sets/lists/man/md.loongarch64 distrib/sets/lists/man/md.loongarch64 new file mode 100644 index 00000000000..e69de29bb2d diff --git etc/etc.loongarch64/MAKEDEV etc/etc.loongarch64/MAKEDEV new file mode 100644 index 00000000000..56fc7865027 --- /dev/null +++ etc/etc.loongarch64/MAKEDEV @@ -0,0 +1,554 @@ +#!/bin/sh - +# +# THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT. +# generated from: +# +# OpenBSD: etc.riscv64/MAKEDEV.md,v 1.6 2025/09/29 01:00:14 deraadt Exp +# OpenBSD: MAKEDEV.common,v 1.124 2025/10/15 17:53:36 deraadt Exp +# OpenBSD: MAKEDEV.mi,v 1.91 2025/11/19 17:49:42 deraadt Exp +# OpenBSD: MAKEDEV.sub,v 1.14 2005/02/07 06:14:18 david Exp +# +# +# Copyright (c) 2001-2004 Todd T. Fries +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# +# Device "make" file. Valid arguments: +# all makes all known devices, including local devices. +# Tries to make the ``standard'' number of each type. +# ramdisk Ramdisk kernel devices +# std Standard devices +# local Configuration specific devices +# redodisks Recreates all partitions +# Disks: +# cd* ATAPI and SCSI CD-ROM drives +# rd* "rd" pseudo-disks +# sd* SCSI disks, including flopticals +# vnd* "file" pseudo-disk devices +# wd* "winchester" disk drives (ST506, IDE, ESDI, RLL, ...) +# Tapes: +# ch* SCSI media changers +# Terminal ports: +# tty[0-7][0-9a-f] NS16x50 serial ports +# Pseudo terminals: +# ptm pty master device +# pty* Set of 62 master pseudo terminals +# tty* Set of 62 slave pseudo terminals +# Console ports: +# ttyC-J* wscons display devices +# wscons Minimal wscons devices +# wskbd* wscons keyboards +# wsmux wscons keyboard/mouse mux devices +# Pointing devices: +# wsmouse* wscons mice +# Printers: +# USB devices: +# ttyU* USB serial ports +# uall All USB devices +# ugen* Generic USB devices +# uhid* Generic HID devices +# fido fido/* nodes +# ujoy ujoy/* nodes +# ulpt* Printer devices +# usb* Bus control devices used by usbd for attach/detach +# Special purpose devices: +# apm Power Management Interface +# audio* Audio devices +# bio ioctl tunnel pseudo-device +# bktr* Video frame grabbers +# bpf Berkeley Packet Filter +# dt Dynamic Tracer +# diskmap Disk mapper +# dri Direct Rendering Infrastructure +# fd fd/* nodes +# fuse Userland Filesystem +# gpio* General Purpose Input/Output +# hotplug devices hot plugging +# ipmi* IPMI BMC access +# pci* PCI bus devices +# pf Packet Filter +# pppx* PPP Multiplexer +# pppac* PPP Access Concentrator +# radio* FM tuner devices +# *random In-kernel random data source +# rmidi* Raw MIDI devices +# tun* Network tunnel driver +# tap* Ethernet tunnel driver +# uk* Unknown SCSI devices +# video* Video V4L2 devices +# vscsi* Virtual SCSI controller +# kstat Kernel Statistics +PATH=/sbin:/usr/sbin:/bin:/usr/bin +UNITMULT=64 +MAKEDEV_PARTITIONS=${MAKEDEV_PARTITIONS:-`sysctl -n kern.maxpartitions`} +T=$0 + +# set this to echo for Echo-Only debugging +[ "$eo" ] || eo= + +# Find all the disk device-names which already exist +finddisks() +{ + local mode x name + ls -n *a | while read mode x x x x x x x x name; do + [[ $mode = b* ]] && echo ${name%a} + done +} + +hex() +{ + case $1 in + [0-9]) echo -n $1;; + 10) echo -n a;; + 11) echo -n b;; + 12) echo -n c;; + 13) echo -n d;; + 14) echo -n e;; + 15) echo -n f;; + esac +} + +alph2d() +{ + local t="$1" + local p="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + local sub=${p%${t}*} + echo ${#sub} +} + +h2d() +{ + local s="$1" + local f=${s%*[0-9a-f]} n=${s#[0-9a-f]*} + + echo $(($(_h2d $f)*16+ $(_h2d $n) )) +} + +_h2d() +{ + case $1 in + [0-9]) echo -n $1;; + a) echo -n 10;; + b) echo -n 11;; + c) echo -n 12;; + d) echo -n 13;; + e) echo -n 14;; + f) echo -n 15;; + esac +} + +unt() +{ + # XXX pdksh can't seem to deal with locally scoped variables + # in ${foo#$bar} expansions + arg="$1" + tmp="${arg#[a-zA-Z]*}" + tmp="${tmp%*[a-zA-Z]}" + while [ "$tmp" != "$arg" ] + do + arg=$tmp + tmp="${arg#[a-zA-Z]*}" + tmp="${tmp%*[a-zA-Z]}" + done + echo $arg +} + +dodisk() +{ + [ "$DEBUG" ] && set -x + n=$(($((${5}*${7:-$UNITMULT}))+${6})) count=0 + _extra= + [ $MAKEDEV_PARTITIONS == 52 ] && _extra="q r s t u v w x y z \ + A B C D E F G H I J K L M N O P Q R S T U V W X Y Z" + for d in a b c d e f g h i j k l m n o p $_extra + do + M $1$2$d b $3 $(($n+$count)) 640 operator + M r$1$2$d c $4 $(($n+$count)) 640 operator + let count=count+1 + done +} + +dodisk2() +{ + n=$(($(($5*${7:-$UNITMULT}))+$6)) + M $1$2a b $3 $n 640 operator + M r$1$2a c $4 $n 640 operator + n=$(($n+2)) + M $1$2c b $3 $n 640 operator + M r$1$2c c $4 $n 640 operator +} + +# M name b/c major minor [mode] [group] +RMlist[0]="rm -f" + +mkl() { + : ${mklist[0]:=";mknod"} + mklist[${#mklist[*]}]=" -m $1 $2 $3 $4 $5" +} + +M() { + RMlist[${#RMlist[*]}]=$1 + mkl ${5-666} $1 $2 $3 $4 + G=${6:-wheel} + [ "$7" ] && { + MKlist[${#MKlist[*]}]="&& chown $7:$G $1" + } || { + case $G in + wheel) + [ ${#whlist[*]} = 0 ] && whlist[0]="&& chgrp wheel" + whlist[${#whlist[*]}]="$1" + ;; + operator) + [ ${#oplist[*]} = 0 ] && oplist[0]="&& chgrp operator" + oplist[${#oplist[*]}]="$1" + ;; + *) + MKlist[${#MKlist[*]}]="&& chgrp $G $1"; + esac + } + return 0 +} + +R() { +[ "$DEBUG" ] && set -x +for i in "$@" +do +U=`unt $i` +[ "$U" ] || U=0 + +case $i in +ramdisk) + R std bpf wd0 sd0 tty00 tty01 rd0 bio diskmap + R cd0 ttyC0 wskbd0 wskbd1 wskbd2 random + ;; + +std) + M console c 0 0 600 + M tty c 1 0 + M mem c 2 0 640 kmem + M kmem c 2 1 640 kmem + M null c 2 2 + M zero c 2 12 + M stdin c 22 0 + M stdout c 22 1 + M stderr c 22 2 + M ksyms c 50 0 640 kmem + M klog c 7 0 600 + M openprom c 70 0 600 + ;; + + +kstat) + M kstat c 51 0 640 + ;; + +vscsi*) + M vscsi$U c 89 $U 600 + ;; + +video*) + M video$U c 44 $U 600 + MKlist[${#MKlist[*]}]=";[ -e video ] || ln -s video$U video" + ;; + +uk*) + M uk$U c 20 $U 640 operator + ;; + +tap*) + M tap$U c 93 $U 600 + ;; + +tun*) + M tun$U c 40 $U 600 + ;; + +rmidi*) + M rmidi$U c 52 $U 660 _sndiop + ;; + +*random) + M urandom c 45 0 644 + RMlist[${#RMlist[*]}]=random + MKlist[${#MKlist[*]}]=";ln -s urandom random" + ;; + +radio*) + M radio$U c 76 $U + MKlist[${#MKlist[*]}]=";[ -e radio ] || ln -s radio$U radio" + ;; + +pppac*) + M pppac$U c 99 $U 600 + ;; + +pppx*) + M pppx$U c 91 $U 600 + ;; + +pf) + M pf c 73 0 600 + ;; + +pci*) + M pci$U c 72 $U 600 + MKlist[${#MKlist[*]}]=";[ -h pci ] || ln -sf pci0 pci" + ;; + +ipmi*) + M ipmi$U c 96 $U 600 + ;; + +hotplug) + M hotplug c 82 $U 400 + ;; + +gpio*) + M gpio$U c 88 $U 600 + ;; + +fuse) + M fuse$U c 92 $U 600 + ;; + +fd) + RMlist[${#RMlist[*]}]=";mkdir -p fd;rm -f" n=0 + while [ $n -lt 64 ];do M fd/$n c 22 $n;n=$(($n+1));done + MKlist[${#MKlist[*]}]=";chmod 555 fd" + ;; + +dri) + RMlist[${#RMlist[*]}]=";mkdir -p dri;rm -f" + n=0 + while [ $n -lt 4 ] + do + M dri/card$n c 87 $n 600 + r=$(($n+128)) + M dri/renderD$r c 87 $r 600 + n=$(($n+1)) + done + MKlist[${#MKlist[*]}]=";chmod 555 dri" + ;; + +diskmap) + M diskmap c 90 0 640 operator + ;; + +dt) + M dt c 30 0 600 + ;; + +bpf) + M bpf c 23 0 600 + M bpf0 c 23 0 600 + ;; + +bktr*) + M bktr$U c 49 $U 644 + ;; + +bio) + M bio c 79 0 600 + ;; + +audio*) + M audio$U c 42 $U 660 _sndiop + M audioctl$U c 42 $(($U+192)) 660 _sndiop + ;; + +apm*) + M apm c 83 0 644 + M apmctl c 83 8 644 + ;; + +usb*) + [ "$i" = "usb" ] && u= || u=$U + M usb$u c 61 $U 640 + ;; + +ulpt*) + M ulpt$U c 64 $U 600 + ;; + +ujoy) + RMlist[${#RMlist[*]}]=";mkdir -p ujoy;rm -f" n=0 + while [ $n -lt 4 ];do M ujoy/$n c 100 $n 444;n=$(($n+1));done + MKlist[${#MKlist[*]}]=";chmod 555 ujoy" + ;; + +fido) + RMlist[${#RMlist[*]}]=";mkdir -p fido;rm -f" n=0 + while [ $n -lt 4 ];do M fido/$n c 98 $n 666;n=$(($n+1));done + MKlist[${#MKlist[*]}]=";chmod 555 fido" + ;; + +uhid*) + M uhid$U c 62 $U 600 + ;; + +ugen*) + n=$(($U*16)) + for j in 0{0,1,2,3,4,5,6,7,8,9} 1{0,1,2,3,4,5} + do + M ugen$U.$j c 63 $(($n+10#$j)) 600 + done + ;; + +uall) + R ttyU0 ttyU1 ttyU2 ttyU3 ugen0 ugen1 ugen2 ugen3 ugen4 ugen5 + R ugen6 ugen7 ulpt0 ulpt1 ujoy fido uhid0 uhid1 uhid2 uhid3 + R uhid4 uhid5 uhid6 uhid7 usb0 usb1 usb2 usb3 usb4 usb5 usb6 + R usb7 + ;; + +ttyU[0-9a-zA-Z]) + U=${i#ttyU*} + o=$(alph2d $U) + M ttyU$U c 66 $o 660 dialer root + M cuaU$U c 66 $(($o+128)) 660 dialer root + ;; + +wsmouse[0-9]*) + M wsmouse$U c 68 $U 600 + ;; + +wsmux|wsmouse|wskbd) + M wsmouse c 69 0 600 + M wskbd c 69 1 600 + ;; + +wskbd[0-9]*) + M wskbd$U c 67 $U 600 + ;; + +wscons) + R wsmouse0 wsmouse1 wsmouse2 wsmouse3 wsmouse4 wsmouse5 + R wsmouse6 wsmouse7 wsmouse8 wsmouse9 wskbd0 wskbd1 wskbd2 + R wskbd3 wskbd4 wskbd5 wskbd6 wskbd7 wskbd8 wskbd9 wsmux + R ttyCcfg ttyC0 ttyC1 ttyC2 ttyC3 ttyC4 ttyC5 ttyC6 ttyC7 + R ttyC8 ttyC9 ttyCa ttyCb + ;; + +tty[C-J]*) + U=${i##tty[C-J]} + case $i in + ttyC*) n=C m=0;; + ttyD*) n=D m=256;; + ttyE*) n=E m=512;; + ttyF*) n=F m=768;; + ttyG*) n=G m=1024;; + ttyH*) n=H m=1280;; + ttyI*) n=I m=1536;; + ttyJ*) n=J m=1792;; + esac + case $U in + [0-9a-f]) M tty$n$U c 12 $((16#$U+$m)) 600;; + cfg) M tty${n}cfg c 12 $((255+$m)) 600;; + *) echo bad unit $U for $i; exit 1;; + esac + ;; + +pty*) + if [ $U -gt 15 ]; then + echo bad unit for pty in: $i + continue + fi + set -A letters p q r s t u v w x y z P Q R S T + set -A suffixes 0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q \ + r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X \ + Y Z + + name=${letters[$U]} + n=0 + while [ $n -lt 62 ] + do + nam=$name${suffixes[$n]} + off=$(($U*62)) + M tty$nam c 5 $(($off+$n)) + M pty$nam c 6 $(($off+$n)) + n=$(($n+1)) + done + ;; + +ptm) + M ptm c 81 0 666 + ;; + +tty[0-7][0-9a-f]) + U=${i#tty*} + o=$(h2d $U) + M tty$U c 8 $o 660 dialer root + M cua$U c 8 $(($o+128)) 660 dialer root + ;; + +ch*) + M ch$U c 17 $U 660 operator + ;; + +vnd*) + dodisk vnd $U 14 41 $U 0 + ;; + +rd*) + dodisk2 rd $U 8 47 $U 0 + ;; + +cd*) + dodisk2 cd $U 6 15 $U 0 + ;; + +local) + test -s $T.local && sh $T.local + ;; + +all) + R ipmi0 gpio0 gpio1 gpio2 bktr0 vnd0 vnd1 vnd2 vnd3 sd0 sd1 + R sd2 sd3 sd4 sd5 sd6 sd7 sd8 sd9 cd0 cd1 rd0 tap0 tap1 tap2 + R tap3 tun0 tun1 tun2 tun3 bio pty0 dri diskmap vscsi0 ch0 + R audio0 audio1 audio2 audio3 kstat dt bpf fuse pppac pppx + R hotplug ptm local wscons pci0 pci1 pci2 pci3 uall rmidi0 + R rmidi1 rmidi2 rmidi3 rmidi4 rmidi5 rmidi6 rmidi7 radio0 + R video0 video1 video2 video3 uk0 random tty00 tty01 tty02 + R tty03 tty04 tty05 tty06 tty07 tty08 tty09 tty0a tty0b apm pf + R wd0 wd1 wd2 wd3 std fd + ;; + +wd*|sd*) + case $i in + wd*) dodisk wd $U 0 3 $U 0;; + sd*) dodisk sd $U 4 13 $U 0;; + esac + ;; + +redodisks) + R `finddisks` + ;; + +*) + echo $i: unknown device + ;; +esac +done +} +R "$@" +{ +echo -n ${RMlist[*]} +echo -n ${mklist[*]} +echo -n ${MKlist[*]} +echo -n ${whlist[*]} +echo ${oplist[*]} +} | if [ "$eo" = "echo" ]; then + cat +else + sh +fi diff --git etc/etc.loongarch64/MAKEDEV.md etc/etc.loongarch64/MAKEDEV.md new file mode 100644 index 00000000000..af0e29b276f --- /dev/null +++ etc/etc.loongarch64/MAKEDEV.md @@ -0,0 +1,118 @@ +define(MACHINE,loongarch64)dnl +vers(__file__, + {-$OpenBSD: MAKEDEV.md,v 1.6 2025/09/29 01:00:14 deraadt Exp $-}, +etc.MACHINE)dnl +dnl +dnl Copyright (c) 2001-2006 Todd T. Fries +dnl +dnl Permission to use, copy, modify, and distribute this software for any +dnl purpose with or without fee is hereby granted, provided that the above +dnl copyright notice and this permission notice appear in all copies. +dnl +dnl THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +dnl WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +dnl MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +dnl ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +dnl WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +dnl ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +dnl OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +dnl +dnl +__devitem(apm, apm, Power Management Interface)dnl +_TITLE(make) +_DEV(all) +_DEV(ramdisk) +_DEV(std) +_DEV(local) +_DEV(redodisks) +_TITLE(dis) +_DEV(cd, 15, 6) +_DEV(rd, 47, 8) +_DEV(sd, 13, 4) +_DEV(vnd, 41, 14) +_DEV(wd, 3, 0) +_TITLE(tap) +_DEV(ch, 17) +_TITLE(term) +_DEV(com, 8) +_TITLE(pty) +_DEV(ptm, 81) +_DEV(pty, 6) +_DEV(tty, 5) +_TITLE(cons) +_DEV(wsdisp, 12) +_DEV(wscons) +_DEV(wskbd, 67) +_DEV(wsmux, 69) +_TITLE(point) +_DEV(wsmouse, 68) +_TITLE(prn) +_TITLE(usb) +_DEV(ttyU, 66) +_DEV(uall) +_DEV(ugen, 63) +_DEV(uhid, 62) +_DEV(fido, 98) +_DEV(ujoy, 100) +_DEV(ulpt, 64) +_DEV(usb, 61) +_TITLE(spec) +_DEV(apm, 83) +_DEV(au, 42) +_DEV(bio, 79) +_DEV(bktr, 49) +_DEV(bpf, 23) +_DEV(dt, 30) +_DEV(diskmap, 90) +_DEV(dri, 87) +_DEV(fdesc, 22) +_DEV(fuse, 92) +_DEV(gpio, 88) +_DEV(hotplug, 82) +_DEV(ipmi, 96) +dnl _DEV(joy, 26) +_DEV(pci, 72) +_DEV(pf, 73) +_DEV(pppx, 91) +_DEV(pppac, 99) +_DEV(radio, 76) +_DEV(rnd, 45) +_DEV(rmidi, 52) +_DEV(tun, 40) +_DEV(tap, 93) +_DEV(uk, 20) +_DEV(vi, 44) +_DEV(vscsi, 89) +_DEV(kstat, 51) +dnl +divert(__mddivert)dnl +dnl +ramdisk) + _recurse std bpf wd0 sd0 tty00 tty01 rd0 bio diskmap + _recurse cd0 ttyC0 wskbd0 wskbd1 wskbd2 random + ;; + +_std(1, 2, 50, 7) + M openprom c 70 0 600 + ;; + +dnl +dnl riscv specific targets +dnl +twrget(all, au, audio, 0, 1, 2, 3)dnl +target(all, ch, 0)dnl +target(all, vscsi, 0)dnl +target(all, diskmap)dnl +target(all, dri)dnl +target(all, pty, 0)dnl +target(all, bio)dnl +target(all, tun, 0, 1, 2, 3)dnl +target(all, tap, 0, 1, 2, 3)dnl +target(all, rd, 0)dnl +target(all, cd, 0, 1)dnl +target(all, sd, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9)dnl +target(all, vnd, 0, 1, 2, 3)dnl +target(all, bktr, 0)dnl +target(all, gpio, 0, 1, 2)dnl +target(all, ipmi, 0)dnl +twrget(ramd, wsdisp, ttyC, 0)dnl diff --git etc/etc.loongarch64/Makefile etc/etc.loongarch64/Makefile new file mode 100644 index 00000000000..8bccc0ddfdd --- /dev/null +++ etc/etc.loongarch64/Makefile @@ -0,0 +1,5 @@ +# $OpenBSD: Makefile,v 1.1 2021/04/28 03:26:25 drahn Exp $ + +all: MAKEDEV + +.include diff --git etc/etc.loongarch64/Makefile.inc etc/etc.loongarch64/Makefile.inc new file mode 100644 index 00000000000..5bbafc765bc --- /dev/null +++ etc/etc.loongarch64/Makefile.inc @@ -0,0 +1,8 @@ +# $OpenBSD: Makefile.inc,v 1.2 2021/06/29 22:03:30 deraadt Exp $ + +KERNELS += GENERIC.MP bsd.mp + +bootblocks: + cp -p ${DESTDIR}/usr/mdec/BOOTLOONGARCH64.EFI ${RELEASEDIR} + +MDEXT= bsd.rd BOOTLOONGARCH64.EFI miniroot${OSrev}.img diff --git etc/etc.loongarch64/disktab etc/etc.loongarch64/disktab new file mode 100644 index 00000000000..f3487560268 --- /dev/null +++ etc/etc.loongarch64/disktab @@ -0,0 +1,11 @@ +# $OpenBSD: disktab,v 1.2 2023/03/06 18:12:48 krw Exp $ + +# Leave nc=16; adjust size using: ns +rdroot|ramdiskroot|RAM-disk root FS image:\ + :dt=rdroot:se#512:nc#16:nt#2:ns#512:\ + :ta=4.2BSD:oa#0:pa#16384:fa#512:ba#4096:\ + :oc#0:pc#16384: + +miniroot:\ + :dt=rdroot:se#512:nc#33:nt#16:ns#128:\ + :oc#0:pc#67584: diff --git etc/etc.loongarch64/fbtab etc/etc.loongarch64/fbtab new file mode 100644 index 00000000000..530a47bd3ce --- /dev/null +++ etc/etc.loongarch64/fbtab @@ -0,0 +1,2 @@ +/dev/tty00 0600 /dev/console +/dev/ttyC0 0600 /dev/console:/dev/wskbd:/dev/wskbd0:/dev/wsmouse:/dev/wsmouse0:/dev/ttyCcfg:/dev/ttyC4:/dev/dri/card0:/dev/dri/renderD128 diff --git etc/etc.loongarch64/login.conf etc/etc.loongarch64/login.conf new file mode 100644 index 00000000000..0a2539b73a4 --- /dev/null +++ etc/etc.loongarch64/login.conf @@ -0,0 +1,124 @@ +# $OpenBSD: login.conf,v 1.12 2026/05/24 15:43:32 tb Exp $ + +# +# Sample login.conf file. See login.conf(5) for details. +# + +# +# Standard authentication styles: +# +# passwd Use only the local password file +# chpass Do not authenticate, but change user's password (change +# the YP password if the user has one, else change the +# local password) +# lchpass Do not login; change user's local password instead +# ldap Use LDAP authentication +# radius Use RADIUS authentication +# reject Use rejected authentication +# skey Use S/Key authentication +# activ ActivCard X9.9 token authentication +# crypto CRYPTOCard X9.9 token authentication +# snk Digital Pathways SecureNet Key authentication +# token Generic X9.9 token authentication +# yubikey YubiKey authentication +# + +# Default allowed authentication styles +auth-defaults:auth=passwd,skey: + +# Default allowed authentication styles for authentication type ftp +auth-ftp-defaults:auth-ftp=passwd: + +# +# The default values +# To alter the default authentication types change the line: +# :tc=auth-defaults:\ +# to read something like: (enables passwd, "myauth", and activ) +# :auth=passwd,myauth,activ:\ +# Any value changed in the daemon class should be reset in default +# class. +# +default:\ + :path=/usr/bin /bin /usr/sbin /sbin /usr/X11R6/bin /usr/local/bin /usr/local/sbin:\ + :umask=022:\ + :datasize-max=1536M:\ + :datasize-cur=1536M:\ + :maxproc-max=256:\ + :maxproc-cur=128:\ + :openfiles-max=1024:\ + :openfiles-cur=512:\ + :stacksize-cur=4M:\ + :localcipher=blowfish,8:\ + :tc=auth-defaults:\ + :tc=auth-ftp-defaults: + +# +# Settings used by /etc/rc and root +# This must be set properly for daemons started as root by inetd as well. +# Be sure to reset these values to system defaults in the default class! +# +daemon:\ + :ignorenologin:\ + :datasize=4096M:\ + :maxproc=infinity:\ + :openfiles-max=1024:\ + :openfiles-cur=128:\ + :stacksize-cur=8M:\ + :localcipher=blowfish,9:\ + :tc=default: + +# +# Staff have fewer restrictions and can login even when nologins are set. +# +staff:\ + :datasize-cur=1536M:\ + :datasize-max=infinity:\ + :maxproc-max=512:\ + :maxproc-cur=128:\ + :ignorenologin:\ + :requirehome@:\ + :tc=default: + +# +# Authpf accounts get a special motd and shell +# +authpf:\ + :welcome=/etc/motd.authpf:\ + :shell=/usr/sbin/authpf:\ + :tc=default: + +# +# Building LLVM in base requires higher limits +# +build:\ + :datasize-max=3072M:\ + :datasize-cur=3072M:\ + :tc=default: + +# +# Building ports with DPB uses raised limits +# +pbuild:\ + :datasize-max=infinity:\ + :datasize-cur=12G:\ + :maxproc-max=1024:\ + :maxproc-cur=512:\ + :stacksize-cur=8M:\ + :priority=5:\ + :tc=default: + +# +# Override resource limits for certain daemons started by rc.d(8) +# +bgpd:\ + :datasize=16384M:\ + :openfiles=512:\ + :tc=daemon: + +unbound:\ + :openfiles=512:\ + :tc=daemon: + +xenodm:\ + :openfiles=512:\ + :tc=daemon: diff --git etc/etc.loongarch64/sysctl.conf etc/etc.loongarch64/sysctl.conf new file mode 100644 index 00000000000..e69de29bb2d diff --git etc/etc.loongarch64/ttys etc/etc.loongarch64/ttys new file mode 100644 index 00000000000..838ad81686b --- /dev/null +++ etc/etc.loongarch64/ttys @@ -0,0 +1,26 @@ +# +# $OpenBSD: ttys,v 1.1 2021/04/28 03:26:25 drahn Exp $ +# +# name getty type status comments +# +console "/usr/libexec/getty std.115200" vt220 on secure +ttyC0 "/usr/libexec/getty std.9600" vt220 off secure +ttyC1 "/usr/libexec/getty std.9600" vt220 on secure +ttyC2 "/usr/libexec/getty std.9600" vt220 on secure +ttyC3 "/usr/libexec/getty std.9600" vt220 on secure +ttyC4 "/usr/libexec/getty std.9600" vt220 off secure +ttyC5 "/usr/libexec/getty std.9600" vt220 on secure +ttyC6 "/usr/libexec/getty std.9600" vt220 off secure +ttyC7 "/usr/libexec/getty std.9600" vt220 off secure +ttyC8 "/usr/libexec/getty std.9600" vt220 off secure +ttyC9 "/usr/libexec/getty std.9600" vt220 off secure +ttyCa "/usr/libexec/getty std.9600" vt220 off secure +ttyCb "/usr/libexec/getty std.9600" vt220 off secure +tty00 "/usr/libexec/getty std.115200" unknown off secure +tty01 "/usr/libexec/getty std.9600" unknown off secure +tty02 "/usr/libexec/getty std.9600" unknown off +tty03 "/usr/libexec/getty std.9600" unknown off +tty04 "/usr/libexec/getty std.9600" unknown off +tty05 "/usr/libexec/getty std.9600" unknown off +tty06 "/usr/libexec/getty std.9600" unknown off +tty07 "/usr/libexec/getty std.9600" unknown off diff --git gnu/lib/libcompiler_rt/Makefile gnu/lib/libcompiler_rt/Makefile index 51bcfd74206..a9e272c8996 100644 --- gnu/lib/libcompiler_rt/Makefile +++ gnu/lib/libcompiler_rt/Makefile @@ -337,6 +337,11 @@ SRCS+= restore.S \ GEN_SRCS+= ${GEN_TF_SRCS} .endif +.if ${RTARCH} == "loongarch64" +# Quad-precision float support +GEN_SRCS+= ${GEN_TF_SRCS} +.endif + .for file in ${GEN_SRCS} . if exists(${.CURDIR}/../../llvm/compiler-rt/lib/builtins/${RTARCH}/${file}.S) SRCS+= ${file}.S diff --git gnu/usr.bin/Makefile gnu/usr.bin/Makefile index 4d2234f9989..42ba7e132e1 100644 --- gnu/usr.bin/Makefile +++ gnu/usr.bin/Makefile @@ -19,7 +19,7 @@ SUBDIR+= cvs .if make(obj) SUBDIR+= binutils .elif ${MACHINE_CPU} != "aarch64" && ${MACHINE_CPU} != "powerpc64" && \ - ${MACHINE_CPU} != "riscv64" + ${MACHINE_CPU} != "riscv64" && ${MACHINE_CPU} != "loongarch64" SUBDIR+= binutils .endif SUBDIR+= binutils-2.17 diff --git gnu/usr.bin/binutils-2.17/Makefile.bsd-wrapper gnu/usr.bin/binutils-2.17/Makefile.bsd-wrapper index 223483c63f9..94fcbed259e 100644 --- gnu/usr.bin/binutils-2.17/Makefile.bsd-wrapper +++ gnu/usr.bin/binutils-2.17/Makefile.bsd-wrapper @@ -33,7 +33,7 @@ INST_SUBDIRS+= binutils MAN+= binutils/doc/strings.1 .if (${TARGET_ARCH} != "aarch64" && ${TARGET_ARCH} != "powerpc64" && \ - ${TARGET_ARCH} != "riscv64") + ${TARGET_ARCH} != "riscv64" && ${TARGET_ARCH} != "loongarch64") SUBDIRS+= ld gas CONF_SUBDIRS+= ld gas INST_SUBDIRS+= ld gas @@ -72,7 +72,7 @@ CONFIGTARGET= .endif .if ${TARGET_ARCH} == "aarch64" || ${TARGET_ARCH} == "powerpc64" || \ - ${TARGET_ARCH} == "riscv64" + ${TARGET_ARCH} == "riscv64" || ${TARGET_ARCH} == "loongarch64" CONFIGTARGET+=--without-gnu-ld CONFIGTARGET+=--without-gnu-as .endif diff --git gnu/usr.bin/binutils-2.17/bfd/Makefile.am gnu/usr.bin/binutils-2.17/bfd/Makefile.am index b929b857e8c..3cd2c025483 100644 --- gnu/usr.bin/binutils-2.17/bfd/Makefile.am +++ gnu/usr.bin/binutils-2.17/bfd/Makefile.am @@ -82,6 +82,7 @@ ALL_MACHINES = \ cpu-i960.lo \ cpu-ip2k.lo \ cpu-iq2000.lo \ + cpu-loongarch64.lo \ cpu-m32c.lo \ cpu-m32r.lo \ cpu-m68hc11.lo \ @@ -146,6 +147,7 @@ ALL_MACHINES_CFILES = \ cpu-i960.c \ cpu-ip2k.c \ cpu-iq2000.c \ + cpu-loongarch64.lo \ cpu-m32c.c \ cpu-m32r.c \ cpu-m68hc11.c \ @@ -548,6 +550,7 @@ BFD64_BACKENDS = \ elf64-hppa.lo \ elf32-ia64.lo \ elf64-ia64.lo \ + elf64-loongarch.lo \ elf64-gen.lo \ elfn32-mips.lo \ elf64-mips.lo \ @@ -575,6 +578,7 @@ BFD64_BACKENDS_CFILES = \ elf64-alpha.c \ elf64-hppa.c \ elf64-gen.c \ + elf64-loongarch.lo \ elfn32-mips.c \ elf64-mips.c \ elf64-mmix.c \ @@ -1031,6 +1035,7 @@ cpu-i860.lo: cpu-i860.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h cpu-i960.lo: cpu-i960.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h cpu-ip2k.lo: cpu-ip2k.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h cpu-iq2000.lo: cpu-iq2000.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h +cpu-loongarch64.lo: cpu-loongarch64.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h cpu-m32c.lo: cpu-m32c.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h cpu-m32r.lo: cpu-m32r.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h cpu-m68hc11.lo: cpu-m68hc11.c $(INCDIR)/filenames.h \ @@ -1767,6 +1772,9 @@ elf64-hppa.lo: elf64-hppa.c $(INCDIR)/alloca-conf.h \ elf64-gen.lo: elf64-gen.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h \ elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h elf64-target.h +elf64-loongarch.lo: elf64-loongarch.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h \ + elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ + $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h elf64-target.h elfn32-mips.lo: elfn32-mips.c $(INCDIR)/filenames.h \ $(INCDIR)/hashtab.h $(INCDIR)/bfdlink.h genlink.h elf-bfd.h \ $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ diff --git gnu/usr.bin/binutils-2.17/bfd/Makefile.in gnu/usr.bin/binutils-2.17/bfd/Makefile.in index 9b695c45c3f..dd9742808d4 100644 --- gnu/usr.bin/binutils-2.17/bfd/Makefile.in +++ gnu/usr.bin/binutils-2.17/bfd/Makefile.in @@ -318,6 +318,7 @@ ALL_MACHINES = \ cpu-i960.lo \ cpu-ip2k.lo \ cpu-iq2000.lo \ + cpu-loongarch64.lo \ cpu-m32c.lo \ cpu-m32r.lo \ cpu-m68hc11.lo \ @@ -382,6 +383,7 @@ ALL_MACHINES_CFILES = \ cpu-i960.c \ cpu-ip2k.c \ cpu-iq2000.c \ + cpu-loongarch64.c \ cpu-m32c.c \ cpu-m32r.c \ cpu-m68hc11.c \ @@ -787,6 +789,7 @@ BFD64_BACKENDS = \ elf64-hppa.lo \ elf32-ia64.lo \ elf64-ia64.lo \ + elf64-loongarch.lo \ elf64-gen.lo \ elfn32-mips.lo \ elf64-mips.lo \ @@ -815,6 +818,7 @@ BFD64_BACKENDS_CFILES = \ elf64-alpha.c \ elf64-hppa.c \ elf64-gen.c \ + elf64-loongarch.c \ elfn32-mips.c \ elf64-mips.c \ elf64-mmix.c \ @@ -1600,6 +1604,7 @@ cpu-i860.lo: cpu-i860.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h cpu-i960.lo: cpu-i960.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h cpu-ip2k.lo: cpu-ip2k.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h cpu-iq2000.lo: cpu-iq2000.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h +cpu-loongarch64.lo: cpu-loongarch64.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h cpu-m32c.lo: cpu-m32c.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h cpu-m32r.lo: cpu-m32r.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h cpu-m68hc11.lo: cpu-m68hc11.c $(INCDIR)/filenames.h \ @@ -2341,6 +2346,9 @@ elf64-hppa.lo: elf64-hppa.c $(INCDIR)/alloca-conf.h \ elf64-gen.lo: elf64-gen.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h \ elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h elf64-target.h +elf64-loongarch.lo: elf64-loongarch.c $(INCDIR)/filenames.h $(INCDIR)/hashtab.h \ + elf-bfd.h $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h \ + $(INCDIR)/elf/external.h $(INCDIR)/bfdlink.h elf64-target.h elfn32-mips.lo: elfn32-mips.c $(INCDIR)/filenames.h \ $(INCDIR)/hashtab.h $(INCDIR)/bfdlink.h genlink.h elf-bfd.h \ $(INCDIR)/elf/common.h $(INCDIR)/elf/internal.h $(INCDIR)/elf/external.h \ diff --git gnu/usr.bin/binutils-2.17/bfd/archures.c gnu/usr.bin/binutils-2.17/bfd/archures.c index ab2d868231e..2395aead4a0 100644 --- gnu/usr.bin/binutils-2.17/bfd/archures.c +++ gnu/usr.bin/binutils-2.17/bfd/archures.c @@ -384,6 +384,7 @@ DESCRIPTION .#define bfd_mach_r800 11 {* R800: successor with multiplication. *} . bfd_arch_aarch64, . bfd_arch_riscv64, +. bfd_arch_loongarch64, . bfd_arch_last . }; */ @@ -446,6 +447,7 @@ extern const bfd_arch_info_type bfd_i960_arch; extern const bfd_arch_info_type bfd_ia64_arch; extern const bfd_arch_info_type bfd_ip2k_arch; extern const bfd_arch_info_type bfd_iq2000_arch; +extern const bfd_arch_info_type bfd_loongarch64_arch; extern const bfd_arch_info_type bfd_m32c_arch; extern const bfd_arch_info_type bfd_m32r_arch; extern const bfd_arch_info_type bfd_m68hc11_arch; @@ -514,6 +516,7 @@ static const bfd_arch_info_type * const bfd_archures_list[] = &bfd_ia64_arch, &bfd_ip2k_arch, &bfd_iq2000_arch, + &bfd_loongarch_arch, &bfd_m32c_arch, &bfd_m32r_arch, &bfd_m68hc11_arch, diff --git gnu/usr.bin/binutils-2.17/bfd/bfd-in2.h gnu/usr.bin/binutils-2.17/bfd/bfd-in2.h index 53dd756ea64..ab498ab7321 100644 --- gnu/usr.bin/binutils-2.17/bfd/bfd-in2.h +++ gnu/usr.bin/binutils-2.17/bfd/bfd-in2.h @@ -1988,6 +1988,7 @@ enum bfd_architecture #define bfd_mach_r800 11 /* R800: successor with multiplication. */ bfd_arch_aarch64, bfd_arch_riscv64, + bfd_arch_loongarch64, bfd_arch_last }; diff --git gnu/usr.bin/binutils-2.17/bfd/config.bfd gnu/usr.bin/binutils-2.17/bfd/config.bfd index fbf223e839e..d98a1ca4ae7 100644 --- gnu/usr.bin/binutils-2.17/bfd/config.bfd +++ gnu/usr.bin/binutils-2.17/bfd/config.bfd @@ -82,6 +82,7 @@ dlx*) targ_archs=bfd_dlx_arch ;; hppa*) targ_archs=bfd_hppa_arch ;; i[3-7]86) targ_archs=bfd_i386_arch ;; i370) targ_archs=bfd_i370_arch ;; +loongarch64) targ_archs=bfd_loongarch64_arch ;; m6811*|m68hc11*) targ_archs="bfd_m68hc11_arch bfd_m68hc12_arch" ;; m6812*|m68hc12*) targ_archs="bfd_m68hc12_arch bfd_m68hc11_arch" ;; m68*) targ_archs=bfd_m68k_arch ;; @@ -179,6 +180,10 @@ case "${targ}" in targ_defvec=bfd_elf32_ia64_hpux_big_vec targ_selvecs="bfd_elf64_ia64_hpux_big_vec" ;; + loongarch64-*-openbsd*) + targ_defvec=bfd_elf64_loongarch_vec + ;; + riscv64-*-openbsd*) targ_defvec=bfd_elf64_riscv_vec ;; diff --git gnu/usr.bin/binutils-2.17/bfd/configure gnu/usr.bin/binutils-2.17/bfd/configure index ea423d3725c..746c7b03570 100755 --- gnu/usr.bin/binutils-2.17/bfd/configure +++ gnu/usr.bin/binutils-2.17/bfd/configure @@ -13189,6 +13189,7 @@ do bfd_elf64_ia64_little_vec) tb="$tb elf64-ia64.lo elf64.lo $elf"; target_size=64 ;; bfd_elf64_little_generic_vec) tb="$tb elf64-gen.lo elf64.lo $elf"; target_size=64 ;; bfd_elf64_littlemips_vec) tb="$tb elf64-mips.lo elf64.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;; + bfd_elf64_loongarch_vec) tb="$tb elf64-loongarch.lo"; target_size=64 ;; bfd_elf64_mmix_vec) tb="$tb elf64-mmix.lo elf64.lo $elf" target_size=64 ;; bfd_elf64_powerpc_vec) tb="$tb elf64-ppc.lo elf64-gen.lo elf64.lo $elf"; target_size=64 ;; bfd_elf64_powerpcle_vec) tb="$tb elf64-ppc.lo elf64-gen.lo elf64.lo $elf" target_size=64 ;; diff --git gnu/usr.bin/binutils-2.17/bfd/cpu-loongarch64.c gnu/usr.bin/binutils-2.17/bfd/cpu-loongarch64.c new file mode 100644 index 00000000000..ce42a0f445f --- /dev/null +++ gnu/usr.bin/binutils-2.17/bfd/cpu-loongarch64.c @@ -0,0 +1,40 @@ +/* BFD Support for RISCV + + Copyright 2005 Free Software Foundation, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, + USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +const bfd_arch_info_type bfd_loongarch64_arch = + { + 64, /* Bits in a word. */ + 64, /* Bits in an address. */ + 8, /* Bits in a byte. */ + bfd_arch_loongarch64, + 0, /* Only one machine. */ + "loongarch", /* Arch name. */ + "loongarch:la64", /* Arch printable name. */ + 4, /* Section align power. */ + TRUE, /* The one and only. */ + bfd_default_compatible, + bfd_default_scan , + 0, + }; diff --git gnu/usr.bin/binutils-2.17/bfd/elf64-loongarch.c gnu/usr.bin/binutils-2.17/bfd/elf64-loongarch.c new file mode 100644 index 00000000000..c164cbdd045 --- /dev/null +++ gnu/usr.bin/binutils-2.17/bfd/elf64-loongarch.c @@ -0,0 +1,69 @@ +/* Generic support for 64-bit ELF + Copyright 1993, 1995, 1998, 1999, 2001, 2002, 2004, 2005 + Free Software Foundation, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "elf-bfd.h" + +/* This does not include any relocation information, but should be + good enough for GDB or objdump to read the file. */ + +static reloc_howto_type dummy = + HOWTO (0, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + NULL, /* special_function */ + "UNKNOWN", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE); /* pcrel_offset */ + +static void +elf_generic_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, + arelent *bfd_reloc, + Elf_Internal_Rela *elf_reloc ATTRIBUTE_UNUSED) +{ + bfd_reloc->howto = &dummy; +} + +static void +elf_generic_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, + arelent *bfd_reloc, + Elf_Internal_Rela *elf_reloc ATTRIBUTE_UNUSED) +{ + bfd_reloc->howto = &dummy; +} + +#define TARGET_LITTLE_SYM bfd_elf64_loongarch_vec +#define TARGET_LITTLE_NAME "elf64-loongarch" +#define ELF_ARCH bfd_arch_loongarch64 +#define ELF_MACHINE_CODE EM_LOONGARCH +#define ELF_MAXPAGESIZE 0x1000 +#define bfd_elf64_bfd_reloc_type_lookup bfd_default_reloc_type_lookup +#define elf_info_to_howto elf_generic_info_to_howto +#define elf_info_to_howto_rel elf_generic_info_to_howto_rel + +#include "elf64-target.h" diff --git gnu/usr.bin/binutils-2.17/bfd/targets.c gnu/usr.bin/binutils-2.17/bfd/targets.c index 7c23d4157c3..5110028d19d 100644 --- gnu/usr.bin/binutils-2.17/bfd/targets.c +++ gnu/usr.bin/binutils-2.17/bfd/targets.c @@ -660,6 +660,7 @@ extern const bfd_target bfd_elf64_ia64_hpux_big_vec; extern const bfd_target bfd_elf64_ia64_little_vec; extern const bfd_target bfd_elf64_little_generic_vec; extern const bfd_target bfd_elf64_littlemips_vec; +extern const bfd_target bfd_elf64_loongarch_vec; extern const bfd_target bfd_elf64_mmix_vec; extern const bfd_target bfd_elf64_powerpc_vec; extern const bfd_target bfd_elf64_powerpcle_vec; diff --git gnu/usr.bin/binutils-2.17/binutils/readelf.c gnu/usr.bin/binutils-2.17/binutils/readelf.c index 1da22b5016d..081af6d8652 100644 --- gnu/usr.bin/binutils-2.17/binutils/readelf.c +++ gnu/usr.bin/binutils-2.17/binutils/readelf.c @@ -87,6 +87,7 @@ #include "elf/i960.h" #include "elf/ia64.h" #include "elf/ip2k.h" +#include "elf/loongarch.h" #include "elf/m32c.h" #include "elf/m32r.h" #include "elf/m68k.h" @@ -1431,6 +1432,10 @@ dump_relocations (FILE *file, case EM_RISCV: rtype = elf_riscv_reloc_type (type); break; + + case EM_LOONGARCH: + rtype = elf_loongarch_reloc_type (type); + break; } if (rtype == NULL) diff --git gnu/usr.bin/binutils-2.17/include/elf/common.h gnu/usr.bin/binutils-2.17/include/elf/common.h index e71b987576d..c6aff809a5d 100644 --- gnu/usr.bin/binutils-2.17/include/elf/common.h +++ gnu/usr.bin/binutils-2.17/include/elf/common.h @@ -187,6 +187,7 @@ #define EM_CRX 114 /* National Semiconductor CRX */ #define EM_AARCH64 183 #define EM_RISCV 243 +#define EM_LOONGARCH 258 /* If it is necessary to assign new unofficial EM_* values, please pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the chances of collision diff --git gnu/usr.bin/binutils-2.17/include/elf/loongarch.h gnu/usr.bin/binutils-2.17/include/elf/loongarch.h new file mode 100644 index 00000000000..8010164c8ae --- /dev/null +++ gnu/usr.bin/binutils-2.17/include/elf/loongarch.h @@ -0,0 +1,34 @@ +/* LOONGARCH ELF support for BFD. + * Copyright (c) 2017 Philip Guenther + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _ELF_LOONGARCH_H +#define _ELF_LOONGARCH_H + +#include "elf/reloc-macros.h" + +START_RELOC_NUMBERS (elf_loongarch_reloc_type ) + RELOC_NUMBER (R_LARCH_NONE, 0) /* No reloc */ + RELOC_NUMBER (R_LARCH_64, 2) /* Adjust by symbol value */ + RELOC_NUMBER (R_LARCH_RELATIVE, 3) /* Adjust by object base */ + RELOC_NUMBER (R_LARCH_COPY, 4) /* Copy symbol at runtime */ + RELOC_NUMBER (R_LARCH_JUMP_SLOT, 5) /* Create PLT entry */ + RELOC_NUMBER (R_LARCH_TLS_DTPMOD64, 7) /* Dynamic TLS module */ + RELOC_NUMBER (R_LARCH_TLS_DTPREL64, 9) /* Dynamic TLS offset */ + RELOC_NUMBER (R_LARCH_TLS_TPREL64, 11) /* Thread pointer relative */ + RELOC_NUMBER (R_LARCH_IRELATIVE, 58) /* Indirect relative */ +END_RELOC_NUMBERS (R_LARCH_max) + +#endif diff --git gnu/usr.bin/binutils-2.17/opcodes/configure gnu/usr.bin/binutils-2.17/opcodes/configure index 1a4e412bb19..66a39d09068 100755 --- gnu/usr.bin/binutils-2.17/opcodes/configure +++ gnu/usr.bin/binutils-2.17/opcodes/configure @@ -8824,6 +8824,7 @@ if test x${all_targets} = xfalse ; then bfd_ia64_arch) ta="$ta ia64-dis.lo ia64-opc.lo" ;; bfd_ip2k_arch) ta="$ta ip2k-asm.lo ip2k-desc.lo ip2k-dis.lo ip2k-ibld.lo ip2k-opc.lo" using_cgen=yes ;; bfd_iq2000_arch) ta="$ta iq2000-asm.lo iq2000-desc.lo iq2000-dis.lo iq2000-ibld.lo iq2000-opc.lo" using_cgen=yes ;; + bfd_loongarch64_arch) ;; bfd_m32c_arch) ta="$ta m32c-asm.lo m32c-desc.lo m32c-dis.lo m32c-ibld.lo m32c-opc.lo" using_cgen=yes ;; bfd_m32r_arch) ta="$ta m32r-asm.lo m32r-desc.lo m32r-dis.lo m32r-ibld.lo m32r-opc.lo m32r-opinst.lo" using_cgen=yes ;; bfd_m68hc11_arch) ta="$ta m68hc11-dis.lo m68hc11-opc.lo" ;; diff --git gnu/usr.bin/binutils-2.17/opcodes/configure.in gnu/usr.bin/binutils-2.17/opcodes/configure.in index 7d4617ddf66..dddb4708168 100644 --- gnu/usr.bin/binutils-2.17/opcodes/configure.in +++ gnu/usr.bin/binutils-2.17/opcodes/configure.in @@ -176,6 +176,7 @@ if test x${all_targets} = xfalse ; then bfd_ia64_arch) ta="$ta ia64-dis.lo ia64-opc.lo" ;; bfd_ip2k_arch) ta="$ta ip2k-asm.lo ip2k-desc.lo ip2k-dis.lo ip2k-ibld.lo ip2k-opc.lo" using_cgen=yes ;; bfd_iq2000_arch) ta="$ta iq2000-asm.lo iq2000-desc.lo iq2000-dis.lo iq2000-ibld.lo iq2000-opc.lo" using_cgen=yes ;; + bfd_loongarch64_arch) ;; bfd_m32c_arch) ta="$ta m32c-asm.lo m32c-desc.lo m32c-dis.lo m32c-ibld.lo m32c-opc.lo" using_cgen=yes ;; bfd_m32r_arch) ta="$ta m32r-asm.lo m32r-desc.lo m32r-dis.lo m32r-ibld.lo m32r-opc.lo m32r-opinst.lo" using_cgen=yes ;; bfd_m68hc11_arch) ta="$ta m68hc11-dis.lo m68hc11-opc.lo" ;; diff --git gnu/usr.bin/clang/Makefile.arch gnu/usr.bin/clang/Makefile.arch index f56ebf601c7..1bdc8b35de8 100644 --- gnu/usr.bin/clang/Makefile.arch +++ gnu/usr.bin/clang/Makefile.arch @@ -1,6 +1,6 @@ # $OpenBSD: Makefile.arch,v 1.9 2021/04/29 05:32:01 drahn Exp $ -LLVM_ARCHS=AArch64 AMDGPU ARM Mips PowerPC RISCV Sparc X86 +LLVM_ARCHS=AArch64 AMDGPU ARM Mips PowerPC RISCV Sparc X86 LoongArch LLVM_ARCH?= .if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "i386" @@ -17,6 +17,8 @@ LLVM_ARCH= AArch64 LLVM_ARCH= ARM .elif ${MACHINE_ARCH} == "mips64" || ${MACHINE_ARCH} == "mips64el" LLVM_ARCH= Mips +.elif ${MACHINE_ARCH} == "loongarch64" +LLVM_ARCH= LoongArch .endif BACKEND_ASMPARSER?= @@ -34,7 +36,7 @@ BACKEND_DESC+= LLVM${arch}Desc BACKEND_DISASSEMBLER+= LLVM${arch}Disassembler BACKEND_INFO+= LLVM${arch}Info .if "${arch}" == "X86" || "${arch}" == "AArch64" || "${arch}" == "ARM" \ - || "${arch}" == "AMDGPU" || "${arch}" == "RISCV" + || "${arch}" == "AMDGPU" || "${arch}" == "RISCV" || "${arch}" == "LoongArch" BACKEND_UTILS+= LLVM${arch}Utils .endif .endif diff --git gnu/usr.bin/clang/include/llvm/LoongArch/Makefile gnu/usr.bin/clang/include/llvm/LoongArch/Makefile new file mode 100644 index 00000000000..ef983fdbd6c --- /dev/null +++ gnu/usr.bin/clang/include/llvm/LoongArch/Makefile @@ -0,0 +1,76 @@ +# $OpenBSD: Makefile,v 1.5 2026/05/29 11:18:30 robert Exp $ + +.include + +LLVM_SRCS= ${.CURDIR}/../../../../../llvm/llvm + +HDRS= LoongArchGenAsmMatcher.inc \ + LoongArchGenAsmWriter.inc \ + LoongArchGenDAGISel.inc \ + LoongArchGenDisassemblerTables.inc \ + LoongArchGenInstrInfo.inc \ + LoongArchGenMCCodeEmitter.inc \ + LoongArchGenMCPseudoLowering.inc \ + LoongArchGenRegisterInfo.inc \ + LoongArchGenSubtargetInfo.inc \ + LoongArchGenSDNodeInfo.inc + +all: ${HDRS} + +install: + @# Nothing here so far ... + +clean cleandir: + rm -f ${HDRS} + +LoongArchGenRegisterInfo.inc: ${LLVM_SRCS}/lib/Target/LoongArch/LoongArch.td + ${.OBJDIR}/../../../llvm-tblgen/llvm-tblgen -gen-register-info \ + -I${LLVM_SRCS}/include -I${LLVM_SRCS}/lib/Target/LoongArch \ + -o ${.TARGET} ${.ALLSRC} + +LoongArchGenDisassemblerTables.inc: ${LLVM_SRCS}/lib/Target/LoongArch/LoongArch.td + ${.OBJDIR}/../../../llvm-tblgen/llvm-tblgen -gen-disassembler \ + -I${LLVM_SRCS}/include -I${LLVM_SRCS}/lib/Target/LoongArch \ + -o ${.TARGET} ${.ALLSRC} + +LoongArchGenInstrInfo.inc: ${LLVM_SRCS}/lib/Target/LoongArch/LoongArch.td + ${.OBJDIR}/../../../llvm-tblgen/llvm-tblgen -gen-instr-info \ + -I${LLVM_SRCS}/include -I${LLVM_SRCS}/lib/Target/LoongArch \ + -o ${.TARGET} ${.ALLSRC} + +LoongArchGenAsmWriter.inc: ${LLVM_SRCS}/lib/Target/LoongArch/LoongArch.td + ${.OBJDIR}/../../../llvm-tblgen/llvm-tblgen -gen-asm-writer \ + -I${LLVM_SRCS}/include \ + -I${LLVM_SRCS}/lib/Target/LoongArch -o ${.TARGET} ${.ALLSRC} + +LoongArchGenAsmMatcher.inc: ${LLVM_SRCS}/lib/Target/LoongArch/LoongArch.td + ${.OBJDIR}/../../../llvm-tblgen/llvm-tblgen -gen-asm-matcher \ + -I${LLVM_SRCS}/include -I${LLVM_SRCS}/lib/Target/LoongArch \ + -o ${.TARGET} ${.ALLSRC} + +LoongArchGenDAGISel.inc: ${LLVM_SRCS}/lib/Target/LoongArch/LoongArch.td + ${.OBJDIR}/../../../llvm-tblgen/llvm-tblgen -gen-dag-isel \ + -I${LLVM_SRCS}/include -I${LLVM_SRCS}/lib/Target/LoongArch \ + -o ${.TARGET} ${.ALLSRC} + +LoongArchGenSubtargetInfo.inc: ${LLVM_SRCS}/lib/Target/LoongArch/LoongArch.td + ${.OBJDIR}/../../../llvm-tblgen/llvm-tblgen -gen-subtarget \ + -I${LLVM_SRCS}/include -I${LLVM_SRCS}/lib/Target/LoongArch \ + -o ${.TARGET} ${.ALLSRC} + +LoongArchGenMCCodeEmitter.inc: ${LLVM_SRCS}/lib/Target/LoongArch/LoongArch.td + ${.OBJDIR}/../../../llvm-tblgen/llvm-tblgen -gen-emitter \ + -I${LLVM_SRCS}/include -I${LLVM_SRCS}/lib/Target/LoongArch \ + -o ${.TARGET} ${.ALLSRC} + +LoongArchGenMCPseudoLowering.inc: ${LLVM_SRCS}/lib/Target/LoongArch/LoongArch.td + ${.OBJDIR}/../../../llvm-tblgen/llvm-tblgen -gen-pseudo-lowering \ + -I${LLVM_SRCS}/include -I${LLVM_SRCS}/lib/Target/LoongArch \ + -o ${.TARGET} ${.ALLSRC} + +LoongArchGenSDNodeInfo.inc: ${LLVM_SRCS}/lib/Target/LoongArch/LoongArch.td + ${.OBJDIR}/../../../llvm-tblgen/llvm-tblgen -gen-sd-node-info \ + -I${LLVM_SRCS}/include -I${LLVM_SRCS}/lib/Target/LoongArch \ + -o ${.TARGET} ${.ALLSRC} + +.include diff --git gnu/usr.bin/clang/libLLVMLoongArchAsmParser/Makefile gnu/usr.bin/clang/libLLVMLoongArchAsmParser/Makefile new file mode 100644 index 00000000000..8e503062610 --- /dev/null +++ gnu/usr.bin/clang/libLLVMLoongArchAsmParser/Makefile @@ -0,0 +1,11 @@ +# $OpenBSD: Makefile,v 1.1 2021/04/29 05:32:01 drahn Exp $ + +LIB= LLVMLoongArchAsmParser +NOPROFILE= + +CPPFLAGS+= -I${.OBJDIR}/../include/llvm/LoongArch \ + -I${LLVM_SRCS}/lib/Target/LoongArch + +SRCS+= LoongArchAsmParser.cpp + +.PATH: ${.CURDIR}/../../../llvm/llvm/lib/Target/LoongArch/AsmParser diff --git gnu/usr.bin/clang/libLLVMLoongArchCodeGen/Makefile gnu/usr.bin/clang/libLLVMLoongArchCodeGen/Makefile new file mode 100644 index 00000000000..06c01350cb6 --- /dev/null +++ gnu/usr.bin/clang/libLLVMLoongArchCodeGen/Makefile @@ -0,0 +1,26 @@ +# $OpenBSD: Makefile,v 1.6 2026/05/29 11:18:31 robert Exp $ + +LIB= LLVMLoongArchCodeGen +NOPROFILE= + +CPPFLAGS+= -I${.OBJDIR}/../include/llvm/LoongArch \ + -I${LLVM_SRCS}/lib/Target/LoongArch + +SRCS+= LoongArchAsmPrinter.cpp \ + LoongArchDeadRegisterDefinitions.cpp \ + LoongArchExpandAtomicPseudoInsts.cpp \ + LoongArchExpandPseudoInsts.cpp \ + LoongArchFrameLowering.cpp \ + LoongArchInstrInfo.cpp \ + LoongArchISelDAGToDAG.cpp \ + LoongArchISelLowering.cpp \ + LoongArchMCInstLower.cpp \ + LoongArchMergeBaseOffset.cpp \ + LoongArchOptWInstrs.cpp \ + LoongArchRegisterInfo.cpp \ + LoongArchSelectionDAGInfo.cpp \ + LoongArchSubtarget.cpp \ + LoongArchTargetMachine.cpp \ + LoongArchTargetTransformInfo.cpp + +.PATH: ${.CURDIR}/../../../llvm/llvm/lib/Target/LoongArch diff --git gnu/usr.bin/clang/libLLVMLoongArchDesc/Makefile gnu/usr.bin/clang/libLLVMLoongArchDesc/Makefile new file mode 100644 index 00000000000..9fed4bb0a36 --- /dev/null +++ gnu/usr.bin/clang/libLLVMLoongArchDesc/Makefile @@ -0,0 +1,20 @@ +# $OpenBSD: Makefile,v 1.4 2026/05/29 11:18:31 robert Exp $ + +LIB= LLVMLoongArchDesc +NOPROFILE= + +CPPFLAGS+= -I${.OBJDIR}/../include/llvm/LoongArch \ + -I${LLVM_SRCS}/lib/Target/LoongArch + +SRCS+= LoongArchAsmBackend.cpp \ + LoongArchBaseInfo.cpp \ + LoongArchELFObjectWriter.cpp \ + LoongArchInstPrinter.cpp \ + LoongArchMCAsmInfo.cpp \ + LoongArchMCCodeEmitter.cpp \ + LoongArchMCTargetDesc.cpp \ + LoongArchMatInt.cpp \ + LoongArchTargetStreamer.cpp \ + LoongArchELFStreamer.cpp + +.PATH: ${.CURDIR}/../../../llvm/llvm/lib/Target/LoongArch/MCTargetDesc diff --git gnu/usr.bin/clang/libLLVMLoongArchDisassembler/Makefile gnu/usr.bin/clang/libLLVMLoongArchDisassembler/Makefile new file mode 100644 index 00000000000..e9bc72f304f --- /dev/null +++ gnu/usr.bin/clang/libLLVMLoongArchDisassembler/Makefile @@ -0,0 +1,11 @@ +# $OpenBSD: Makefile,v 1.1 2021/04/29 05:32:01 drahn Exp $ + +LIB= LLVMLoongArchDisassembler +NOPROFILE= + +CPPFLAGS+= -I${.OBJDIR}/../include/llvm/LoongArch \ + -I${LLVM_SRCS}/lib/Target/LoongArch + +SRCS+= LoongArchDisassembler.cpp + +.PATH: ${.CURDIR}/../../../llvm/llvm/lib/Target/LoongArch/Disassembler diff --git gnu/usr.bin/clang/libLLVMLoongArchInfo/Makefile gnu/usr.bin/clang/libLLVMLoongArchInfo/Makefile new file mode 100644 index 00000000000..aff14f0bac5 --- /dev/null +++ gnu/usr.bin/clang/libLLVMLoongArchInfo/Makefile @@ -0,0 +1,11 @@ +# $OpenBSD: Makefile,v 1.1 2021/04/29 05:32:01 drahn Exp $ + +LIB= LLVMLoongArchInfo +NOPROFILE= + +CPPFLAGS+= -I${.OBJDIR}/../include/llvm/LoongArch \ + -I${LLVM_SRCS}/lib/Target/LoongArch + +SRCS+= LoongArchTargetInfo.cpp + +.PATH: ${.CURDIR}/../../../llvm/llvm/lib/Target/LoongArch/TargetInfo diff --git gnu/usr.bin/clang/llvm-config/LibraryDependencies.inc.LoongArch gnu/usr.bin/clang/llvm-config/LibraryDependencies.inc.LoongArch new file mode 100644 index 00000000000..870e966ebb7 --- /dev/null +++ gnu/usr.bin/clang/llvm-config/LibraryDependencies.inc.LoongArch @@ -0,0 +1,131 @@ + + struct AvailableComponent { + /// The name of the component. + const char *Name; + + /// The name of the library for this component (or NULL). + const char *Library; + + /// Whether the component is installed. + bool IsInstalled; + + /// The list of libraries required when linking this component. + const char *RequiredLibraries[116]; + } AvailableComponents[116] = { + { "abi", "LLVMABI", true, {"core", "support"} }, +{ "aggressiveinstcombine", "LLVMAggressiveInstCombine", true, {"analysis", "core", "support", "transformutils"} }, +{ "all", nullptr, true, {"demangle", "supportlsp", "support", "tablegen", "abi", "core", "fuzzercli", "fuzzmutate", "filecheck", "interfacestub", "irprinter", "irreader", "cas", "cgdata", "codegen", "selectiondag", "asmprinter", "mirparser", "globalisel", "codegentypes", "binaryformat", "bitreader", "bitwriter", "bitstreamreader", "dwarflinker", "dwarflinkerclassic", "dwarflinkerparallel", "extensions", "frontendatomic", "frontenddirective", "frontenddriver", "frontendhlsl", "frontendopenacc", "frontendopenmp", "frontendoffloading", "transformutils", "instrumentation", "aggressiveinstcombine", "instcombine", "scalaropts", "ipo", "vectorize", "objcarcopts", "coroutines", "cfguard", "hipstdpar", "linker", "analysis", "dtlto", "lto", "mc", "mcparser", "mcdisassembler", "mca", "objcopy", "object", "objectyaml", "option", "remarks", "debuginfodwarflowlevel", "debuginfodwarf", "debuginfogsym", "debuginfologicalview", "debuginfomsf", "debuginfocodeview", "debuginfopdb", "symbolize", "debuginfobtf", "dwarfcfichecker", "dwp", "executionengine", "interpreter", "jitlink", "mcjit", "orcjit", "orcdebugging", "orcshared", "orctargetprocess", "runtimedyld", "target", "loongarchcodegen", "loongarchasmparser", "loongarchdisassembler", "loongarchdesc", "loongarchtargetmca", "loongarchinfo", "amdgpucodegen", "amdgpuasmparser", "amdgpudisassembler", "amdgputargetmca", "amdgpudesc", "amdgpuinfo", "amdgpuutils", "sandboxir", "asmparser", "lineeditor", "profiledata", "coverage", "passes", "plugins", "targetparser", "textapi", "textapibinaryreader", "telemetry", "dlltooldriver", "libdriver", "xray", "windowsdriver", "windowsmanifest", "all-targets", "engine", "native", "nativecodegen", "loongarch", "amdgpu"} }, +{ "all-targets", nullptr, true, {"loongarch", "amdgpu"} }, +{ "amdgpu", nullptr, true, {"amdgpucodegen", "amdgpuasmparser", "amdgpudisassembler", "amdgputargetmca", "amdgpudesc", "amdgpuinfo", "amdgpuutils"} }, +{ "amdgpuasmparser", "LLVMAMDGPUAsmParser", true, {"amdgpudesc", "amdgpuinfo", "amdgpuutils", "codegentypes", "mc", "mcparser", "support", "targetparser"} }, +{ "amdgpucodegen", "LLVMAMDGPUCodeGen", true, {"amdgpudesc", "amdgpuinfo", "amdgpuutils", "analysis", "asmprinter", "binaryformat", "codegen", "codegentypes", "core", "globalisel", "hipstdpar", "ipo", "irprinter", "instrumentation", "mc", "mirparser", "objcarcopts", "passes", "scalaropts", "selectiondag", "support", "target", "targetparser", "transformutils", "vectorize"} }, +{ "amdgpudesc", "LLVMAMDGPUDesc", true, {"amdgpuinfo", "amdgpuutils", "binaryformat", "codegentypes", "core", "mc", "support", "targetparser"} }, +{ "amdgpudisassembler", "LLVMAMDGPUDisassembler", true, {"amdgpudesc", "amdgpuinfo", "amdgpuutils", "codegentypes", "mc", "mcdisassembler", "support"} }, +{ "amdgpuinfo", "LLVMAMDGPUInfo", true, {"mc", "support"} }, +{ "amdgputargetmca", "LLVMAMDGPUTargetMCA", true, {"amdgpudesc", "amdgpuinfo", "amdgpuutils", "codegentypes", "mc", "mca", "mcparser", "support", "targetparser"} }, +{ "amdgpuutils", "LLVMAMDGPUUtils", true, {"analysis", "binaryformat", "codegentypes", "core", "mc", "mcparser", "support", "targetparser"} }, +{ "analysis", "LLVMAnalysis", true, {"binaryformat", "core", "frontendhlsl", "object", "profiledata", "support", "targetparser"} }, +{ "asmparser", "LLVMAsmParser", true, {"binaryformat", "core", "support", "targetparser"} }, +{ "asmprinter", "LLVMAsmPrinter", true, {"analysis", "binaryformat", "codegen", "codegentypes", "core", "debuginfocodeview", "debuginfodwarf", "debuginfodwarflowlevel", "mc", "mcparser", "profiledata", "remarks", "support", "target", "targetparser"} }, +{ "binaryformat", "LLVMBinaryFormat", true, {"support", "targetparser"} }, +{ "bitreader", "LLVMBitReader", true, {"bitstreamreader", "core", "support", "targetparser"} }, +{ "bitstreamreader", "LLVMBitstreamReader", true, {"support"} }, +{ "bitwriter", "LLVMBitWriter", true, {"analysis", "core", "mc", "object", "profiledata", "support", "targetparser"} }, +{ "cas", "LLVMCAS", true, {"support"} }, +{ "cfguard", "LLVMCFGuard", true, {"core", "support", "targetparser"} }, +{ "cgdata", "LLVMCGData", true, {"bitreader", "bitwriter", "core", "support", "object"} }, +{ "codegen", "LLVMCodeGen", true, {"analysis", "bitreader", "bitwriter", "cgdata", "codegentypes", "core", "mc", "objcarcopts", "profiledata", "scalaropts", "support", "target", "targetparser", "transformutils"} }, +{ "codegentypes", "LLVMCodeGenTypes", true, {"support"} }, +{ "core", "LLVMCore", true, {"binaryformat", "demangle", "remarks", "support", "targetparser"} }, +{ "coroutines", "LLVMCoroutines", true, {"analysis", "core", "ipo", "scalaropts", "support", "transformutils", "targetparser"} }, +{ "coverage", "LLVMCoverage", true, {"core", "object", "profiledata", "support", "targetparser"} }, +{ "debuginfobtf", "LLVMDebugInfoBTF", true, {"support"} }, +{ "debuginfocodeview", "LLVMDebugInfoCodeView", true, {"support"} }, +{ "debuginfodwarf", "LLVMDebugInfoDWARF", true, {"binaryformat", "debuginfodwarflowlevel", "object", "support", "targetparser"} }, +{ "debuginfodwarflowlevel", "LLVMDebugInfoDWARFLowLevel", true, {"binaryformat", "support", "targetparser"} }, +{ "debuginfogsym", "LLVMDebugInfoGSYM", true, {"mc", "object", "support", "targetparser", "debuginfodwarf"} }, +{ "debuginfologicalview", "LLVMDebugInfoLogicalView", true, {"binaryformat", "demangle", "object", "mc", "support", "targetparser", "debuginfocodeview", "debuginfodwarf", "debuginfodwarflowlevel", "debuginfopdb"} }, +{ "debuginfomsf", "LLVMDebugInfoMSF", true, {"support"} }, +{ "debuginfopdb", "LLVMDebugInfoPDB", true, {"binaryformat", "object", "support", "debuginfocodeview", "debuginfomsf"} }, +{ "demangle", "LLVMDemangle", true, {} }, +{ "dlltooldriver", "LLVMDlltoolDriver", true, {"binaryformat", "object", "option", "support", "targetparser"} }, +{ "dtlto", "LLVMDTLTO", true, {"binaryformat", "core", "lto", "object", "support"} }, +{ "dwarfcfichecker", "LLVMDWARFCFIChecker", true, {"mc", "debuginfodwarflowlevel", "support"} }, +{ "dwarflinker", "LLVMDWARFLinker", true, {"binaryformat", "codegen", "debuginfodwarf", "object", "support"} }, +{ "dwarflinkerclassic", "LLVMDWARFLinkerClassic", true, {"asmprinter", "binaryformat", "codegen", "codegentypes", "debuginfodwarf", "debuginfodwarflowlevel", "dwarflinker", "mc", "object", "support", "targetparser"} }, +{ "dwarflinkerparallel", "LLVMDWARFLinkerParallel", true, {"asmprinter", "binaryformat", "codegen", "debuginfodwarf", "debuginfodwarflowlevel", "dwarflinker", "mc", "object", "support", "targetparser"} }, +{ "dwp", "LLVMDWP", true, {"debuginfodwarf", "mc", "object", "support"} }, +{ "engine", nullptr, true, {"interpreter"} }, +{ "executionengine", "LLVMExecutionEngine", true, {"core", "mc", "object", "orctargetprocess", "runtimedyld", "support", "target", "targetparser"} }, +{ "extensions", "LLVMExtensions", true, {"support"} }, +{ "filecheck", "LLVMFileCheck", true, {} }, +{ "frontendatomic", "LLVMFrontendAtomic", true, {"core", "support", "analysis"} }, +{ "frontenddirective", "LLVMFrontendDirective", true, {"support"} }, +{ "frontenddriver", "LLVMFrontendDriver", true, {"core", "support", "analysis", "instrumentation"} }, +{ "frontendhlsl", "LLVMFrontendHLSL", true, {"binaryformat", "core", "support"} }, +{ "frontendoffloading", "LLVMFrontendOffloading", true, {"core", "binaryformat", "object", "objectyaml", "support", "transformutils", "targetparser"} }, +{ "frontendopenacc", "LLVMFrontendOpenACC", true, {} }, +{ "frontendopenmp", "LLVMFrontendOpenMP", true, {"core", "support", "targetparser", "transformutils", "analysis", "demangle", "mc", "scalaropts", "bitreader", "frontendoffloading", "frontendatomic", "frontenddirective"} }, +{ "fuzzercli", "LLVMFuzzerCLI", true, {"support", "targetparser"} }, +{ "fuzzmutate", "LLVMFuzzMutate", true, {"analysis", "bitreader", "bitwriter", "core", "scalaropts", "support", "targetparser", "transformutils"} }, +{ "globalisel", "LLVMGlobalISel", true, {"analysis", "codegen", "codegentypes", "core", "mc", "selectiondag", "support", "target", "transformutils"} }, +{ "hipstdpar", "LLVMHipStdPar", true, {"analysis", "core", "support", "transformutils"} }, +{ "instcombine", "LLVMInstCombine", true, {"analysis", "core", "support", "transformutils"} }, +{ "instrumentation", "LLVMInstrumentation", true, {"analysis", "core", "demangle", "mc", "support", "targetparser", "transformutils", "profiledata"} }, +{ "interfacestub", "LLVMInterfaceStub", true, {"binaryformat", "mc", "object", "support", "targetparser"} }, +{ "interpreter", "LLVMInterpreter", true, {"codegen", "core", "executionengine", "support"} }, +{ "ipo", "LLVMipo", true, {"aggressiveinstcombine", "analysis", "bitreader", "bitwriter", "core", "frontendopenmp", "instcombine", "irreader", "demangle", "linker", "object", "profiledata", "scalaropts", "support", "targetparser", "transformutils", "vectorize", "instrumentation"} }, +{ "irprinter", "LLVMIRPrinter", true, {"analysis", "core", "support"} }, +{ "irreader", "LLVMIRReader", true, {"asmparser", "bitreader", "core", "support"} }, +{ "jitlink", "LLVMJITLink", true, {"binaryformat", "object", "option", "orctargetprocess", "support", "targetparser"} }, +{ "libdriver", "LLVMLibDriver", true, {"binaryformat", "bitreader", "object", "option", "support", "targetparser", "binaryformat", "bitreader", "object", "option", "support"} }, +{ "lineeditor", "LLVMLineEditor", true, {"support"} }, +{ "linker", "LLVMLinker", true, {"core", "object", "support", "transformutils", "targetparser"} }, +{ "lto", "LLVMLTO", true, {"aggressiveinstcombine", "analysis", "binaryformat", "bitreader", "bitwriter", "cgdata", "codegen", "codegentypes", "core", "extensions", "ipo", "instcombine", "instrumentation", "linker", "mc", "objcarcopts", "object", "passes", "plugins", "remarks", "scalaropts", "support", "target", "targetparser", "transformutils"} }, +{ "mc", "LLVMMC", true, {"binaryformat", "debuginfodwarflowlevel", "support", "targetparser"} }, +{ "mca", "LLVMMCA", true, {"mc", "support"} }, +{ "mcdisassembler", "LLVMMCDisassembler", true, {"mc", "support", "targetparser"} }, +{ "mcjit", "LLVMMCJIT", true, {"core", "executionengine", "object", "runtimedyld", "support", "target"} }, +{ "mcparser", "LLVMMCParser", true, {"mc", "support", "targetparser"} }, +{ "mirparser", "LLVMMIRParser", true, {"asmparser", "binaryformat", "codegen", "codegentypes", "core", "mc", "support", "target"} }, +{ "native", nullptr, true, {} }, +{ "nativecodegen", nullptr, true, {} }, +{ "objcarcopts", "LLVMObjCARCOpts", true, {"analysis", "core", "support", "targetparser", "transformutils"} }, +{ "objcopy", "LLVMObjCopy", true, {"binaryformat", "object", "support", "mc"} }, +{ "object", "LLVMObject", true, {"bitreader", "core", "mc", "irreader", "binaryformat", "mcparser", "support", "targetparser", "textapi"} }, +{ "objectyaml", "LLVMObjectYAML", true, {"binaryformat", "object", "support", "targetparser", "debuginfocodeview", "mc"} }, +{ "option", "LLVMOption", true, {"support"} }, +{ "orcdebugging", "LLVMOrcDebugging", true, {"binaryformat", "debuginfodwarf", "jitlink", "object", "orcjit", "orcshared", "support", "targetparser"} }, +{ "orcjit", "LLVMOrcJIT", true, {"binaryformat", "core", "executionengine", "jitlink", "object", "orcshared", "orctargetprocess", "windowsdriver", "mc", "passes", "runtimedyld", "support", "target", "targetparser", "textapi", "transformutils"} }, +{ "orcshared", "LLVMOrcShared", true, {"support"} }, +{ "orctargetprocess", "LLVMOrcTargetProcess", true, {"binaryformat", "object", "orcshared", "support", "targetparser"} }, +{ "passes", "LLVMPasses", true, {"aggressiveinstcombine", "analysis", "cfguard", "codegen", "globalisel", "core", "coroutines", "hipstdpar", "ipo", "instcombine", "irprinter", "objcarcopts", "scalaropts", "support", "target", "transformutils", "vectorize", "instrumentation"} }, +{ "plugins", "LLVMPlugins", true, {"support"} }, +{ "profiledata", "LLVMProfileData", true, {"bitstreamreader", "core", "object", "support", "demangle", "symbolize", "debuginfodwarf", "debuginfodwarflowlevel", "targetparser"} }, +{ "remarks", "LLVMRemarks", true, {"bitstreamreader", "support"} }, +{ "loongarch", nullptr, true, {"loongarchcodegen", "loongarchasmparser", "loongarchdisassembler", "loongarchdesc", "loongarchtargetmca", "loongarchinfo"} }, +{ "loongarchasmparser", "LLVMLoongArchAsmParser", true, {"mc", "mcparser", "loongarchdesc", "loongarchinfo", "support", "targetparser"} }, +{ "loongarchcodegen", "LLVMLoongArchCodeGen", true, {"analysis", "asmprinter", "codegen", "codegentypes", "core", "globalisel", "ipo", "mc", "passes", "loongarchdesc", "loongarchinfo", "scalaropts", "selectiondag", "support", "target", "targetparser", "transformutils", "vectorize"} }, +{ "loongarchdesc", "LLVMLoongArchDesc", true, {"binaryformat", "mc", "loongarchinfo", "support", "targetparser"} }, +{ "loongarchdisassembler", "LLVMLoongArchDisassembler", true, {"mc", "mcdisassembler", "loongarchdesc", "loongarchinfo", "support"} }, +{ "loongarchinfo", "LLVMLoongArchInfo", true, {"mc", "support"} }, +{ "loongarchtargetmca", "LLVMLoongArchTargetMCA", true, {"codegentypes", "mc", "mca", "mcparser", "loongarchdesc", "loongarchinfo", "support", "targetparser"} }, +{ "runtimedyld", "LLVMRuntimeDyld", true, {"core", "mc", "object", "support", "targetparser"} }, +{ "sandboxir", "LLVMSandboxIR", true, {"core", "support", "analysis"} }, +{ "scalaropts", "LLVMScalarOpts", true, {"aggressiveinstcombine", "analysis", "core", "instcombine", "profiledata", "support", "transformutils"} }, +{ "selectiondag", "LLVMSelectionDAG", true, {"analysis", "codegen", "codegentypes", "core", "mc", "support", "target", "targetparser", "transformutils"} }, +{ "support", "LLVMSupport", true, {"demangle"} }, +{ "supportlsp", "LLVMSupportLSP", true, {"support"} }, +{ "symbolize", "LLVMSymbolize", true, {"debuginfodwarf", "debuginfogsym", "debuginfopdb", "debuginfobtf", "object", "support", "demangle", "targetparser"} }, +{ "tablegen", "LLVMTableGen", true, {"support"} }, +{ "target", "LLVMTarget", true, {"analysis", "core", "mc", "support", "targetparser"} }, +{ "targetparser", "LLVMTargetParser", true, {"support"} }, +{ "telemetry", "LLVMTelemetry", true, {"support"} }, +{ "textapi", "LLVMTextAPI", true, {"support", "binaryformat", "targetparser"} }, +{ "textapibinaryreader", "LLVMTextAPIBinaryReader", true, {"debuginfodwarf", "support", "object", "textapi", "targetparser"} }, +{ "transformutils", "LLVMTransformUtils", true, {"analysis", "core", "support", "targetparser"} }, +{ "vectorize", "LLVMVectorize", true, {"analysis", "core", "support", "transformutils", "sandboxir"} }, +{ "windowsdriver", "LLVMWindowsDriver", true, {"option", "support", "targetparser"} }, +{ "windowsmanifest", "LLVMWindowsManifest", true, {"support"} }, +{ "xray", "LLVMXRay", true, {"support", "object", "targetparser"} }, +}; \ No newline at end of file diff --git gnu/usr.bin/clang/llvm-config/Makefile gnu/usr.bin/clang/llvm-config/Makefile index 396f39b15c0..c7a47037c7d 100644 --- gnu/usr.bin/clang/llvm-config/Makefile +++ gnu/usr.bin/clang/llvm-config/Makefile @@ -3,7 +3,7 @@ PROG= llvm-config BINDIR= /usr/bin -NATIVE_ARCHS=AArch64 ARM Mips PowerPC RISCV Sparc X86 +NATIVE_ARCHS=AArch64 ARM Mips PowerPC RISCV Sparc X86 LoongArch CMAKE= cmake LLVMROOT= ${.CURDIR}/../../../llvm/llvm diff --git lib/csu/loongarch64/md_init.h lib/csu/loongarch64/md_init.h new file mode 100644 index 00000000000..3f7a00dd486 --- /dev/null +++ lib/csu/loongarch64/md_init.h @@ -0,0 +1,110 @@ +/* $OpenBSD: md_init.h,v 1.4 2023/11/18 16:26:16 deraadt Exp $ */ +/* + * Copyright (c) 2020 Dale Rahn + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define MD_SECT_CALL_FUNC(section, func) \ + __asm (".section "#section", \"ax\" \n" \ + "bl " # func " \n" \ + " .previous") + +#define MD_SECTION_PROLOGUE(sect, entry_pt) \ + __asm ( \ + ".section "#sect",\"ax\",%progbits \n" \ + " .globl " #entry_pt " \n" \ + " .type " #entry_pt ",@function \n" \ + " .align 2 \n" \ + #entry_pt": \n" \ + " addi.d $sp, $sp, -16 \n" \ + " st.d $ra, $sp, 8 \n" \ + " st.d $s0, $sp, 0 \n" \ + " addi.d $s0, $sp, 16 \n" \ + " /* fall thru */ \n" \ + " .previous") + + +#define MD_SECTION_EPILOGUE(sect) \ + __asm ( \ + ".section "#sect",\"ax\",%progbits \n" \ + " ld.d $ra, $sp, 8 \n" \ + " ld.d $s0, $sp, 0 \n" \ + " addi.d $sp, $sp, 16 \n" \ + " jirl $zero, $ra, 0 \n" \ + " .previous") + + +#define MD_CRT0_START \ + __asm( \ + ".text \n" \ + " .align 0 \n" \ + " .globl _start \n" \ + " .globl __start \n" \ + " .type _start, @function \n" \ + " .type __start, @function \n" \ + "_start: \n" \ + "__start: \n" \ + "/* Get argc/argv/envp from stack */ \n" \ + " ld.d $a0, $sp, 0 \n" \ + " addi.d $a1, $sp, 0x8 \n" \ + " slli.d $t0, $a0, 0x3 \n" \ + " add.d $a2, $a1, $t0 \n" \ + " addi.d $a2, $a2, 0x8 \n" \ + " \n" \ + " addi.d $sp, $sp, -16 \n" \ + " st.d $t0, $sp, 0 \n" \ + " \n" \ + " b ___start \n" \ + " .size _start, .-_start \n" \ + " .size __start, .-__start \n" \ + ".previous"); + +#define MD_RCRT0_START \ + char **environ, *__progname; \ + __asm( \ + ".text \n" \ + " .align 0 \n" \ + " .globl _start \n" \ + " .globl __start \n" \ + " .type _start, @function \n" \ + " .type __start, @function \n" \ + "_start: \n" \ + "__start: \n" \ + " move $a0, $sp \n" \ + " move $fp, $sp \n" \ + " \n" \ + " addi.d $sp, $sp, -(8+8+(16*8)) \n" \ + " addi.d $a1, $sp, 4 \n" \ + " \n" \ + "1: la $a2, _DYNAMIC \n" \ + " \n" \ + " bl _dl_boot_bind \n" \ + " \n" \ + " move $sp, $fp \n" \ + " li.d $fp, 0x0 \n" \ + " \n" \ + " li.d $a3, 0x0 /* cleanup */ \n" \ + "/* Get argc/argv/envp from stack */ \n" \ + " ld.d $a0, $sp, 0 \n" \ + " addi.d $a1, $sp, 0x0008 \n" \ + " slli.d $a2, $a0, 0x3 \n" \ + " add.d $a2, $a1, $a2 \n" \ + " addi.d $a2, $a2, 0x0008 \n" \ + " \n" \ + " b ___start \n" \ + " .size _start, .-_start \n" \ + " .size __start, .-__start \n" \ + "_csu_abort: \n" \ + " break 13 \n" \ + ".previous"); diff --git lib/libc/arch/loongarch64/DEFS.h lib/libc/arch/loongarch64/DEFS.h new file mode 100644 index 00000000000..09bc27befb6 --- /dev/null +++ lib/libc/arch/loongarch64/DEFS.h @@ -0,0 +1,66 @@ +/* $OpenBSD: DEFS.h,v 1.3 2023/12/11 22:24:16 kettenis Exp $ */ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)SYS.h 5.5 (Berkeley) 5/7/91 + * $NetBSD: SYS.h,v 1.5 2002/06/03 18:30:32 fvdl Exp $ + */ + +#include + +/* + * We define a hidden alias with the prefix "_libc_" for each global symbol + * that may be used internally. By referencing _libc_x instead of x, other + * parts of libc prevent overriding by the application and avoid unnecessary + * relocations. + */ +#define _HIDDEN(x) _libc_##x +#define _HIDDEN_ALIAS(x,y) \ + STRONG_ALIAS(_HIDDEN(x),y); \ + .hidden _HIDDEN(x) +#define _HIDDEN_FALIAS(x,y) \ + _HIDDEN_ALIAS(x,y); \ + .type _HIDDEN(x),@function + +/* + * For functions implemented in ASM that aren't syscalls. + * END_STRONG(x) Like DEF_STRONG() in C; for standard/reserved C names + * END_WEAK(x) Like DEF_WEAK() in C; for non-ISO C names + */ +#define END_STRONG(x) END(x); _HIDDEN_FALIAS(x,x); END(_HIDDEN(x)) +#define END_WEAK(x) END_STRONG(x); .weak x + +#define PINSYSCALL(sysno, label) \ + .pushsection .openbsd.syscalls,"",@progbits; \ + .p2align 2; \ + .long label; \ + .long sysno; \ + .popsection; diff --git lib/libc/arch/loongarch64/Makefile.inc lib/libc/arch/loongarch64/Makefile.inc new file mode 100644 index 00000000000..1ffa2093188 --- /dev/null +++ lib/libc/arch/loongarch64/Makefile.inc @@ -0,0 +1,6 @@ +# $OpenBSD: Makefile.inc,v 1.2 2021/05/04 04:26:00 drahn Exp $ +.include + +# Suppress DWARF2 warnings +DEBUG?= -gdwarf-4 + diff --git lib/libc/arch/loongarch64/SYS.h lib/libc/arch/loongarch64/SYS.h new file mode 100644 index 00000000000..7db45b17bef --- /dev/null +++ lib/libc/arch/loongarch64/SYS.h @@ -0,0 +1,132 @@ +/* $OpenBSD: SYS.h,v 1.5 2023/12/10 16:45:52 deraadt Exp $ */ +/*- + * Copyright (c) 2020 Brian Bamsch + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)SYS.h 5.5 (Berkeley) 5/7/91 + */ + +#include "DEFS.h" +#include + +/* offsetof(struct tib, tib_errno) - offsetof(struct tib, __tib_tcb) */ +#define TCB_OFFSET_ERRNO -12 + +/* offset of errno from tp */ +#define TP_OFFSET_ERRNO TCB_OFFSET_ERRNO + +#define SYSENTRY(x) \ + .weak x; \ + x = _thread_sys_ ## x; \ + ENTRY(_thread_sys_ ## x) +#define SYSENTRY_HIDDEN(x) \ + ENTRY(_thread_sys_ ## x) +#define __END_HIDDEN(x) \ + END(_thread_sys_ ## x); \ + _HIDDEN_FALIAS(x, _thread_sys_ ## x); \ + END(_HIDDEN(x)) +#define __END(x) \ + __END_HIDDEN(x); END(x) + +#define SYSTRAP(x) \ + li.w $t0, SYS_ ## x; \ +97: syscall 0; \ + PINSYSCALL(SYS_ ## x, 97b) + +#define HANDLE_ERROR() \ + beqz $t0, 200f; \ + st.w $a0, $tp, TP_OFFSET_ERRNO; \ + li.w $a0, -1; \ +200: + +#define HANDLE_ERROR_TARGET(target) \ + beqz $t0, 200f; \ + st.w $a0, $tp, TP_OFFSET_ERRNO; \ + li.w $a0, -1; \ + b target; \ +200: +#define _SYSCALL_NOERROR(x,y) \ + SYSENTRY(x); \ + SYSTRAP(y) +#define _SYSCALL_HIDDEN_NOERROR(x,y) \ + SYSENTRY_HIDDEN(x); \ + SYSTRAP(y) + +#define _SYSCALL(x, y) \ + _SYSCALL_NOERROR(x,y); \ + HANDLE_ERROR() \ +#define _SYSCALL_HIDDEN(x, y) \ + _SYSCALL_HIDDEN_NOERROR(x,y); \ + HANDLE_ERROR() \ + +#define SYSCALL_NOERROR(x) \ + _SYSCALL_NOERROR(x,x) + +#define SYSCALL(x) \ + _SYSCALL(x,x) + + +#define PSEUDO_NOERROR(x,y) \ + SYSENTRY(x); \ + RETGUARD_SETUP(x, $t6); \ + SYSTRAP(y); \ + RETGUARD_CHECK(x, $t6); \ + ret; \ + __END(x) + +#define PSEUDO(x,y) \ + SYSENTRY(x); \ + RETGUARD_SETUP(x, $t6); \ + SYSTRAP(y); \ + HANDLE_ERROR(); \ + RETGUARD_CHECK(x, $t6); \ + ret; \ + __END(x) +#define PSEUDO_HIDDEN(x,y) \ + SYSENTRY_HIDDEN(x); \ + RETGUARD_SETUP(x, $t6); \ + SYSTRAP(y); \ + HANDLE_ERROR(); \ + RETGUARD_CHECK(x, $t6); \ + ret; \ + __END_HIDDEN(x) + +#define RSYSCALL_NOERROR(x) \ + PSEUDO_NOERROR(x,x) + +#define RSYSCALL(x) \ + PSEUDO(x,x) +#define RSYSCALL_HIDDEN(x) \ + PSEUDO_HIDDEN(x,x) +#define SYSCALL_END(x) \ + __END(x) +#define SYSCALL_END_HIDDEN(x) \ + __END_HIDDEN(x) diff --git lib/libc/arch/loongarch64/Symbols.list lib/libc/arch/loongarch64/Symbols.list new file mode 100644 index 00000000000..fecd8d3daca --- /dev/null +++ lib/libc/arch/loongarch64/Symbols.list @@ -0,0 +1,5 @@ +__mcount +fabsl +frexpl +ldexpl +modfl diff --git lib/libc/arch/loongarch64/gdtoa/Makefile.inc lib/libc/arch/loongarch64/gdtoa/Makefile.inc new file mode 100644 index 00000000000..f2215dd0407 --- /dev/null +++ lib/libc/arch/loongarch64/gdtoa/Makefile.inc @@ -0,0 +1,3 @@ +# $OpenBSD: Makefile.inc,v 1.1 2021/04/28 04:38:01 drahn Exp $ + +SRCS+= strtord.c strtorQ.c diff --git lib/libc/arch/loongarch64/gdtoa/arith.h lib/libc/arch/loongarch64/gdtoa/arith.h new file mode 100644 index 00000000000..32513b96e90 --- /dev/null +++ lib/libc/arch/loongarch64/gdtoa/arith.h @@ -0,0 +1,6 @@ +#define IEEE_8087 +#define Arith_Kind_ASL 1 +#define Long int +#define Intcast (int)(long) +#define Double_Align +#define X64_bit_pointers diff --git lib/libc/arch/loongarch64/gdtoa/gd_qnan.h lib/libc/arch/loongarch64/gdtoa/gd_qnan.h new file mode 100644 index 00000000000..9593d5c247f --- /dev/null +++ lib/libc/arch/loongarch64/gdtoa/gd_qnan.h @@ -0,0 +1,12 @@ +#define f_QNAN 0x7fc00000 +#define d_QNAN0 0x0 +#define d_QNAN1 0x7ff80000 +#define ld_QNAN0 0x0 +#define ld_QNAN1 0x0 +#define ld_QNAN2 0x0 +#define ld_QNAN3 0x7fff8000 +#define ldus_QNAN0 0x0 +#define ldus_QNAN1 0x0 +#define ldus_QNAN2 0x0 +#define ldus_QNAN3 0x0 +#define ldus_QNAN4 0x0 diff --git lib/libc/arch/loongarch64/gen/Makefile.inc lib/libc/arch/loongarch64/gen/Makefile.inc new file mode 100644 index 00000000000..e251b496848 --- /dev/null +++ lib/libc/arch/loongarch64/gen/Makefile.inc @@ -0,0 +1,10 @@ +# $OpenBSD: Makefile.inc,v 1.2 2021/06/19 18:43:28 deraadt Exp $ +SRCS+= ldexp.c +SRCS+= infinity.c modf.c nan.c +SRCS+= flt_rounds.c +SRCS+= fpclassifyl.c +SRCS+= fpgetmask.c fpgetround.c fpgetsticky.c +SRCS+= fpsetmask.c fpsetround.c fpsetsticky.c +SRCS+= fabs.c usertc.c +SRCS+= setjmp.S _setjmp.S sigsetjmp.S +SRCS+= isnanl.c signbitl.c isfinitel.c isinfl.c isnormall.c diff --git lib/libc/arch/loongarch64/gen/_atomic_lock.c lib/libc/arch/loongarch64/gen/_atomic_lock.c new file mode 100644 index 00000000000..31a6121e5de --- /dev/null +++ lib/libc/arch/loongarch64/gen/_atomic_lock.c @@ -0,0 +1,43 @@ +/* $OpenBSD: _atomic_lock.c,v 1.2 2022/12/27 17:10:06 jmc Exp $ */ +/* + * Copyright (c) 2020 Mars Li + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Atomic lock for loongarch64 + */ + +#include +#include + +/* + * Spinlock does not have Acquire/Release semantics, so amoswap.w.aq + * should not used here. + */ +int +_atomic_lock(volatile _atomic_lock_t *lock) +{ + _atomic_lock_t old; + + /* + * Use the amoswap instruction to swap the lock value with + * a local variable containing the locked state. + */ + __asm__("amswap.w %0, %1, %2" + : "=&r" (old) + : "r" (_ATOMIC_LOCK_LOCKED), "r" (lock) : "memory"); + + return (old != _ATOMIC_LOCK_UNLOCKED); +} diff --git lib/libc/arch/loongarch64/gen/_setjmp.S lib/libc/arch/loongarch64/gen/_setjmp.S new file mode 100644 index 00000000000..a6b67af7b26 --- /dev/null +++ lib/libc/arch/loongarch64/gen/_setjmp.S @@ -0,0 +1,147 @@ +/* $OpenBSD: _setjmp.S,v 1.3 2021/05/14 00:57:03 drahn Exp $ */ +/* + * Copyright (c) 2020 Dale Rahn + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +#include "DEFS.h" +#include + +/* + * LoongArch64 conversion of _setjmp / _longjmp. + * jmp_buf layout (bytes): + * 0: sigmask (unused, but kept for ABI compatibility) + * 8: sp + * 16: s0 (r23) + * 24: s1 (r24) + * 32: s2 (r25) + * 40: s3 (r26) + * 48: s4 (r27) + * 56: s5 (r28) + * 64: s6 (r29) + * 72: s7 (r30) + * 80: s8 (r31) + * 88: ra (r1) + * 96: fs0 (f24) + * 104: fs1 (f25) + * 112: fs2 (f26) + * 120: fs3 (f27) + * 128: fs4 (f28) + * 136: fs5 (f29) + * 144: fs6 (f30) + * 152: fs7 (f31) + * 160: fcsr + */ + +.equ JB_SIGMASK, 0 +.equ JB_SP, 8 +.equ JB_S0, 16 +.equ JB_S1, 24 +.equ JB_S2, 32 +.equ JB_S3, 40 +.equ JB_S4, 48 +.equ JB_S5, 56 +.equ JB_S6, 64 +.equ JB_S7, 72 +.equ JB_S8, 80 +.equ JB_RA, 88 +.equ JB_FS0, 96 +.equ JB_FS1, 104 +.equ JB_FS2, 112 +.equ JB_FS3, 120 +.equ JB_FS4, 128 +.equ JB_FS5, 136 +.equ JB_FS6, 144 +.equ JB_FS7, 152 +.equ JB_FCSR, 160 + +ENTRY(_setjmp) + RETGUARD_SETUP(_setjmp, t6) + + /* Save stack pointer and callee-saved integer registers */ + st.d $sp, $a0, JB_SP + st.d $r23, $a0, JB_S0 + st.d $r24, $a0, JB_S1 + st.d $r25, $a0, JB_S2 + st.d $r26, $a0, JB_S3 + st.d $r27, $a0, JB_S4 + st.d $r28, $a0, JB_S5 + st.d $r29, $a0, JB_S6 + st.d $r30, $a0, JB_S7 + st.d $r31, $a0, JB_S8 + st.d $ra, $a0, JB_RA + +#ifndef _STANDALONE + /* Save callee-saved floating-point registers and fcsr */ + fst.d $f24, $a0, JB_FS0 + fst.d $f25, $a0, JB_FS1 + fst.d $f26, $a0, JB_FS2 + fst.d $f27, $a0, JB_FS3 + fst.d $f28, $a0, JB_FS4 + fst.d $f29, $a0, JB_FS5 + fst.d $f30, $a0, JB_FS6 + fst.d $f31, $a0, JB_FS7 + movfcsr2gr $t0, $fcsr0 + st.d $t0, $a0, JB_FCSR +#endif + + /* Return 0 */ + li.d $a0, 0 + RETGUARD_CHECK(_setjmp, t6) + ret +END_STRONG(_setjmp) + +ENTRY(_longjmp) + RETGUARD_SYMBOL(_longjmp) + RETGUARD_LOAD_RANDOM(_longjmp, t6) + + /* Restore stack pointer */ + ld.d $t0, $a0, JB_SP + move $sp, $t0 + + /* Restore callee-saved integer registers and ra */ + ld.d $r23, $a0, JB_S0 + ld.d $r24, $a0, JB_S1 + ld.d $r25, $a0, JB_S2 + ld.d $r26, $a0, JB_S3 + ld.d $r27, $a0, JB_S4 + ld.d $r28, $a0, JB_S5 + ld.d $r29, $a0, JB_S6 + ld.d $r30, $a0, JB_S7 + ld.d $r31, $a0, JB_S8 + ld.d $ra, $a0, JB_RA + +#ifndef _STANDALONE + /* Restore floating-point registers and fcsr */ + fld.d $f24, $a0, JB_FS0 + fld.d $f25, $a0, JB_FS1 + fld.d $f26, $a0, JB_FS2 + fld.d $f27, $a0, JB_FS3 + fld.d $f28, $a0, JB_FS4 + fld.d $f29, $a0, JB_FS5 + fld.d $f30, $a0, JB_FS6 + fld.d $f31, $a0, JB_FS7 + ld.d $t0, $a0, JB_FCSR + movgr2fcsr $fcsr0, $t0 +#endif + + /* Return value: if a1 == 0 return 1, else return a1 */ + li.d $a0, 1 + beqz $a1, 1f + move $a0, $a1 +1: + RETGUARD_CHECK(_longjmp, t6) + ret +END_STRONG(_longjmp) \ No newline at end of file diff --git lib/libc/arch/loongarch64/gen/fabs.c lib/libc/arch/loongarch64/gen/fabs.c new file mode 100644 index 00000000000..dcd2532cecd --- /dev/null +++ lib/libc/arch/loongarch64/gen/fabs.c @@ -0,0 +1,35 @@ +/* $OpenBSD: fabs.c,v 1.1 2021/06/19 18:43:28 deraadt Exp $ */ +/* + * Copyright (c) 2008 Martynas Venckus + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +/* + * fabs(d) returns the absolute value of d. + */ +double +fabs(double d) +{ + struct ieee_double *p = (struct ieee_double *)&d; + + p->dbl_sign = 0; + + return(d); +} + +__strong_alias(fabsl, fabs); diff --git lib/libc/arch/loongarch64/gen/flt_rounds.c lib/libc/arch/loongarch64/gen/flt_rounds.c new file mode 100644 index 00000000000..2b291aee40b --- /dev/null +++ lib/libc/arch/loongarch64/gen/flt_rounds.c @@ -0,0 +1,31 @@ +/* $OpenBSD: flt_rounds.c,v 1.1 2021/04/28 15:38:59 kettenis Exp $ */ + +/* + * Written by Mark Kettenis based on the hppa version written by + * Miodrag Vallat. Public domain. + */ + +#include +#include + +static const int map[] = { + 1, /* round to nearest, ties to even */ + 0, /* round to zero */ + 3, /* round to negative infinity */ + 2, /* round to positive infinity */ + 4, /* round to nearest, ties away from zero */ + -1, /* invalid */ + -1, /* invalid */ + -1 /* invalid */ +}; + +int +__flt_rounds(void) +{ + uint32_t fcsr; + + __asm volatile ("csrrd %0, 0\n\t" + "andi %0, %0, 3" : "=r"(fcsr)); + return map[fcsr]; +} +DEF_STRONG(__flt_rounds); diff --git lib/libc/arch/loongarch64/gen/fpclassifyl.c lib/libc/arch/loongarch64/gen/fpclassifyl.c new file mode 100644 index 00000000000..9e74a6d9bcd --- /dev/null +++ lib/libc/arch/loongarch64/gen/fpclassifyl.c @@ -0,0 +1,45 @@ +/* $OpenBSD: fpclassifyl.c,v 1.1 2021/04/27 04:36:00 drahn Exp $ */ +/* + * Copyright (c) 2008 Martynas Venckus + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +int +__fpclassifyl(long double e) +{ + struct ieee_ext *p = (struct ieee_ext *)&e; + + if (p->ext_exp == 0) { + if (p->ext_frach == 0 && p->ext_frachm == 0 && + p->ext_fraclm == 0 && p->ext_fracl == 0) + return FP_ZERO; + else + return FP_SUBNORMAL; + } + + if (p->ext_exp == EXT_EXP_INFNAN) { + if (p->ext_frach == 0 && p->ext_frachm == 0 && + p->ext_fraclm == 0 && p->ext_fracl == 0) + return FP_INFINITE; + else + return FP_NAN; + } + + return FP_NORMAL; +} +DEF_STRONG(__fpclassifyl); diff --git lib/libc/arch/loongarch64/gen/fpgetmask.c lib/libc/arch/loongarch64/gen/fpgetmask.c new file mode 100644 index 00000000000..60bd60334a7 --- /dev/null +++ lib/libc/arch/loongarch64/gen/fpgetmask.c @@ -0,0 +1,24 @@ +/* $OpenBSD: fpgetmask.c,v 1.3 2021/04/30 16:13:00 drahn Exp $ */ +/* + * Copyright (c) 2018 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +fp_except +fpgetmask(void) +{ + return 0; +} diff --git lib/libc/arch/loongarch64/gen/fpgetround.c lib/libc/arch/loongarch64/gen/fpgetround.c new file mode 100644 index 00000000000..438b983e0d0 --- /dev/null +++ lib/libc/arch/loongarch64/gen/fpgetround.c @@ -0,0 +1,30 @@ +/* $OpenBSD: fpgetround.c,v 1.1 2021/04/29 17:19:18 kettenis Exp $ */ +/* + * Copyright (c) 2021 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +fp_rnd +fpgetround(void) +{ + uint32_t fcsr; + + __asm volatile ("csrrd %0, 0\n\t" + "andi %0, %0, 0x3" : "=r"(fcsr)); + return fcsr & 0x3; +} +DEF_WEAK(fpgetround); diff --git lib/libc/arch/loongarch64/gen/fpgetsticky.c lib/libc/arch/loongarch64/gen/fpgetsticky.c new file mode 100644 index 00000000000..dc6f3660969 --- /dev/null +++ lib/libc/arch/loongarch64/gen/fpgetsticky.c @@ -0,0 +1,31 @@ +/* $OpenBSD: fpgetsticky.c,v 1.2 2021/04/30 16:13:00 drahn Exp $ */ +/* + * Copyright (c) 2021 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +fp_except +fpgetsticky(void) +{ + uint32_t fflags; + + __asm volatile ("csrrd %0, 0\n\t" + "srli.d %0, %0, 2\n\t" + "andi %0, %0, 0x1f" + : "=r"(fflags)); + return fflags; +} diff --git lib/libc/arch/loongarch64/gen/fpsetmask.c lib/libc/arch/loongarch64/gen/fpsetmask.c new file mode 100644 index 00000000000..3d9a8d901e2 --- /dev/null +++ lib/libc/arch/loongarch64/gen/fpsetmask.c @@ -0,0 +1,24 @@ +/* $OpenBSD: fpsetmask.c,v 1.3 2021/04/30 16:13:00 drahn Exp $ */ +/* + * Copyright (c) 2018 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +fp_except +fpsetmask(fp_except mask) +{ + return 0; +} diff --git lib/libc/arch/loongarch64/gen/fpsetround.c lib/libc/arch/loongarch64/gen/fpsetround.c new file mode 100644 index 00000000000..43b7f5b663f --- /dev/null +++ lib/libc/arch/loongarch64/gen/fpsetround.c @@ -0,0 +1,41 @@ +/* $OpenBSD: fpsetround.c,v 1.2 2021/04/30 16:13:00 drahn Exp $ */ +/* + * Copyright (c) 2021 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +fp_rnd +fpsetround(fp_rnd rnd_dir) +{ + uint32_t fcsr; + + __asm volatile ("csrrd %0, 0 \n\t" + "andi %0, %0, 0x3 \n\t" + "csrrd $t0, 0 \n\t" + "srli.d $t0, $t0, 2 \n\t" // 4. Shift right 2 (discard old RM) + "slli.d $t0, $t0, 2 \n\t" // 5. Shift left 2 (zero-fill RM bits) + "or $t0, $t0, %1 \n\t" + "csrwr $t0, 0 \n\t" + : "=r" (fcsr) + : "r" (rnd_dir) + : "$t0", "memory" + ); + + + /* Truncating to 2 bits means both RNE and RMM become FP_RN. */ + return fcsr & 0x3; +} diff --git lib/libc/arch/loongarch64/gen/fpsetsticky.c lib/libc/arch/loongarch64/gen/fpsetsticky.c new file mode 100644 index 00000000000..1ab22f89d39 --- /dev/null +++ lib/libc/arch/loongarch64/gen/fpsetsticky.c @@ -0,0 +1,44 @@ +/* $OpenBSD: fpsetsticky.c,v 1.2 2021/04/30 16:13:00 drahn Exp $ */ +/* + * Copyright (c) 2021 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +fp_except +fpsetsticky(fp_except sticky) +{ + uint32_t fflags; + + __asm volatile ( + "csrrd %0, 0 \n\t" // 1. Read FCSR -> %0 (Return old fflags) + "srli.d %0, %0, 2 \n\t" // 2. Shift right 2 (Align flags to bits [4:0]) + "andi %0, %0, 0x1f \n\t" // 3. Mask 5 bits (NV, DZ, OF, UF, NX) + "csrrd $t0, 0 \n\t" // 4. Read FCSR -> $t0 (Modify) + "andi $t1, $t0, 0x3 \n\t" // 5. Save RM (bits [1:0]) -> $t1 + "srli.d $t0, $t0, 2 \n\t" // 6. Discard old flags + RM + "slli.d $t0, $t0, 2 \n\t" // 7. Zero flags [6:2] and RM [1:0] + "slli.d %1, %1, 2 \n\t" // 8. Align new flags (input bits [4:0] -> [6:2]) + "or $t0, $t0, %1 \n\t" // 9. Merge new flags + "or $t0, $t0, $t1 \n\t" // 10. Restore RM + "csrwr $t0, 0 \n\t" // 11. Write FCSR + : "=r" (fflags) // Output: Old flags (RISC-V fflags format) + : "r" (sticky) // Input: New flags (RISC-V fflags format, bits [4:0]) + : "$t0", "$t1", "memory" // Clobbers: Scratch regs + memory barrier for FP state + ); + + return fflags; +} diff --git lib/libc/arch/loongarch64/gen/infinity.c lib/libc/arch/loongarch64/gen/infinity.c new file mode 100644 index 00000000000..96fd51278d4 --- /dev/null +++ lib/libc/arch/loongarch64/gen/infinity.c @@ -0,0 +1,14 @@ +/* $OpenBSD: infinity.c,v 1.1 2021/04/27 04:36:00 drahn Exp $ */ +/* + * IEEE-compatible infinity.c -- public domain. + */ + +#include +#include + +char __infinity[] __attribute__((__aligned__(sizeof(double)))) = +#if BYTE_ORDER == BIG_ENDIAN + { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0}; +#else + { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f}; +#endif diff --git lib/libc/arch/loongarch64/gen/isfinitel.c lib/libc/arch/loongarch64/gen/isfinitel.c new file mode 100644 index 00000000000..e37d2d13cf9 --- /dev/null +++ lib/libc/arch/loongarch64/gen/isfinitel.c @@ -0,0 +1,28 @@ +/* $OpenBSD: isfinitel.c,v 1.1 2021/04/27 04:36:00 drahn Exp $ */ +/* + * Copyright (c) 2008 Martynas Venckus + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +int +__isfinitel(long double e) +{ + struct ieee_ext *p = (struct ieee_ext *)&e; + + return (p->ext_exp != EXT_EXP_INFNAN); +} diff --git lib/libc/arch/loongarch64/gen/isinfl.c lib/libc/arch/loongarch64/gen/isinfl.c new file mode 100644 index 00000000000..f459fe99a77 --- /dev/null +++ lib/libc/arch/loongarch64/gen/isinfl.c @@ -0,0 +1,30 @@ +/* $OpenBSD: isinfl.c,v 1.1 2021/04/27 04:36:00 drahn Exp $ */ +/* + * Copyright (c) 2008 Martynas Venckus + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +int +__isinfl(long double e) +{ + struct ieee_ext *p = (struct ieee_ext *)&e; + + return (p->ext_exp == EXT_EXP_INFNAN && + p->ext_frach == 0 && p->ext_frachm == 0 && + p->ext_fraclm == 0 && p->ext_fracl == 0); +} diff --git lib/libc/arch/loongarch64/gen/isnanl.c lib/libc/arch/loongarch64/gen/isnanl.c new file mode 100644 index 00000000000..8633385e93e --- /dev/null +++ lib/libc/arch/loongarch64/gen/isnanl.c @@ -0,0 +1,30 @@ +/* $OpenBSD: isnanl.c,v 1.1 2021/04/27 04:36:00 drahn Exp $ */ +/* + * Copyright (c) 2008 Martynas Venckus + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +int +__isnanl(long double e) +{ + struct ieee_ext *p = (struct ieee_ext *)&e; + + return (p->ext_exp == EXT_EXP_INFNAN && + (p->ext_frach != 0 || p->ext_frachm != 0 || + p->ext_fraclm != 0 || p->ext_fracl != 0)); +} diff --git lib/libc/arch/loongarch64/gen/isnormall.c lib/libc/arch/loongarch64/gen/isnormall.c new file mode 100644 index 00000000000..f17e6a2473f --- /dev/null +++ lib/libc/arch/loongarch64/gen/isnormall.c @@ -0,0 +1,28 @@ +/* $OpenBSD: isnormall.c,v 1.1 2021/04/27 04:36:00 drahn Exp $ */ +/* + * Copyright (c) 2008 Martynas Venckus + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +int +__isnormall(long double e) +{ + struct ieee_ext *p = (struct ieee_ext *)&e; + + return (p->ext_exp != 0 && p->ext_exp != EXT_EXP_INFNAN); +} diff --git lib/libc/arch/loongarch64/gen/nan.c lib/libc/arch/loongarch64/gen/nan.c new file mode 100644 index 00000000000..71f5393ee7c --- /dev/null +++ lib/libc/arch/loongarch64/gen/nan.c @@ -0,0 +1,13 @@ +/* $OpenBSD: nan.c,v 1.1 2021/04/27 04:36:00 drahn Exp $ */ +/* Written by Martynas Venckus. Public Domain. */ + +#include +#include + +/* bytes for qNaN on an arm (IEEE single format) */ +char __nan[] __attribute__((__aligned__(sizeof(float)))) = +#if BYTE_ORDER == BIG_ENDIAN + { 0x7f, 0xc0, 0, 0 }; +#else /* BYTE_ORDER == BIG_ENDIAN */ + { 0, 0, 0xc0, 0x7f }; +#endif /* BYTE_ORDER == BIG_ENDIAN */ diff --git lib/libc/arch/loongarch64/gen/setjmp.S lib/libc/arch/loongarch64/gen/setjmp.S new file mode 100644 index 00000000000..13cdd194de5 --- /dev/null +++ lib/libc/arch/loongarch64/gen/setjmp.S @@ -0,0 +1,172 @@ +/* $OpenBSD: setjmp.S,v 1.3 2021/05/17 15:06:09 deraadt Exp $ */ +/* + * Copyright (c) 2020 Dale Rahn + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "SYS.h" +#include + +/* + * LoongArch64 conversion of the original RISC-V setjmp/longjmp. + * Register mapping: + * - Callee-saved integer: s0-s8 ($r23-$r31) + * - Callee-saved FP: fs0-fs7 ($f24-$f31) + * - ra ($r1), sp ($r2) + * - fcsr (floating-point control/status register) + * + * jmp_buf layout (offsets in bytes): + * 0: sigmask (word) + * 8: sp + * 16: s0 + * 24: s1 + * 32: s2 + * 40: s3 + * 48: s4 + * 56: s5 + * 64: s6 + * 72: s7 + * 80: s8 + * 88: ra + * 96: fs0 + * 104: fs1 + * 112: fs2 + * 120: fs3 + * 128: fs4 + * 136: fs5 + * 144: fs6 + * 152: fs7 + * 160: fcsr (double) + */ + +.equ JB_SIGMASK, 0 +.equ JB_SP, 8 +.equ JB_S0, 16 +.equ JB_S1, 24 +.equ JB_S2, 32 +.equ JB_S3, 40 +.equ JB_S4, 48 +.equ JB_S5, 56 +.equ JB_S6, 64 +.equ JB_S7, 72 +.equ JB_S8, 80 +.equ JB_RA, 88 +.equ JB_FS0, 96 +.equ JB_FS1, 104 +.equ JB_FS2, 112 +.equ JB_FS3, 120 +.equ JB_FS4, 128 +.equ JB_FS5, 136 +.equ JB_FS6, 144 +.equ JB_FS7, 152 +.equ JB_FCSR, 160 + +ENTRY(setjmp) + /* Save jmpbuf pointer for later use */ + move $a3, $a0 + + /* Get current signal mask via sigprocmask(SIG_BLOCK, NULL, &mask) */ + li.d $a0, SYS_sigprocmask + li.d $a1, 1 /* SIG_BLOCK */ + li.d $a2, 0 /* set = NULL */ + move $a3, $a3 /* oset = jmpbuf (already in a3) */ + syscall 0 + + /* Store old mask at offset 0 (word) */ + st.w $a0, $a3, JB_SIGMASK + + /* Store stack pointer */ + st.d $sp, $a3, JB_SP + + /* Store callee-saved integer registers s0-s8 ($r23-$r31) and ra ($r1) */ + st.d $r23, $a3, JB_S0 + st.d $r24, $a3, JB_S1 + st.d $r25, $a3, JB_S2 + st.d $r26, $a3, JB_S3 + st.d $r27, $a3, JB_S4 + st.d $r28, $a3, JB_S5 + st.d $r29, $a3, JB_S6 + st.d $r30, $a3, JB_S7 + st.d $r31, $a3, JB_S8 + st.d $ra, $a3, JB_RA + + /* Store callee-saved floating-point registers fs0-fs7 ($f24-$f31) */ + fst.d $f24, $a3, JB_FS0 + fst.d $f25, $a3, JB_FS1 + fst.d $f26, $a3, JB_FS2 + fst.d $f27, $a3, JB_FS3 + fst.d $f28, $a3, JB_FS4 + fst.d $f29, $a3, JB_FS5 + fst.d $f30, $a3, JB_FS6 + fst.d $f31, $a3, JB_FS7 + + /* Store floating-point control/status register (fcsr) */ + movfcsr2gr $t0, $fcsr0 + st.d $t0, $a3, JB_FCSR + + /* Return 0 */ + li.d $a0, 0 + ret +END_STRONG(setjmp) + +ENTRY(longjmp) + /* Save jmpbuf pointer and return value in temporaries */ + move $t0, $a0 /* jmpbuf */ + move $t1, $a1 /* return value (may be 0) */ + + /* Restore signal mask: sigprocmask(SIG_SETMASK, &mask, NULL) */ + ld.w $t2, $t0, JB_SIGMASK /* load saved mask value */ + li.d $a0, SYS_sigprocmask + li.d $a1, 3 /* SIG_SETMASK */ + move $a2, $t2 /* set = mask value (by value) */ + move $a3, $t0 /* oset = jmpbuf (unused but kept) */ + syscall 0 + + /* Restore stack pointer */ + ld.d $t2, $t0, JB_SP + move $sp, $t2 + + /* Restore callee-saved integer registers and ra */ + ld.d $r23, $t0, JB_S0 + ld.d $r24, $t0, JB_S1 + ld.d $r25, $t0, JB_S2 + ld.d $r26, $t0, JB_S3 + ld.d $r27, $t0, JB_S4 + ld.d $r28, $t0, JB_S5 + ld.d $r29, $t0, JB_S6 + ld.d $r30, $t0, JB_S7 + ld.d $r31, $t0, JB_S8 + ld.d $ra, $t0, JB_RA + + /* Restore floating-point registers */ + fld.d $f24, $t0, JB_FS0 + fld.d $f25, $t0, JB_FS1 + fld.d $f26, $t0, JB_FS2 + fld.d $f27, $t0, JB_FS3 + fld.d $f28, $t0, JB_FS4 + fld.d $f29, $t0, JB_FS5 + fld.d $f30, $t0, JB_FS6 + fld.d $f31, $t0, JB_FS7 + + /* Restore floating-point control/status register */ + ld.d $t2, $t0, JB_FCSR + movgr2fcsr $fcsr0, $t2 + + /* Return value: if argument was 0, return 1; else return argument */ + li.d $a0, 1 + bnez $t1, 1f + move $a0, $t1 +1: + ret +END_STRONG(longjmp) diff --git lib/libc/arch/loongarch64/gen/signbitl.c lib/libc/arch/loongarch64/gen/signbitl.c new file mode 100644 index 00000000000..e0162065fde --- /dev/null +++ lib/libc/arch/loongarch64/gen/signbitl.c @@ -0,0 +1,28 @@ +/* $OpenBSD: signbitl.c,v 1.1 2021/04/28 08:25:07 kettenis Exp $ */ +/* + * Copyright (c) 2008 Martynas Venckus + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +int +__signbitl(long double e) +{ + struct ieee_ext *p = (struct ieee_ext *)&e; + + return p->ext_sign; +} diff --git lib/libc/arch/loongarch64/gen/sigsetjmp.S lib/libc/arch/loongarch64/gen/sigsetjmp.S new file mode 100644 index 00000000000..dbcb46101f1 --- /dev/null +++ lib/libc/arch/loongarch64/gen/sigsetjmp.S @@ -0,0 +1,181 @@ +/* $OpenBSD: sigsetjmp.S,v 1.4 2021/06/20 20:43:50 kettenis Exp $ */ +/* + * Copyright (c) 2020 Dale Rahn + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "SYS.h" +#include + +/* + * LoongArch64 conversion of sigsetjmp / siglongjmp. + * jmp_buf layout (from ): + * offset 0: savemask flag (word) + * offset _JB_SIGMASK * 8: signal mask (word) + * offsets 8,16,...: saved registers (see setjmp.S) + * + * This matches the RISC‑V layout used in the original file. + */ + +.equ JB_SAVEMASK, 0 /* offset 0, word */ +.equ JB_SIGMASK_OFF, _JB_SIGMASK * 8 /* byte offset for sigmask */ + +.equ JB_SP, 8 +.equ JB_S0, 16 +.equ JB_S1, 24 +.equ JB_S2, 32 +.equ JB_S3, 40 +.equ JB_S4, 48 +.equ JB_S5, 56 +.equ JB_S6, 64 +.equ JB_S7, 72 +.equ JB_S8, 80 +.equ JB_RA, 88 +.equ JB_FS0, 96 +.equ JB_FS1, 104 +.equ JB_FS2, 112 +.equ JB_FS3, 120 +.equ JB_FS4, 128 +.equ JB_FS5, 136 +.equ JB_FS6, 144 +.equ JB_FS7, 152 +.equ JB_FCSR, 160 + +ENTRY(sigsetjmp) + RETGUARD_SETUP(sigsetjmp, t6) + + /* Save savemask flag at offset 0 */ + st.w $a1, $a0, JB_SAVEMASK + + /* If savemask == 0, skip signal mask saving */ + beqz $a1, 1f + + /* sigprocmask(SIG_BLOCK, NULL, &jmpbuf->_jb_sigmask) */ + li.d $a0, SYS_sigprocmask + li.d $a1, 1 /* SIG_BLOCK */ + li.d $a2, 0 /* set = NULL */ + addi.d $a3, $a0, JB_SIGMASK_OFF /* oset = &jmpbuf->sigmask (byte offset) */ + syscall 0 + /* Kernel returns old mask in a0; store it at the sigmask offset */ + st.w $a0, $a3, 0 /* $a3 still points to sigmask location? actually we need to reload */ + /* Better: we already have jmpbuf in $a0, but we used $a0 as syscall arg. + Save jmpbuf earlier. We'll use a temporary. */ + /* Let's restructure: save jmpbuf in a2 early */ + move $a2, $a0 /* save jmpbuf */ + /* Now call syscall with arguments using $a2 */ + li.d $a0, SYS_sigprocmask + li.d $a1, 1 /* SIG_BLOCK */ + li.d $a2, 0 /* set = NULL */ + addi.d $a3, $a2, JB_SIGMASK_OFF /* oset = &jmpbuf->sigmask */ + syscall 0 + /* Store returned old mask (in a0) at sigmask offset */ + st.w $a0, $a2, JB_SIGMASK_OFF + move $a0, $a2 /* restore jmpbuf pointer */ +1: + /* Now save all other registers (same as setjmp) */ + move $a2, $a0 /* jmpbuf in a2 for convenience */ + + /* Save stack pointer */ + st.d $sp, $a2, JB_SP + + /* Save callee-saved integer registers s0-s8 ($r23-$r31) and ra ($r1) */ + st.d $r23, $a2, JB_S0 + st.d $r24, $a2, JB_S1 + st.d $r25, $a2, JB_S2 + st.d $r26, $a2, JB_S3 + st.d $r27, $a2, JB_S4 + st.d $r28, $a2, JB_S5 + st.d $r29, $a2, JB_S6 + st.d $r30, $a2, JB_S7 + st.d $r31, $a2, JB_S8 + st.d $ra, $a2, JB_RA + + /* Save callee-saved floating-point registers fs0-fs7 ($f24-$f31) */ + fst.d $f24, $a2, JB_FS0 + fst.d $f25, $a2, JB_FS1 + fst.d $f26, $a2, JB_FS2 + fst.d $f27, $a2, JB_FS3 + fst.d $f28, $a2, JB_FS4 + fst.d $f29, $a2, JB_FS5 + fst.d $f30, $a2, JB_FS6 + fst.d $f31, $a2, JB_FS7 + + /* Save fcsr */ + movfcsr2gr $t0, $fcsr0 + st.d $t0, $a2, JB_FCSR + + /* Return 0 */ + li.d $a0, 0 + RETGUARD_CHECK(sigsetjmp, t6) + ret + +END_STRONG(sigsetjmp) + +ENTRY(siglongjmp) + RETGUARD_SYMBOL(siglongjmp) + RETGUARD_LOAD_RANDOM(siglongjmp, t6) + + move $t0, $a0 /* jmpbuf */ + move $t1, $a1 /* return value */ + + /* Load savemask flag; if zero, skip signal mask restore */ + ld.w $t2, $t0, JB_SAVEMASK + beqz $t2, 1f + + /* sigprocmask(SIG_SETMASK, &jmpbuf->sigmask, NULL) */ + li.d $a0, SYS_sigprocmask + li.d $a1, 3 /* SIG_SETMASK */ + ld.w $a2, $t0, JB_SIGMASK_OFF /* set = saved mask value */ + li.d $a3, 0 /* oset = NULL */ + syscall 0 +1: + /* Restore stack pointer */ + ld.d $t2, $t0, JB_SP + move $sp, $t2 + + /* Restore callee-saved integer registers and ra */ + ld.d $r23, $t0, JB_S0 + ld.d $r24, $t0, JB_S1 + ld.d $r25, $t0, JB_S2 + ld.d $r26, $t0, JB_S3 + ld.d $r27, $t0, JB_S4 + ld.d $r28, $t0, JB_S5 + ld.d $r29, $t0, JB_S6 + ld.d $r30, $t0, JB_S7 + ld.d $r31, $t0, JB_S8 + ld.d $ra, $t0, JB_RA + + /* Restore floating-point registers */ + fld.d $f24, $t0, JB_FS0 + fld.d $f25, $t0, JB_FS1 + fld.d $f26, $t0, JB_FS2 + fld.d $f27, $t0, JB_FS3 + fld.d $f28, $t0, JB_FS4 + fld.d $f29, $t0, JB_FS5 + fld.d $f30, $t0, JB_FS6 + fld.d $f31, $t0, JB_FS7 + + /* Restore fcsr */ + ld.d $t2, $t0, JB_FCSR + movgr2fcsr $fcsr0, $t2 + + /* Return value: if original argument was 0, return 1; else return it */ + li.d $a0, 1 + beqz $t1, 2f + move $a0, $t1 +2: + RETGUARD_CHECK(siglongjmp, t6) + ret + +END_STRONG(siglongjmp) diff --git lib/libc/arch/loongarch64/gen/usertc.c lib/libc/arch/loongarch64/gen/usertc.c new file mode 100644 index 00000000000..810095e3c3f --- /dev/null +++ lib/libc/arch/loongarch64/gen/usertc.c @@ -0,0 +1,44 @@ +/* $OpenBSD: usertc.c,v 1.2 2021/07/24 22:41:09 jca Exp $ */ +/* + * Copyright (c) 2020 Paul Irofti + * Copyright (c) 2021 Jeremie Courreges-Anglas + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +static inline u_int +rdtime(void) +{ + uint64_t ret, tmp; + + __asm volatile("rdtime.d %0, %1" : "=r"(ret), "=r"(tmp)); + + return ret; +} + +static int +tc_get_timecount(struct timekeep *tk, u_int *tc) +{ + switch (tk->tk_user) { + case TC_TB: + *tc = rdtime(); + return 0; + } + + return -1; +} + +int (*const _tc_get_timecount)(struct timekeep *, u_int *) = tc_get_timecount; diff --git lib/libc/arch/loongarch64/string/Makefile.inc lib/libc/arch/loongarch64/string/Makefile.inc new file mode 100644 index 00000000000..22940ae0cdd --- /dev/null +++ lib/libc/arch/loongarch64/string/Makefile.inc @@ -0,0 +1,9 @@ +# $OpenBSD: Makefile.inc,v 1.1 2021/04/28 04:26:40 drahn Exp $ + +SRCS+= bcopy.c memcpy.c memmove.c \ + strchr.c strrchr.c \ + bcmp.c bzero.c ffs.c memchr.c memcmp.c memset.c \ + strcmp.c strncmp.c \ + strcat.c strcpy.c strcspn.c strlen.c strlcat.c strlcpy.c \ + strncat.c strncpy.c strpbrk.c strsep.c \ + strspn.c swab.c strstr.c diff --git lib/libc/arch/loongarch64/sys/Ovfork.S lib/libc/arch/loongarch64/sys/Ovfork.S new file mode 100644 index 00000000000..e44186925da --- /dev/null +++ lib/libc/arch/loongarch64/sys/Ovfork.S @@ -0,0 +1,41 @@ +/* $OpenBSD: Ovfork.S,v 1.1 2021/04/29 18:33:36 drahn Exp $ */ +/* + * Copyright (c) 2020 Brian Bamsch + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "SYS.h" + +SYSENTRY_HIDDEN(vfork) + RETGUARD_SETUP(vfork, $t6) + move $a2, $ra + SYSTRAP(vfork) + HANDLE_ERROR() + move $ra, $a2 + RETGUARD_CHECK(vfork, $t6) + ret +SYSCALL_END_HIDDEN(vfork) diff --git lib/libc/arch/loongarch64/sys/brk.S lib/libc/arch/loongarch64/sys/brk.S new file mode 100644 index 00000000000..ee9af7ad1af --- /dev/null +++ lib/libc/arch/loongarch64/sys/brk.S @@ -0,0 +1,59 @@ +/* $OpenBSD: brk.S,v 1.5 2023/12/10 16:45:52 deraadt Exp $ */ +/* + * Copyright (c) 2021 Dale Rahn + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "SYS.h" + + .extern __curbrk + .extern _end + + .data + .align 3 +__minbrk: + .dword _end + + +ENTRY_NB(brk) + RETGUARD_SETUP(brk, $t6) + la.local $t1, __minbrk + ld.d $t5, $t1, 0 + bgeu $a0, $t5, .L_brk_call + move $a0, $t5 + +.L_brk_call: + move $a2, $a0 + la.local $t1, __curbrk + + li.d $t0, SYS_break +99: syscall 0 + PINSYSCALL(SYS_break, 99b) + + /* check for error */ + beqz $t0, .L_brk_ok + + st.w $a0, $tp, TP_OFFSET_ERRNO + li.d $a0, -1 + bl .L_done + + /* update, __curbrk and return */ +.L_brk_ok: + st.d $a2, $t1, 0 + li.d $a0, 0 /* # return 0 */ +.L_done: + RETGUARD_CHECK(brk, $t6); + ret +END(brk) + .weak brk diff --git lib/libc/arch/loongarch64/sys/sbrk.S lib/libc/arch/loongarch64/sys/sbrk.S new file mode 100644 index 00000000000..4ddae335b85 --- /dev/null +++ lib/libc/arch/loongarch64/sys/sbrk.S @@ -0,0 +1,50 @@ +/* $OpenBSD: sbrk.S,v 1.4 2022/12/03 15:02:30 jca Exp $ */ +/* + * Copyright (c) 2021 Dale Rahn + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "SYS.h" + + .extern _end + + .data + .align 3 + .globl __curbrk + .hidden __curbrk + .type __curbrk,@object +__curbrk: + .dword _end + END(__curbrk) + +ENTRY_NB(sbrk) + RETGUARD_SETUP(sbrk, $t6) + + la.local $t1, __curbrk + ld.d $a2, $t1, 0 + add.d $a0, $a0, $a2 // compute current break + move $t3, $a0 + SYSTRAP(break) + beqz $t0, .L_sbrk_ok + st.w $a0, $tp, TP_OFFSET_ERRNO + li.d $a0, -1 + bl .L_sbrk_fail +.L_sbrk_ok: + st.d $t3, $t1, 0 // save current val of curbrk from above + move $a0, $a2 // return old val of curbrk from above +.L_sbrk_fail: + RETGUARD_CHECK(sbrk, $t6); + ret +END(sbrk) + .weak sbrk diff --git lib/libc/arch/loongarch64/sys/sigpending.S lib/libc/arch/loongarch64/sys/sigpending.S new file mode 100644 index 00000000000..fa4085b731e --- /dev/null +++ lib/libc/arch/loongarch64/sys/sigpending.S @@ -0,0 +1,43 @@ +/* $OpenBSD: sigpending.S,v 1.2 2021/05/04 04:26:00 drahn Exp $ */ +/* + * Copyright (c) 2020 Brian Bamsch + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "SYS.h" + +SYSENTRY(sigpending) + RETGUARD_SETUP(sigpending, $t6) + move $a2, $a0 + SYSTRAP(sigpending) + HANDLE_ERROR_TARGET(1f) + st.w $a0, $a2, 0 /* 4 bytes */ + move $a0, $r0 +1: + RETGUARD_CHECK(sigpending, $t6) + ret +SYSCALL_END(sigpending) diff --git lib/libc/arch/loongarch64/sys/sigprocmask.S lib/libc/arch/loongarch64/sys/sigprocmask.S new file mode 100644 index 00000000000..463383fdf60 --- /dev/null +++ lib/libc/arch/loongarch64/sys/sigprocmask.S @@ -0,0 +1,52 @@ +/* $OpenBSD: sigprocmask.S,v 1.2 2021/05/04 04:26:00 drahn Exp $ */ +/* + * Copyright (c) 2020 Brian Bamsch + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "SYS.h" + +SYSENTRY_HIDDEN(sigprocmask) + RETGUARD_SETUP(sigprocmask, $t6) + beqz $a1, 1f + ld.w $a1, $a1, 0 + bl 2f +1: + li.d $a0, 1 + li.d $a1, 0 +2: + + SYSTRAP(sigprocmask) + HANDLE_ERROR_TARGET(3f) + beqz $a2, 1f + st.w $a0, $a2, 0 +1: + li.d $a0, 0 +3: + RETGUARD_CHECK(sigprocmask, $t6) + ret +SYSCALL_END_HIDDEN(sigprocmask) diff --git lib/libc/arch/loongarch64/sys/sigsuspend.S lib/libc/arch/loongarch64/sys/sigsuspend.S new file mode 100644 index 00000000000..54ad64f26dc --- /dev/null +++ lib/libc/arch/loongarch64/sys/sigsuspend.S @@ -0,0 +1,42 @@ +/* $OpenBSD: sigsuspend.S,v 1.2 2021/05/04 04:26:00 drahn Exp $ */ +/* + * Copyright (c) 2020 Brian Bamsch + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "SYS.h" + +SYSENTRY_HIDDEN(sigsuspend) + RETGUARD_SETUP(sigsuspend, $t6) + ld.w $a0, $a0, 0 + SYSTRAP(sigsuspend) + HANDLE_ERROR_TARGET(1f) + li.d $a0, 0 +1: + RETGUARD_CHECK(sigsuspend, $t6) + ret +SYSCALL_END_HIDDEN(sigsuspend) diff --git lib/libc/arch/loongarch64/sys/syscall.S lib/libc/arch/loongarch64/sys/syscall.S new file mode 100644 index 00000000000..b592c3c7e45 --- /dev/null +++ lib/libc/arch/loongarch64/sys/syscall.S @@ -0,0 +1,35 @@ +/* $OpenBSD: syscall.S,v 1.1 2021/04/29 18:33:36 drahn Exp $ */ +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)syscall.s 5.1 (Berkeley) 4/23/90 + */ + +#include "SYS.h" + +RSYSCALL(syscall) diff --git lib/libc/arch/loongarch64/sys/tfork_thread.S lib/libc/arch/loongarch64/sys/tfork_thread.S new file mode 100644 index 00000000000..df52b422c9e --- /dev/null +++ lib/libc/arch/loongarch64/sys/tfork_thread.S @@ -0,0 +1,53 @@ +/* $OpenBSD: tfork_thread.S,v 1.2 2021/05/04 04:26:00 drahn Exp $ */ +/* + * Copyright (c) 2020 Brian Bamsch + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "SYS.h" + +/* + * a0 a1 a2 a3 + * __tfork_thread(param, psize, start_fnc, start_arg); + */ + +ENTRY(__tfork_thread) + RETGUARD_SETUP(__tfork_thread, $t6) + SYSTRAP(__tfork) + HANDLE_ERROR_TARGET(2f) + + beqz $a0, 1f + /* parent thread */ +2: + RETGUARD_CHECK(__tfork_thread, $t6) + ret + +1: /* child thread */ + move $a0, $a3 + jirl $zero, $a2, 0 + SYSTRAP(__threxit) +END(__tfork_thread) diff --git lib/libcrypto/arch/loongarch64/Makefile.inc lib/libcrypto/arch/loongarch64/Makefile.inc new file mode 100644 index 00000000000..badc90517c7 --- /dev/null +++ lib/libcrypto/arch/loongarch64/Makefile.inc @@ -0,0 +1,3 @@ +# $OpenBSD: Makefile.inc,v 1.10 2024/03/29 07:24:09 jsing Exp $ + +# loongarch64 libcrypto build rules diff --git lib/libcrypto/arch/loongarch64/crypto_arch.h lib/libcrypto/arch/loongarch64/crypto_arch.h new file mode 100644 index 00000000000..a3dd98d0cee --- /dev/null +++ lib/libcrypto/arch/loongarch64/crypto_arch.h @@ -0,0 +1,21 @@ +/* $OpenBSD: crypto_arch.h,v 1.1 2024/08/11 13:02:39 jsing Exp $ */ +/* + * Copyright (c) 2024 Joel Sing + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef HEADER_CRYPTO_ARCH_H +#define HEADER_CRYPTO_ARCH_H + +#endif diff --git lib/libcrypto/bn/arch/loongarch64/bn_arch.h lib/libcrypto/bn/arch/loongarch64/bn_arch.h new file mode 100644 index 00000000000..7c0b2f50cf5 --- /dev/null +++ lib/libcrypto/bn/arch/loongarch64/bn_arch.h @@ -0,0 +1,86 @@ +/* $OpenBSD: bn_arch.h,v 1.7 2023/07/09 10:37:32 jsing Exp $ */ +/* + * Copyright (c) 2023 Joel Sing + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#ifndef HEADER_BN_ARCH_H +#define HEADER_BN_ARCH_H + +#ifndef OPENSSL_NO_ASM + +#if defined(__GNUC__) + +#define HAVE_BN_ADDW + +static inline void +bn_addw(BN_ULONG a, BN_ULONG b, BN_ULONG *out_r1, BN_ULONG *out_r0) +{ + BN_ULONG carry, r0; + + __asm__ ( + "add.d %[r0], %[a], %[b] \n" + "sltu %[carry], %[r0], %[a] \n" + : [carry]"=r"(carry), [r0]"=&r"(r0) + : [a]"r"(a), [b]"r"(b)); + + *out_r1 = carry; + *out_r0 = r0; +} + +#define HAVE_BN_MULW + +static inline void +bn_mulw(BN_ULONG a, BN_ULONG b, BN_ULONG *out_r1, BN_ULONG *out_r0) +{ + BN_ULONG r1, r0; + + /* + * Unsigned multiplication using a mulh/mul pair. Note that the order + * of these instructions is important, as they can potentially be fused + * into a single operation. + */ + __asm__ ( + "mulh.du %[r1], %[a], %[b] \n" + "mul.d %[r0], %[a], %[b] \n" + : [r1]"=&r"(r1), [r0]"=r"(r0) + : [a]"r"(a), [b]"r"(b)); + + *out_r1 = r1; + *out_r0 = r0; +} + +#define HAVE_BN_SUBW + +static inline void +bn_subw(BN_ULONG a, BN_ULONG b, BN_ULONG *out_borrow, BN_ULONG *out_r0) +{ + BN_ULONG borrow, r0; + + __asm__ ( + "sub.d %[r0], %[a], %[b] \n" + "sltu %[borrow], %[a], %[r0] \n" + : [borrow]"=r"(borrow), [r0]"=&r"(r0) + : [a]"r"(a), [b]"r"(b)); + + *out_borrow = borrow; + *out_r0 = r0; +} + +#endif /* __GNUC__ */ + +#endif +#endif diff --git lib/libkvm/kvm_loongarch64.c lib/libkvm/kvm_loongarch64.c new file mode 100644 index 00000000000..78490351f4a --- /dev/null +++ lib/libkvm/kvm_loongarch64.c @@ -0,0 +1,129 @@ +/* $OpenBSD: kvm_loongarch64.c,v 1.3 2021/12/01 21:45:19 deraadt Exp $ */ +/* + * Copyright (c) 2006 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice, this permission notice, and the disclaimer below + * appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/*- + * Copyright (C) 1996 Wolfgang Solfrank. + * Copyright (C) 1996 TooLs GmbH. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by TooLs GmbH. + * 4. The name of TooLs GmbH may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * LoongArch machine dependent routines for kvm. + */ + +#include +#include + +#include +#include +#include +#include + +#include + +#include "kvm_private.h" + +#include + +void +_kvm_freevtop(kvm_t *kd) +{ + free(kd->vmst); + kd->vmst = NULL; +} + +int +_kvm_initvtop(kvm_t *kd) +{ + return (0); +} + +/* + * Translate a kernel virtual address to a physical address by walking + * the kernels page table. + */ + +int +_kvm_kvatop(kvm_t *kd, u_long va, paddr_t *pa) +{ + cpu_kcore_hdr_t *cpup = kd->cpu_data; + + if (ISALIVE(kd)) { + _kvm_err(kd, 0, "vatop called in live kernel!"); + return (0); + } + + /* + * This relies upon the kernel text and data being contiguous + * in the first memory segment. + * Other virtual addresses are not reachable yet. + */ + + if (va >= cpup->kernelbase + cpup->kerneloffs && + va < cpup->kernelbase + cpup->kerneloffs + cpup->staticsize) { + *pa = (va - cpup->kernelbase) + + (paddr_t)cpup->ram_segs[0].start; + return (int)(kd->nbpg - (va & (kd->nbpg - 1))); + } + + _kvm_err(kd, 0, "kvm_vatop: va %lx unreachable", va); + return (0); +} + +off_t +_kvm_pa2off(kvm_t *kd, paddr_t pa) +{ + cpu_kcore_hdr_t *cpup = kd->cpu_data; + phys_ram_seg_t *mp = cpup->ram_segs; + off_t off = 0; + int block; + + for (block = 0; block < NPHYS_RAM_SEGS; block++, mp++) { + if (pa >= mp->start && pa < mp->start + mp->size) + return (kd->dump_off + off + + (off_t)(pa - (paddr_t)mp->start)); + off += (off_t)mp->size; + } + + _kvm_err(kd, 0, "not a physical address: %lx", pa); + return (-1); +} diff --git lib/libm/Makefile lib/libm/Makefile index 050cefa5f51..801fbf2edb0 100644 --- lib/libm/Makefile +++ lib/libm/Makefile @@ -127,7 +127,7 @@ CPPFLAGS+= -I${.CURDIR}/src -I${.CURDIR}/src/ld80 SRCS+= ${LONG_SRCS} .endif .if (${MACHINE_CPU} == "mips64") || (${MACHINE_ARCH} == "sparc64") || \ - (${MACHINE_ARCH} == "aarch64") || (${MACHINE_ARCH} == "riscv64") + (${MACHINE_ARCH} == "aarch64") || (${MACHINE_ARCH} == "riscv64") || (${MACHINE_ARCH} == "loongarch64") .PATH: ${.CURDIR}/src/ld128 CPPFLAGS+= -I${.CURDIR}/src -I${.CURDIR}/src/ld128 SRCS+= ${LONG_SRCS} diff --git lib/libm/arch/loongarch64/fenv.c lib/libm/arch/loongarch64/fenv.c new file mode 100644 index 00000000000..7df9a2a815b --- /dev/null +++ lib/libm/arch/loongarch64/fenv.c @@ -0,0 +1,286 @@ +/* $OpenBSD: fenv.c,v 1.4 2022/12/27 17:10:07 jmc Exp $ */ +/*- + * Copyright (c) 2004-2005 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: head/lib/msun/aarch64/fenv.h 280857 2015-03-30 16:42:08Z emaste $ + */ + +#include +#include + +#define __get_fcsr(r) asm volatile("movfcsr2gr %0, $fcsr0" : "=r" (r)) +#define __set_fcsr(r) asm volatile("movgr2fcsr $fcsr0, %0" :: "r" (r)) +#define __get_flags(r) do { \ + unsigned long __tmp; \ + asm volatile("movfcsr2gr %0, $fcsr0" : "=r"(__tmp)); \ + (r) = __tmp & 0xFFUL; \ +} while (0) + +/* Write exception flags (preserve other fields) */ +#define __set_flags(r) do { \ + unsigned long __tmp, __new; \ + asm volatile("movfcsr2gr %0, $fcsr0" : "=r"(__tmp)); \ + __new = (__tmp & ~0xFFUL) | ((unsigned long)(r) & 0xFFUL); \ + asm volatile("movgr2fcsr $fcsr0, %0" :: "r"(__new)); \ +} while (0) + +/* Read rounding mode (bits 10:8 of FCSR) */ +#define __get_frm(r) do { \ + unsigned long __tmp; \ + asm volatile("movfcsr2gr %0, $fcsr0" : "=r"(__tmp)); \ + (r) = (__tmp >> 8) & 0x7UL; \ +} while (0) + +/* Write rounding mode (preserve other fields) */ +#define __set_frm(r) do { \ + unsigned long __tmp, __new; \ + asm volatile("movfcsr2gr %0, $fcsr0" : "=r"(__tmp)); \ + __new = (__tmp & ~(0x7UL << 8)) | \ + (((unsigned long)(r) & 0x7UL) << 8); \ + asm volatile("movgr2fcsr $fcsr0, %0" :: "r"(__new)); \ +} while (0) + + +/* + * The following constant represents the default floating-point environment + * (that is, the one installed at program startup) and has type pointer to + * const-qualified fenv_t. + * + * It can be used as an argument to the functions within the header + * that manage the floating-point environment, namely fesetenv() and + * feupdateenv(). + */ +fenv_t __fe_dfl_env = 0; + +/* + * The feclearexcept() function clears the supported floating-point exceptions + * represented by `excepts'. + */ +int +feclearexcept(int excepts) +{ + fexcept_t r; + + excepts &= FE_ALL_EXCEPT; + __get_flags(r); + r &= ~excepts; + __set_flags(r); + return (0); +} +DEF_STD(feclearexcept); + +/* + * The fegetexceptflag() function stores an implementation-defined + * representation of the states of the floating-point status flags indicated by + * the argument excepts in the object pointed to by the argument flagp. + */ +int +fegetexceptflag(fexcept_t *flagp, int excepts) +{ + fexcept_t r; + + excepts &= FE_ALL_EXCEPT; + __get_flags(r); + *flagp = r & excepts; + return (0); +} + +/* + * The feraiseexcept() function raises the supported floating-point exceptions + * represented by the argument `excepts'. + */ +int +feraiseexcept(int excepts) +{ + fexcept_t r; + + excepts &= FE_ALL_EXCEPT; + __get_flags(r); + r |= excepts; + __set_flags(r); + return (0); +} +DEF_STD(feraiseexcept); + +/* + * This function sets the floating-point status flags indicated by the argument + * `excepts' to the states stored in the object pointed to by `flagp'. It does + * NOT raise any floating-point exceptions, but only sets the state of the flags. + */ +int +fesetexceptflag(const fexcept_t *flagp, int excepts) +{ + fexcept_t r; + + excepts &= FE_ALL_EXCEPT; + __get_flags(r); + r &= ~excepts; + r |= *flagp & excepts; + __set_flags(r); + return (0); +} +DEF_STD(fesetexceptflag); + +/* + * The fetestexcept() function determines which of a specified subset of the + * floating-point exception flags are currently set. The `excepts' argument + * specifies the floating-point status flags to be queried. + */ +int +fetestexcept(int excepts) +{ + fexcept_t r; + + excepts &= FE_ALL_EXCEPT; + __get_flags(r); + return (r & excepts); +} +DEF_STD(fetestexcept); + +/* + * The fegetround() function gets the current rounding direction. + */ +int +fegetround(void) +{ + fenv_t r; + + __get_frm(r); + return (r & _ROUND_MASK); +} +DEF_STD(fegetround); + +/* + * The fesetround() function establishes the rounding direction represented by + * its argument `round'. If the argument is not equal to the value of a rounding + * direction macro, the rounding direction is not changed. + */ +int +fesetround(int round) +{ + fenv_t r; + + if (round & ~_ROUND_MASK) + return (-1); + __set_frm(round); + return (0); +} +DEF_STD(fesetround); + +/* + * The fegetenv() function attempts to store the current floating-point + * environment in the object pointed to by envp. + */ +int +fegetenv(fenv_t *envp) +{ + fenv_t r; + + __get_fcsr(r); + *envp = r; + + return (0); +} +DEF_STD(fegetenv); + +/* + * The feholdexcept() function saves the current floating-point environment + * in the object pointed to by envp, clears the floating-point status flags, and + * then installs a non-stop (continue on floating-point exceptions) mode, if + * available, for all floating-point exceptions. + */ +int +feholdexcept(fenv_t *envp) +{ + fenv_t r; + + __get_fcsr(r); + *envp = r; + r &= ~FE_ALL_EXCEPT; + __set_fcsr(r); + + return (0); +} +DEF_STD(feholdexcept); + +/* + * The fesetenv() function attempts to establish the floating-point environment + * represented by the object pointed to by envp. The argument `envp' points + * to an object set by a call to fegetenv() or feholdexcept(), or equal a + * floating-point environment macro. The fesetenv() function does not raise + * floating-point exceptions, but only installs the state of the floating-point + * status flags represented through its argument. + */ +int +fesetenv(const fenv_t *envp) +{ + + fenv_t r; + r = *envp; + __set_fcsr(r); + return (0); +} +DEF_STD(fesetenv); + +/* + * The feupdateenv() function saves the currently raised floating-point + * exceptions in its automatic storage, installs the floating-point environment + * represented by the object pointed to by `envp', and then raises the saved + * floating-point exceptions. The argument `envp' shall point to an object set + * by a call to feholdexcept() or fegetenv(), or equal a floating-point + * environment macro. + */ +int +feupdateenv(const fenv_t *envp) +{ + fexcept_t r; + + __get_fcsr(r); + fesetenv(envp); + feraiseexcept(r & FE_ALL_EXCEPT); + return (0); +} +DEF_STD(feupdateenv); + +/* + * The following functions are extensions to the standard + */ +int +feenableexcept(int mask) +{ + return -1; +} + +int +fedisableexcept(int mask) +{ + return 0; +} + +int +fegetexcept(void) +{ + return 0; +} diff --git libexec/ld.so/loongarch64/Makefile.inc libexec/ld.so/loongarch64/Makefile.inc new file mode 100644 index 00000000000..41256a7f8e4 --- /dev/null +++ libexec/ld.so/loongarch64/Makefile.inc @@ -0,0 +1,14 @@ +# $OpenBSD: Makefile.inc,v 1.3 2025/05/08 13:57:23 deraadt Exp $ + +CFLAGS += -fpic +CFLAGS += -march=loongarch64 # this prevents the use of float in ld.so +AFLAGS += -D_STANDALONE +AFLAGS += -march=loongarch64 +CPPFLAGS += -I${.CURDIR}/../../lib/libc/arch/loongarch64 +LD_SCRIPT = ${.CURDIR}/${MACHINE_CPU}/ld.script +STACK_PROTECTOR= + +# Suppress DWARF2 warnings +DEBUG?= -gdwarf-4 + +RELATIVE_RELOC=R_LARCH_RELATIVE diff --git libexec/ld.so/loongarch64/SYS.h libexec/ld.so/loongarch64/SYS.h new file mode 100644 index 00000000000..109c49277ea --- /dev/null +++ libexec/ld.so/loongarch64/SYS.h @@ -0,0 +1,55 @@ +/* $OpenBSD: SYS.h,v 1.3 2023/12/11 22:29:25 deraadt Exp $ */ + +/* + * Copyright (c) 2016 Dale Rahn + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include + +#define PINSYSCALL(sysno, label) \ + .pushsection .openbsd.syscalls,"",@progbits ;\ + .p2align 2 ;\ + .long label ;\ + .long sysno ;\ + .popsection + +#define SYSTRAP(x) \ + li.d $t0, SYS_ ## x ;\ +99: syscall 0 ;\ + PINSYSCALL(SYS_ ## x, 99b) + /* XXX fence */ + +#define DL_SYSCALL(n) \ + .global __CONCAT(_dl_,n) ;\ + .type __CONCAT(_dl_,n)%function ;\ +__CONCAT(_dl_,n): ;\ + RETGUARD_SETUP(__CONCAT(_dl_,n), x15) ;\ + SYSTRAP(n) ;\ + beqz $t0, 1f ;\ + sub.d $a0, $zero, $a0 /* r0 = -errno */ ;\ +1: ;\ + RETGUARD_CHECK(__CONCAT(_dl_,n), x15) ;\ + ret diff --git libexec/ld.so/loongarch64/archdep.h libexec/ld.so/loongarch64/archdep.h new file mode 100644 index 00000000000..22c602f6497 --- /dev/null +++ libexec/ld.so/loongarch64/archdep.h @@ -0,0 +1,52 @@ +/* $OpenBSD: archdep.h,v 1.5 2023/11/18 16:26:17 deraadt Exp $ */ + +/* + * Copyright (c) 2021 Dale Rahn + * Copyright (c) 1998 Per Fogelstrom, Opsycon AB + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef _LOONGARCH64_ARCHDEP_H_ +#define _LOONGARCH64_ARCHDEP_H_ + +#define RELOC_TAG DT_RELA +#define MACHID EM_LOONGARCH /* ELF e_machine ID value checked */ + +/* Only used in lib/csu/boot.h */ +#ifdef RCRT0 + +static inline void +RELOC_DYN(const Elf_RelA *r, const Elf_Sym *s, Elf_Addr *p, unsigned long v) +{ + if (ELF_R_TYPE(r->r_info) == R_LARCH_RELATIVE) { + *p = v + r->r_addend; + } else if (ELF_R_TYPE(r->r_info) == R_LARCH_64) { + *p = v + s->st_value + r->r_addend; + } else { + _csu_abort(); + } +} + +#endif /* RCRT0 */ +#endif /* _LOONGARCH64_ARCHDEP_H_ */ diff --git libexec/ld.so/loongarch64/ld.script libexec/ld.so/loongarch64/ld.script new file mode 100644 index 00000000000..91e9dc4adeb --- /dev/null +++ libexec/ld.so/loongarch64/ld.script @@ -0,0 +1,78 @@ +PHDRS +{ + rodata PT_LOAD FILEHDR PHDRS FLAGS (4); + btext PT_LOAD FLAGS (0x08000005); + text PT_LOAD FLAGS (1); + data PT_LOAD; + random PT_OPENBSD_RANDOMIZE; + syscalls PT_OPENBSD_SYSCALLS; + relro PT_GNU_RELRO; + dynamic PT_DYNAMIC; + note PT_NOTE; +} + +SECTIONS +{ + /* RODATA */ + . = 0 + SIZEOF_HEADERS; + .dynsym : { *(.dynsym) } :rodata + .gnu.hash : { *(.gnu.hash) } :rodata + .dynstr : { *(.dynstr) } :rodata + .rodata : { *(.rodata .rodata.*) } :rodata + .eh_frame : { *(.eh_frame) } :rodata + + /* TEXT */ + . = ALIGN(0x10000); + .boot.text : + { + . = ALIGN(0x1000); + boot_text_start = .; + *(.boot.text) + . = ALIGN(0x1000); + boot_text_end = .; + } :btext + . = ALIGN(0x1000); + .text : { *(.text .text.*) } :text + + /* RELRO DATA */ + . = DATA_SEGMENT_ALIGN (0x10000, 0x1000); + .openbsd.randomdata : + { + *(.openbsd.randomdata .openbsd.randomdata.*) + } :data :relro :random + .openbsd.syscalls : + { + *(.openbsd.syscalls .openbsd.syscalls.*) + } :syscalls + + .data.rel.ro : { *(.data.rel.ro.local*) *(.data.rel.ro*) } :data :relro + .dynamic : { *(.dynamic) } :data :relro :dynamic + .got : { *(.got.plt) *(.got) } :data :relro + . = DATA_SEGMENT_RELRO_END (0, .); + + /* BOOTDATA */ + . = ALIGN(0x1000); + boot_data_start = .; + .rela.dyn : + { + *(.rela.text .rela.text.*) + *(.rela.rodata .rela.rodata.*) + *(.rela.data .rela.data.*) + *(.rela.got) + *(.rela.bss .rela.bss.*) + } :data +/* XXX .rela.plt is unused but cannot delete: ld.bfd zeros DT_RELASZ then! */ + .rela.plt : { *(.rela.plt) } :data + .hash : { *(.hash) } :data + .note : { *(.note.openbsd.*) } :data :note + .boot.data : { *(.boot.data .boot.data.*) } :data + boot_data_end = .; + + /* DATA */ + . = ALIGN(0x1000); + .data : { *(.data .data.*) } :data + .bss : { *(.dynbss) *(.bss .bss.*) *(COMMON) } :data + . = DATA_SEGMENT_END (.); + + /DISCARD/ : { *(.note.GNU-stack) } +} diff --git libexec/ld.so/loongarch64/ldasm.S libexec/ld.so/loongarch64/ldasm.S new file mode 100644 index 00000000000..e28e06c12da --- /dev/null +++ libexec/ld.so/loongarch64/ldasm.S @@ -0,0 +1,123 @@ +/* $OpenBSD: ldasm.S,v 1.3 2021/06/26 14:50:25 kettenis Exp $ */ + +/* + * Copyright (c) 2016,2021 Dale Rahn + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#define DL_DATA_SIZE (16 * 8) /* needs to be 8(16?) byte aligned */ +#include +#include + + .option norelax + .section .boot.text,"ax",@progbits + _ALIGN_TEXT + .globl _dl_start + .type _dl_start,@function +_dl_start: + move $a0, $sp + move $fp, $sp + + addi.d $sp, $sp, -(8+8+DL_DATA_SIZE) // dl_data size + addi.d $s8, $sp, 8 // dl_data + + move $a1, $s8 // dl_data + +1: pcalau12i $a2, %pc_hi20(_DYNAMIC) /* &_DYNAMIC */ + addi.d $a2, $a2, %pc_lo12(1b) + + bl _dl_boot_bind + + ld.d $a0, $fp, 0 // load argc + addi.d $a1, $fp, 0x0008 // argv + slli.d $a2, $a0, 0x3 + add.d $a2, $a1, $a2 + addi.d $a2, $a2, 0x0008 // compute envp into a2 + + // _dl_boot(argv, envp, loff, dl_data) + move $a0, $a1 // argv + move $a1, $a2 // envp + ld.d $a2, $s8, (7*8) + move $a3, $s8 // dl_data + + b _dl_boot + + move $sp, $fp // move stack back + move $fp, $zero // clear frame back pointer + +2: pcalau12i $a3, %pc_hi20(_dl_dtors) /* cleanup */ + addi.d $a3, $a3, %pc_lo12(2b) + + jr $a0 +END(_dl_start) + +ENTRY(_dl_bind_start) + /* + * t0 is the "link map" + * t1 is the .got.plt offset + */ + + /* save parameter/result registers */ + addi.d $sp, $sp, -(10*8) /* should be aligned well enough */ + st.d $ra, $sp, (9*8) + st.d $a0, $sp, (0*8) + st.d $a1, $sp, (1*8) + st.d $a2, $sp, (2*8) + st.d $a3, $sp, (3*8) + st.d $a4, $sp, (4*8) + st.d $a5, $sp, (5*8) + st.d $a6, $sp, (6*8) + st.d $a7, $sp, (7*8) + + /* + * no need to save the FP registers as ld.so is compiled such that + * it doesn't touch them + */ + + move $a0, $t0 + srli.d $a1, $t1, 3 + b _dl_bind + move $t0, $a0 + + /* restore parameter/result registers */ + ld.d $a0, $sp, (0*8) + ld.d $a1, $sp, (1*8) + ld.d $a2, $sp, (2*8) + ld.d $a3, $sp, (3*8) + ld.d $a4, $sp, (4*8) + ld.d $a5, $sp, (5*8) + ld.d $a6, $sp, (6*8) + ld.d $a7, $sp, (7*8) + ld.d $ra, $sp, (9*8) + addi.d $sp, $sp, (10*8) + + jr $t0 +END(_dl_bind_start) + +ENTRY(_rtld_tlsdesc) + RETGUARD_SETUP(_rtld_tlsdesc, x15) + ld.d $a0, $a0, 8 + RETGUARD_CHECK(_rtld_tlsdesc, x15) + ret +END(_rtld_tlsdesc) diff --git libexec/ld.so/loongarch64/rtld_machine.c libexec/ld.so/loongarch64/rtld_machine.c new file mode 100644 index 00000000000..7028b9970fe --- /dev/null +++ libexec/ld.so/loongarch64/rtld_machine.c @@ -0,0 +1,304 @@ +/* $OpenBSD: rtld_machine.c,v 1.5 2026/07/16 11:21:37 tb Exp $ */ + +/* + * Copyright (c) 2004,2021 Dale Rahn + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#define _DYN_LOADER + +#include +#include +#include +#include + +#include + +#include "util.h" +#include "resolve.h" + +int64_t pcookie __attribute__((section(".openbsd.randomdata"))) __dso_hidden; +#define R_TYPE(x) R_LARCH_ ## x + +void _dl_bind_start(void); /* XXX */ +Elf_Addr _dl_bind(elf_object_t *object, int index); +#define _RF_S 0x80000000 /* Resolve symbol */ +#define _RF_A 0x40000000 /* Use addend */ +#define _RF_P 0x20000000 /* Location relative */ +#define _RF_G 0x10000000 /* GOT offset */ +#define _RF_B 0x08000000 /* Load address relative */ +#define _RF_V 0x02000000 /* ERROR */ +#define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */ +#define _RF_RS(s) ((s) & 0xff) /* right shift */ +static const int reloc_target_flags[] = { + [ R_TYPE(NONE) ] = 0, + [ R_TYPE(32) ] = + _RF_V|_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* GLOB_DAT */ + [ R_TYPE(64) ] = + _RF_V|_RF_S|_RF_A| _RF_SZ(64) | _RF_RS(0), /* GLOB_DAT */ + [ R_TYPE(JUMP_SLOT) ] = + _RF_V|_RF_S| _RF_SZ(64) | _RF_RS(0), /* JUMP_SLOT */ + [ R_TYPE(RELATIVE) ] = + _RF_V|_RF_B|_RF_A| _RF_SZ(64) | _RF_RS(0), /* REL64 */ +// [ R_TYPE(TLSDESC) ] = _RF_V|_RF_S, + [ R_TYPE(TLS_TPREL64) ] = _RF_V|_RF_S, + [ R_TYPE(COPY) ] = + _RF_V|_RF_S| _RF_SZ(32) | _RF_RS(0), /* 20 COPY */ + +}; + +#define RELOC_RESOLVE_SYMBOL(t) ((reloc_target_flags[t] & _RF_S) != 0) +#define RELOC_PC_RELATIVE(t) ((reloc_target_flags[t] & _RF_P) != 0) +#define RELOC_BASE_RELATIVE(t) ((reloc_target_flags[t] & _RF_B) != 0) +#define RELOC_USE_ADDEND(t) ((reloc_target_flags[t] & _RF_A) != 0) +#define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff) +#define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff) + +static const Elf_Addr reloc_target_bitmask[] = { +#define _BM(x) (~(Elf_Addr)0 >> ((8*sizeof(reloc_target_bitmask[0])) - (x))) + [ R_TYPE(NONE) ] = 0, + [ R_TYPE(32) ] = _BM(32), + [ R_TYPE(64) ] = _BM(64), + [ R_TYPE(JUMP_SLOT) ] = _BM(64), + [ R_TYPE(RELATIVE) ] = _BM(64), +// [ R_TYPE(TLSDESC) ] = _BM(64), + [ R_TYPE(TLS_TPREL64) ] = _BM(64), + [ R_TYPE(COPY) ] = _BM(64), +#undef _BM +}; +#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t]) + + +void _dl_reloc_plt(Elf_Word *where, Elf_Addr value, Elf_RelA *rel); + +int +_dl_md_reloc(elf_object_t *object, int rel, int relsz) +{ + long i; + long numrel; + long relrel; + int fails = 0; + Elf_Addr loff; + Elf_Addr prev_value = 0; + const Elf_Sym *prev_sym = NULL; + Elf_RelA *rels; + + loff = object->obj_base; + numrel = object->Dyn.info[relsz] / sizeof(Elf_RelA); + relrel = rel == DT_RELA ? object->relcount : 0; + rels = (Elf_RelA *)(object->Dyn.info[rel]); + + if (rels == NULL) + return 0; + + if (relrel > numrel) + _dl_die("relcount > numrel: %ld > %ld", relrel, numrel); + + /* tight loop for leading RELATIVE relocs */ + for (i = 0; i < relrel; i++, rels++) { + Elf_Addr *where; + + where = (Elf_Addr *)(rels->r_offset + loff); + *where += loff; + } + for (; i < numrel; i++, rels++) { + Elf_Addr *where, value, mask; + Elf_Word type; + const Elf_Sym *sym; + const char *symn; + + type = ELF_R_TYPE(rels->r_info); + + if (type >= nitems(reloc_target_flags) || + (reloc_target_flags[type] & _RF_V) == 0) + _dl_die("bad relocation %ld %d", i, type); + + if (type == R_TYPE(NONE)) + continue; + + if (type == R_TYPE(JUMP_SLOT) && rel != DT_JMPREL) + continue; + + where = (Elf_Addr *)(rels->r_offset + loff); + + if (RELOC_USE_ADDEND(type)) + value = rels->r_addend; + else + value = 0; + + sym = NULL; + symn = NULL; + if (RELOC_RESOLVE_SYMBOL(type)) { + sym = object->dyn.symtab; + sym += ELF_R_SYM(rels->r_info); + symn = object->dyn.strtab + sym->st_name; + + if (sym->st_shndx != SHN_UNDEF && + ELF_ST_BIND(sym->st_info) == STB_LOCAL) { + value += loff; + } else if (sym == prev_sym) { + value += prev_value; + } else { + struct sym_res sr; + + sr = _dl_find_symbol(symn, + SYM_SEARCH_ALL|SYM_WARNNOTFOUND| + ((type == R_TYPE(JUMP_SLOT)) ? + SYM_PLT : SYM_NOTPLT), sym, object); + if (sr.sym == NULL) { +resolve_failed: + if (ELF_ST_BIND(sym->st_info) != + STB_WEAK) + fails++; + continue; + } + prev_sym = sym; + prev_value = (Elf_Addr)(sr.obj->obj_base + + sr.sym->st_value); + value += prev_value; + } + } + + if (type == R_TYPE(JUMP_SLOT)) { + /* + _dl_reloc_plt((Elf_Word *)where, value, rels); + */ + *where = value; + continue; + } + + if (type == R_TYPE(COPY)) { + void *dstaddr = where; + const void *srcaddr; + const Elf_Sym *dstsym = sym; + struct sym_res sr; + + sr = _dl_find_symbol(symn, + SYM_SEARCH_OTHER|SYM_WARNNOTFOUND|SYM_NOTPLT, + dstsym, object); + if (sr.sym == NULL) + goto resolve_failed; + + srcaddr = (void *)(sr.obj->obj_base + sr.sym->st_value); + _dl_bcopy(srcaddr, dstaddr, dstsym->st_size); + continue; + } + + if (RELOC_PC_RELATIVE(type)) + value -= (Elf_Addr)where; + if (RELOC_BASE_RELATIVE(type)) + value += loff; + + mask = RELOC_VALUE_BITMASK(type); + value >>= RELOC_VALUE_RIGHTSHIFT(type); + value &= mask; + + *where &= ~mask; + *where |= value; + } + + return fails; +} + +/* + * Relocate the Global Offset Table (GOT). + * This is done by calling _dl_md_reloc on DT_JMPREL for DL_BIND_NOW, + * otherwise the lazy binding plt initialization is performed. + */ +int +_dl_md_reloc_got(elf_object_t *object, int lazy) +{ + int fails = 0; + Elf_Addr *pltgot = (Elf_Addr *)object->Dyn.info[DT_PLTGOT]; + int i, num; + Elf_RelA *rel; + + if (object->Dyn.info[DT_PLTREL] != DT_RELA) + return 0; + + if (!lazy) { + fails = _dl_md_reloc(object, DT_JMPREL, DT_PLTRELSZ); + } else { + rel = (Elf_RelA *)(object->Dyn.info[DT_JMPREL]); + num = (object->Dyn.info[DT_PLTRELSZ]); + + for (i = 0; i < num/sizeof(Elf_RelA); i++, rel++) { + Elf_Addr *where; + where = (Elf_Addr *)(rel->r_offset + object->obj_base); + *where += object->obj_base; + } + + pltgot[0] = (Elf_Addr)_dl_bind_start; + pltgot[1] = (Elf_Addr)object; + } + + return fails; +} + +Elf_Addr +_dl_bind(elf_object_t *object, int relidx) +{ + Elf_RelA *rel; + const Elf_Sym *sym; + const char *symn; + struct sym_res sr; + int64_t cookie = pcookie; + struct { + struct __kbind param; + Elf_Addr newval; + } buf; + + rel = ((Elf_RelA *)object->Dyn.info[DT_JMPREL]) + (relidx); + + sym = object->dyn.symtab; + sym += ELF_R_SYM(rel->r_info); + symn = object->dyn.strtab + sym->st_name; + + sr = _dl_find_symbol(symn, SYM_SEARCH_ALL|SYM_WARNNOTFOUND|SYM_PLT, + sym, object); + if (sr.sym == NULL) + _dl_die("lazy binding failed for %s", symn); + + buf.newval = sr.obj->obj_base + sr.sym->st_value; + + if (sr.obj->traced && _dl_trace_plt(sr.obj, symn)) + return buf.newval; + + buf.param.kb_addr = (Elf_Word *)(object->obj_base + rel->r_offset); + buf.param.kb_size = sizeof(Elf_Addr); + + /* directly code the syscall, so that it's actually inline here */ + { + register long syscall_num __asm("$t0") = SYS_kbind; + register void *arg1 __asm("$a0") = &buf; + register long arg2 __asm("$a1") = sizeof(buf); + register long arg3 __asm("$a2") = cookie; + + __asm volatile("syscall 0" : "+r" (arg1), "+r" (arg2) + : "r" (syscall_num), "r" (arg3) + : "cc", "memory"); + } + + return buf.newval; +} diff --git share/mk/bsd.own.mk share/mk/bsd.own.mk index 49f667224ab..26db47dce17 100644 --- share/mk/bsd.own.mk +++ share/mk/bsd.own.mk @@ -15,13 +15,13 @@ SKEY?= yes # Set `YP' to `yes' to build with support for NIS/YP. YP?= yes -CLANG_ARCH=aarch64 amd64 arm i386 mips64 mips64el powerpc powerpc64 riscv64 sparc64 +CLANG_ARCH=aarch64 amd64 arm i386 mips64 mips64el powerpc powerpc64 riscv64 sparc64 loongarch64 GCC4_ARCH=alpha hppa m88k sh -LLD_ARCH=aarch64 amd64 arm i386 powerpc powerpc64 riscv64 sparc64 -LLDB_ARCH=aarch64 amd64 +LLD_ARCH=aarch64 amd64 arm i386 powerpc powerpc64 riscv64 sparc64 loongarch64 +LLDB_ARCH=aarch64 amd64 loongarch64 # Can't use ${CLANG_ARCH} ${GCC4_ARCH} below because of sparc64 -PIE_ARCH=aarch64 alpha amd64 arm hppa i386 m88k mips64 mips64el powerpc powerpc64 riscv64 sh sparc64 +PIE_ARCH=aarch64 alpha amd64 arm hppa i386 m88k mips64 mips64el powerpc powerpc64 riscv64 sh sparc64 loongarch64 STATICPIE_ARCH=${PIE_ARCH} .for _arch in ${MACHINE_ARCH} diff --git sys/Makefile sys/Makefile index 8eb592e2c13..44f03ad8461 100644 --- sys/Makefile +++ sys/Makefile @@ -6,7 +6,7 @@ SUBDIR= dev/microcode \ arch/hppa arch/i386 \ arch/landisk arch/luna88k \ arch/macppc arch/octeon arch/powerpc64 \ - arch/riscv64 arch/sparc64 + arch/riscv64 arch/sparc64 arch/loongarch64 tags: cd ${.CURDIR}/kern; make tags diff --git sys/arch/loongarch64/Makefile sys/arch/loongarch64/Makefile new file mode 100644 index 00000000000..e728334b24a --- /dev/null +++ sys/arch/loongarch64/Makefile @@ -0,0 +1,50 @@ +# $OpenBSD: Makefile,v 1.1 2021/04/23 02:42:16 drahn Exp $ + +.include # for KEEPKERNELS + +S= ${.CURDIR}/../.. +KFILE= GENERIC +.if exists(conf/GENERIC.MP) +KFILE= GENERIC.MP +.endif +TDIRS= ${_arch} include +TAGS= ${.CURDIR}/tags + +NOPROG= +NOMAN= +NOOBJ= +SUBDIR= stand +.if !defined(KEEPKERNELS) || !(make(clean) || make(cleandir)) +SUBDIR+=compile +.endif + +# config the fattest kernel we can find into a temporary dir +# to create a Makefile. Then use make to pull some variables +# out and push them into the sub-shell to expand the paths, +# and finally run ctags. +tags:: + TDIR=`mktemp -d /tmp/_tagXXXXXXXXXX` || exit 1; \ + eval "S=${S}" && \ + config -s ${S} -b $${TDIR} ${.CURDIR}/conf/${KFILE} && \ + eval "_arch=\"`make -V _arch -f $${TDIR}/Makefile`\"" && \ + eval "_mach=\"`make -V _mach -f $${TDIR}/Makefile`\"" && \ + eval "_machdir=\$S/arch/$${_mach}" && \ + eval "_archdir=\$S/arch/$${_arch}" && \ + eval "HFILES=\"`find $S \( -path $S/'arch' -o -path $S/stand -o -path $S/lib/libsa -o -path $S'/lib/libkern/arch' \) -prune -o -name '*.h'; find $${_machdir} $${_archdir} $S/lib/libkern/arch/$${_mach} \( -name boot -o -name stand \) -prune -o -name '*.h'`\"" && \ + eval "SFILES=\"`make -V SFILES -f $${TDIR}/Makefile`\"" && \ + eval "CFILES=\"`make -V CFILES -f $${TDIR}/Makefile`\"" && \ + eval "AFILES=\"`make -V AFILES -f $${TDIR}/Makefile`\"" && \ + ctags -wd -f ${TAGS} $${CFILES} $${HFILES} && \ + egrep "^[_A-Z]*ENTRY[_A-Z]*\(.*\)" $${SFILES} $${AFILES} | \ + sed "s;\\([^:]*\\):\\([^(]*\\)(\\([^, )]*\\)\\(.*\\);\\3 \\1 /^\\2(\\3\\4$$/;" \ + >> ${TAGS} && \ + sort -o ${TAGS} ${TAGS} && \ + rm -rf $${TDIR} + +links: + -for i in conf ${TDIRS}; do \ + (cd $$i && rm -f tags; ln -s tags tags); done + +obj: _SUBDIRUSE + +.include diff --git sys/arch/loongarch64/compile/GENERIC.MP/Makefile sys/arch/loongarch64/compile/GENERIC.MP/Makefile new file mode 100644 index 00000000000..01b5f23410c --- /dev/null +++ sys/arch/loongarch64/compile/GENERIC.MP/Makefile @@ -0,0 +1 @@ +.include "../Makefile.inc" diff --git sys/arch/loongarch64/compile/GENERIC/Makefile sys/arch/loongarch64/compile/GENERIC/Makefile new file mode 100644 index 00000000000..01b5f23410c --- /dev/null +++ sys/arch/loongarch64/compile/GENERIC/Makefile @@ -0,0 +1 @@ +.include "../Makefile.inc" diff --git sys/arch/loongarch64/compile/Makefile sys/arch/loongarch64/compile/Makefile new file mode 100644 index 00000000000..083237cf07b --- /dev/null +++ sys/arch/loongarch64/compile/Makefile @@ -0,0 +1,7 @@ +# $OpenBSD: Makefile,v 1.1 2021/04/23 02:42:16 drahn Exp $ + +.if make(obj) || make(clean) || make(cleandir) +SUBDIR!=find . -type d -maxdepth 1 \! \( -name . -o -name CVS \) | cut -b3- +.endif + +.include diff --git sys/arch/loongarch64/compile/Makefile.inc sys/arch/loongarch64/compile/Makefile.inc new file mode 100644 index 00000000000..9e9e38f1ed1 --- /dev/null +++ sys/arch/loongarch64/compile/Makefile.inc @@ -0,0 +1,19 @@ +SYSDIR != cd ${.CURDIR}/../../../..; pwd +CONFDIR != cd ${.CURDIR}/../../conf; pwd + +.if ${.CURDIR} == ${.OBJDIR} +.PHONY: config +config: + @echo make obj required first >&2 + @false +.else +.PHONY: config clean +config: + config ${.CURDIR:M*.PROF:C/.*/-p/} -b ${.OBJDIR} \ + -s ${SYSDIR} ${CONFDIR}/${.CURDIR:T:S/.PROF$//} +.endif + +cleandir clean: + +.include + diff --git sys/arch/loongarch64/compile/RAMDISK/Makefile sys/arch/loongarch64/compile/RAMDISK/Makefile new file mode 100644 index 00000000000..01b5f23410c --- /dev/null +++ sys/arch/loongarch64/compile/RAMDISK/Makefile @@ -0,0 +1 @@ +.include "../Makefile.inc" diff --git sys/arch/loongarch64/conf/GENERIC sys/arch/loongarch64/conf/GENERIC new file mode 100644 index 00000000000..7a38c67f0e0 --- /dev/null +++ sys/arch/loongarch64/conf/GENERIC @@ -0,0 +1,266 @@ +# $OpenBSD: GENERIC,v 1.66 2026/07/24 10:51:01 kettenis Exp $ +# +# For further information on compiling OpenBSD kernels, see the config(8) +# man page. +# +# For further information on hardware support for this architecture, see +# the intro(4) man page. For further information about kernel options +# for this architecture, see the options(4) man page. For an explanation +# of each device driver in this file see the section 4 man page for the +# device. + +machine loongarch64 +include "../../../conf/GENERIC" +maxusers 80 + +option PCIVERBOSE +option USER_PCICONF +option USBVERBOSE + +makeoptions KERNEL_BASE_PHYS="0x90000000" +makeoptions KERNEL_BASE_VIRT="0xffffffe000200000" +#option DEBUG +#option DEBUG_AUTOCONF +#option DEBUG_INTC + +option WSDISPLAY_COMPAT_USL +option WSDISPLAY_COMPAT_RAWKBD +option WSDISPLAY_DEFAULTSCREENS=6 + + +config bsd swap generic + +# +# Definition of system +# + +# mainbus +mainbus0 at root + +# cpu0 +cpu0 at mainbus0 +intc0 at cpu0 + +# NS16550 compatible serial ports +com* at fdt? + +virtio* at fdt? +virtio* at pci? +vio* at virtio? # Network +vioblk* at virtio? +vioscsi* at virtio? # Disk (SCSI) +#viomb* at virtio? # Memory Ballooning +viornd* at virtio? # Random Source + +# simplebus0 +simplebus* at fdt? + +syscon* at fdt? early 1 +gfrtc* at fdt? +gpiorestart* at fdt? +gpioleds* at fdt? + +ohci* at fdt? +ehci* at fdt? + +cad* at fdt? +dwge* at fdt? +dwqe* at fdt? +dwxe* at fdt? +dwiic* at fdt? +iic* at dwiic? +dwmmc* at fdt? +sdmmc* at dwmmc? + +cdpcie* at fdt? +pci* at cdpcie? +dwpcie* at fdt? +pci* at dwpcie? +pciecam* at fdt? +pci* at pciecam? + +ociic* at fdt? +iic* at ociic? +dapmic* at iic? +titmp* at iic? + +xhci* at fdt? + +# PCI +ppb* at pci? # PCI-PCI bridges +pci* at ppb? + +# DRM devices + +# PCI Ethernet +em* at pci? # Intel Pro/1000 Ethernet +bge* at pci? # Broadcom BCM57xx (aka Tigon3) +oce* at pci? # Emulex OneConnect 10Gb ethernet +aq* at pci? # Aquantia aQtion Ethernet +ix* at pci? # Intel 82598EB 10Gb ethernet +ixl* at pci? # Intel Ethernet 700 Series +igc* at pci? # Intel I225 Ethernet +rge* at pci? # Realtek 8125 + +# Wireless network cards +iwm* at pci? # Intel WiFi Link 7xxx +iwx* at pci? # Intel WiFi Link 22xxx + +nvme* at pci? # NVMe controllers +ahci* at pci? # AHCI SATA controllers + +scsibus* at scsi? +sd* at scsibus? +cd* at scsibus? +ch* at scsibus? +uk* at scsibus? + +# USB Controllers +xhci* at pci? + +# USB bus support +usb* at ohci? +usb* at ehci? +usb* at xhci? + +# USB devices +uhub* at usb? # USB Hubs +uhub* at uhub? # USB Hubs +urng* at uhub? # USB Random Number Generator +uonerng* at uhub? # Moonbase Otago OneRNG +umodem* at uhub? # USB Modems/Serial +ucom* at umodem? +uvisor* at uhub? # Handspring Visor +ucom* at uvisor? +uvscom* at uhub? # SUNTAC Slipper U VS-10U serial +ucom* at uvscom? +ubsa* at uhub? # Belkin serial adapter +ucom* at ubsa? +uftdi* at uhub? # FTDI FT8U100AX serial adapter +ucom* at uftdi? +uplcom* at uhub? # I/O DATA USB-RSAQ2 serial adapter +ucom* at uplcom? +umct* at uhub? # MCT USB-RS232 serial adapter +ucom* at umct? +uslcom* at uhub? # Silicon Laboratories CP210x serial +ucom* at uslcom? +uscom* at uhub? # Simple USB serial adapters +ucom* at uscom? +ucrcom* at uhub? # Chromebook serial +ucom* at ucrcom? +uark* at uhub? # Arkmicro ARK3116 serial +ucom* at uark? +moscom* at uhub? # MosChip MCS7703 serial +ucom* at moscom? +umcs* at uhub? # MosChip MCS78x0 serial +ucom* at umcs? +uipaq* at uhub? # iPAQ serial adapter +ucom* at uipaq? +umsm* at uhub? # Qualcomm MSM EVDO +ucom* at umsm? +uchcom* at uhub? # WinChipHead CH341/340 serial +ucom* at uchcom? +uticom* at uhub? # TI serial +ucom* at uticom? +uxrcom* at uhub? # Exar XR21V1410 serial +ucom* at uxrcom? +uaudio* at uhub? # USB Audio +audio* at uaudio? +umidi* at uhub? # USB MIDI +midi* at umidi? +ulpt* at uhub? # USB Printers +umass* at uhub? # USB Mass Storage devices +uhidev* at uhub? # Human Interface Devices +ums* at uhidev? # USB mouse +wsmouse* at ums? mux 0 +umt* at uhidev? # USB multitouch touchpad +wsmouse* at umt? mux 0 +uts* at uhub? # USB touchscreen +wsmouse* at uts? mux 0 +uwacom* at uhidev? # USB Wacom tablet +wsmouse* at uwacom? mux 0 +ukbd* at uhidev? # USB keyboard +wskbd* at ukbd? mux 1 +ucycom* at uhidev? # Cypress serial +ucom* at ucycom? +uslhcom* at uhidev? # Silicon Labs CP2110 USB HID UART +ucom* at uslhcom? +uhid* at uhidev? # USB generic HID support +fido* at uhidev? # FIDO/U2F security key support +ucc* at uhidev? # Consumer Control keyboards +wskbd* at ucc? mux 1 +ujoy* at uhidev? # USB joystick/gamecontroller support +uhidpp* at uhidev? # Logitech HID++ Devices +upd* at uhidev? # USB Power Devices sensors +aue* at uhub? # ADMtek AN986 Pegasus Ethernet +atu* at uhub? # Atmel AT76c50x based 802.11b +axe* at uhub? # ASIX Electronics AX88172 USB Ethernet +axen* at uhub? # ASIX Electronics AX88179 USB Ethernet +cue* at uhub? # CATC USB-EL1201A based Ethernet +kue* at uhub? # Kawasaki KL5KUSB101B based Ethernet +smsc* at uhub? # SMSC LAN95xx Ethernet +cdce* at uhub? # CDC Ethernet +urndis* at uhub? # Remote NDIS Ethernet +upl* at uhub? # Prolific PL2301/PL2302 host-to-host `network' +ugl* at uhub? # Genesys Logic GL620USB-A host-to-host `network' +udav* at uhub? # Davicom DM9601 based Ethernet +mos* at uhub? # MOSCHIP MCS7730/7830 10/100 Ethernet +mue* at uhub? # Microchip LAN75xx/LAN78xx Ethernet +url* at uhub? # Realtek RTL8150L based adapters +ure* at uhub? # Realtek RTL8152 based adapters +udsbr* at uhub? # D-Link DSB-R100 radio +radio* at udsbr? # USB radio +uberry* at uhub? # Research In Motion BlackBerry +ugen* at uhub? # USB Generic driver +uath* at uhub? # Atheros AR5005UG/AR5005UX +ural* at uhub? # Ralink RT2500USB +rum* at uhub? # Ralink RT2501USB/RT2601USB +run* at uhub? # Ralink RT2700U/RT2800U/RT3000U +mtw* at uhub? # MediaTek MT7601U +otus* at uhub? # Atheros AR9001U +athn* at uhub? # Atheros AR9002U +zyd* at uhub? # Zydas ZD1211 +upgt* at uhub? # Conexant/Intersil PrismGT SoftMAC USB +urtw* at uhub? # Realtek 8187 +rsu* at uhub? # Realtek RTL8188SU/RTL8191SU/RTL8192SU +urtwn* at uhub? # Realtek RTL8188CU/RTL8192CU +udcf* at uhub? # Gude Expert mouseCLOCK +umb* at uhub? # Mobile Broadband Interface Model +uthum* at uhidev? # TEMPerHUM sensor +ugold* at uhidev? # gold TEMPer sensor +utrh* at uhidev? # USBRH sensor +utwitch* at uhidev? # YUREX BBU sensor +uoakrh* at uhidev? # Toradex OAK temp and rel humidity +uoaklux* at uhidev? # Toradex OAK LUX +uoakv* at uhidev? # Toradex OAK 10V sensor +uvideo* at uhub? # USB Video +video* at uvideo? +utvfu* at uhub? # Fushicai Audio-Video Grabber +video* at utvfu? +audio* at utvfu? +udl* at uhub? # DisplayLink USB displays +wsdisplay* at udl? +bwfm* at uhub? # Broadcom FullMAC + +acphy* at mii? # Altima AC101 PHYs +amphy* at mii? # AMD 79C873 PHYs +atphy* at mii? # Attansic F1 PHYs +bmtphy* at mii? # Broadcom 10/100 PHYs +brgphy* at mii? # Broadcom Gigabit PHYs +eephy* at mii? # Marvell 88E1000 series PHY +rgephy* at mii? # Realtek 8169S/8110S PHY +rlphy* at mii? # Realtek 8139 internal PHYs +sqphy* at mii? # Seeq 8x220 PHYs +ukphy* at mii? # "unknown" PHYs +urlphy* at mii? # Realtek RTL8150L internal PHY +ytphy* at mii? # MotorComm YT8511 PHY + +# I2C devices +axppmic* at iic? # AXP15060 PMIC + +# Pseudo-Devices +pseudo-device openprom +pseudo-device hotplug 1 # devices hot plugging + +# mouse & keyboard multiplexor pseudo-devices +pseudo-device wsmux 2 diff --git sys/arch/loongarch64/conf/GENERIC.MP sys/arch/loongarch64/conf/GENERIC.MP new file mode 100644 index 00000000000..ca41d0b330f --- /dev/null +++ sys/arch/loongarch64/conf/GENERIC.MP @@ -0,0 +1,9 @@ +# $OpenBSD: GENERIC.MP,v 1.1 2021/06/29 21:27:52 kettenis Exp $ + +include "arch/loongarch64/conf/GENERIC" + +option MULTIPROCESSOR +#option MP_LOCKDEBUG +#option WITNESS + +cpu* at mainbus? diff --git sys/arch/loongarch64/conf/Makefile.loongarch64 sys/arch/loongarch64/conf/Makefile.loongarch64 new file mode 100644 index 00000000000..6d0b6e5dd9b --- /dev/null +++ sys/arch/loongarch64/conf/Makefile.loongarch64 @@ -0,0 +1,178 @@ +# $OpenBSD: Makefile.loongarch64,v 1.24 2025/07/05 19:03:02 kn Exp $ + +# For instructions on building kernels consult the config(8) and options(4) +# manual pages. +# +# N.B.: NO DEPENDENCIES ON FOLLOWING FLAGS ARE VISIBLE TO MAKEFILE +# IF YOU CHANGE THE DEFINITION OF ANY OF THESE RECOMPILE EVERYTHING +# DEBUG is set to -g by config if debugging is requested (config -g). +# PROF is set to -pg by config if profiling is requested (config -p). + +.include + +SIZE?= size +STRIP?= ctfstrip + +# source tree is located via $S relative to the compilation directory +.ifndef S +S!= cd ../../../..; pwd +.endif + +_machdir?= $S/arch/${_mach} +_archdir?= $S/arch/${_arch} + +INCLUDES= -nostdinc -I$S -I${.OBJDIR} -I$S/arch \ + -I$S/dev/pci/drm/include \ + -I$S/dev/pci/drm/include/uapi +CPPFLAGS= ${INCLUDES} ${IDENT} ${PARAM} -D_KERNEL -D__${_mach}__ -MD -MP +CWARNFLAGS= -Werror -Wall -Wimplicit-function-declaration \ + -Wno-pointer-sign \ + -Wno-constant-conversion -Wno-address-of-packed-member \ + -Wno-unused-but-set-variable -Wno-gnu-folding-constant \ + -Wframe-larger-than=2047 + +CMACHFLAGS= -march=loongarch64 -mno-relax \ + -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer +CMACHFLAGS+= -ffreestanding ${NOPIE_FLAGS} +SORTR= sort -R +.if ${IDENT:M-DNO_PROPOLICE} +CMACHFLAGS+= -fno-stack-protector +.endif +.if ${IDENT:M-DSMALL_KERNEL} +SORTR= cat +COPTIMIZE?= -Oz +.endif + +DEBUG?= -g +COPTIMIZE?= -O2 +CFLAGS= ${DEBUG} ${CWARNFLAGS} ${CMACHFLAGS} ${COPTIMIZE} ${COPTS} ${PIPE} +AFLAGS= -D_LOCORE -x assembler-with-cpp ${CWARNFLAGS} ${CMACHFLAGS} +LINKFLAGS= -T ld.script -X --warn-common -nopie +# propagate failure like ENOSPC on relink +LINKFLAGS+= --no-mmap-output-file + +HOSTCC?= ${CC} +HOSTED_CPPFLAGS=${CPPFLAGS:S/^-nostdinc$//} +HOSTED_CFLAGS= ${CFLAGS} +HOSTED_C= ${HOSTCC} ${HOSTED_CFLAGS} ${HOSTED_CPPFLAGS} -c $< + +NORMAL_C_NOP= ${CC} ${CFLAGS} ${CPPFLAGS} -fno-ret-protector -c $< +NORMAL_C= ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c $< +NORMAL_S= ${CC} ${AFLAGS} ${CPPFLAGS} ${PROF} -c $< + +%OBJS + +%CFILES + +%SFILES + +# load lines for config "xxx" will be emitted as: +# xxx: ${SYSTEM_DEP} swapxxx.o +# ${SYSTEM_LD_HEAD} +# ${SYSTEM_LD} swapxxx.o +# ${SYSTEM_LD_TAIL} +SYSTEM_HEAD= locore0.o gap.o +SYSTEM_OBJ= ${SYSTEM_HEAD} ${OBJS} param.o ioconf.o +SYSTEM_DEP= Makefile ${SYSTEM_OBJ} ld.script +SYSTEM_LD_HEAD= @rm -f $@ +SYSTEM_LD= @echo ${LD} ${LINKFLAGS} -o $@ '$${SYSTEM_HEAD} vers.o $${OBJS}'; \ + umask 007; \ + echo ${OBJS} param.o ioconf.o vers.o | tr " " "\n" | ${SORTR} > lorder; \ + ${LD} ${LINKFLAGS} -o $@ ${SYSTEM_HEAD} `cat lorder` +SYSTEM_LD_TAIL= @${SIZE} $@ + +.if ${DEBUG} == "-g" +STRIPFLAGS= -S +SYSTEM_LD_TAIL+=; umask 007; \ + echo mv $@ $@.gdb; rm -f $@.gdb; mv $@ $@.gdb; \ + echo ${STRIP} ${STRIPFLAGS} -o $@ $@.gdb; \ + ${STRIP} ${STRIPFLAGS} -o $@ $@.gdb +.else +LINKFLAGS+= -S +.endif + +%LOAD + +# cc's -MD puts the source and output paths in the dependency file; +# since those are temp files here we need to fix it up. It also +# puts the file in /tmp, so we use -MF to put it in the current +# directory as assym.P and then generate assym.d from it with a +# good target name +assym.h: $S/kern/genassym.sh Makefile \ + ${_archdir}/${_arch}/genassym.cf ${_machdir}/${_mach}/genassym.cf + cat ${_archdir}/${_arch}/genassym.cf ${_machdir}/${_mach}/genassym.cf | \ + sh $S/kern/genassym.sh ${CC} ${CFLAGS} ${CPPFLAGS} -no-integrated-as -MF assym.P > assym.h.tmp + sed '1s/.*/assym.h: \\/' assym.P > assym.d + sort -u assym.h.tmp > assym.h + +param.c: $S/conf/param.c + rm -f param.c + cp $S/conf/param.c . + +param.o: param.c Makefile + ${NORMAL_C} + +mcount.o: $S/lib/libkern/mcount.c Makefile + ${NORMAL_C_NOP} + +ioconf.o: ioconf.c + ${NORMAL_C} + +ld.script: ${_archdir}/conf/kern.ldscript + cat ${_archdir}/conf/kern.ldscript | \ + sed -e 's/@KERNEL_BASE_PHYS@/${KERNEL_BASE_PHYS}/' \ + -e 's/@KERNEL_BASE_VIRT@/${KERNEL_BASE_VIRT}/' > ld.script +gapdummy.o: + echo '__asm(".section .rodata,\"a\"");' > gapdummy.c + ${CC} -c ${CFLAGS} ${CPPFLAGS} gapdummy.c -o $@ + +makegap.sh: + cp $S/conf/makegap.sh $@ + +MAKE_GAP = LD="${LD}" sh makegap.sh 0x00000000 gapdummy.o + +gap.o: Makefile makegap.sh gapdummy.o vers.o + ${MAKE_GAP} + +vers.o: ${SYSTEM_DEP:Ngap.o} + sh $S/conf/newvers.sh + ${CC} ${CFLAGS} ${CPPFLAGS} ${PROF} -c vers.c + +clean: + rm -f *bsd *bsd.gdb *.[dio] [a-z]*.s assym.* \ + gap.link gapdummy.c ld.script lorder makegap.sh param.c + +cleandir: clean + rm -f Makefile *.h ioconf.c options machine ${_mach} vers.c + +depend obj: + +locore0.o: ${_archdir}/${_arch}/locore0.S assym.h +copy.o copystr.o: assym.h +pagezero.o: assym.h +cpuswitch.o exception.o support.o: assym.h +locore.o trampoline.o: assym.h + +hardlink-obsd: + [[ ! -f /bsd ]] || cmp -s bsd /bsd || ln -f /bsd /obsd + +reconfig: + [[ ! -f /etc/bsd.re-config ]] || config -e -c /etc/bsd.re-config -f bsd + +newinstall: + install -F -m 700 bsd /bsd && sha256 -h /var/db/kernel.SHA256 /bsd + +install: update-link hardlink-obsd reconfig newinstall + +# pull in the dependency information +.ifnmake clean +. for o in ${SYSTEM_OBJ:Ngap.o} assym.h +. if exists(${o:R}.d) +. include "${o:R}.d" +. elif exists($o) + .PHONY: $o +. endif +. endfor +.endif + +%RULES diff --git sys/arch/loongarch64/conf/RAMDISK sys/arch/loongarch64/conf/RAMDISK new file mode 100644 index 00000000000..1cfe0fb82db --- /dev/null +++ sys/arch/loongarch64/conf/RAMDISK @@ -0,0 +1,226 @@ +# $OpenBSD: RAMDISK,v 1.242 2026/06/24 10:23:01 kettenis Exp $ + +machine loongarch64 +maxusers 4 + +option PCIVERBOSE +option USBVERBOSE +option SMALL_KERNEL +option NO_PROPOLICE +option BOOT_CONFIG + +option RAMDISK_HOOKS +option MINIROOTSIZE=24576 + +option FFS +option FFS2 +option MSDOSFS +option INET6 +option EXT2FS +option NFSCLIENT +option CD9660 +option UDF +option CRYPTO + +makeoptions KERNEL_BASE_PHYS="0x90000000" +makeoptions KERNEL_BASE_VIRT="0xffffffe000200000" + +config bsd root on rd0a swap on rd0b + +# The main bus device +mainbus0 at root +softraid0 at root +cpu0 at mainbus? +intc0 at cpu? +efi0 at mainbus? +smbios0 at efi? +acpi0 at mainbus? +acpiec* at acpi? +acpimcfg* at acpi? +acpiiort* at acpi? +acpisectwo* at acpi? +acpipci* at acpi? +pci* at acpipci? +ahci* at acpi? +ccp* at acpi? # AMD Cryptographic Co-processor +com* at acpi? +ehci* at acpi? +ohci* at acpi? +pluart* at acpi? +qcuart* at acpi? +sdhc* at acpi? +ufshci* at acpi? +xhci* at acpi? +simplebus* at fdt? + +scsibus* at scsi? +sd* at scsibus? +st* at scsibus? +cd* at scsibus? +ch* at scsibus? +uk* at scsibus? + +ahci* at fdt? +dwge* at fdt? +dwpcie* at fdt? +pci* at dwpcie? +dwqe* at fdt? +ohci* at fdt? +ehci* at fdt? +pciecam* at fdt? +pci* at pciecam? +sdhc* at fdt? +sdmmc* at sdhc? +bwfm* at sdmmc? # Broadcom FullMAC +xhci* at fdt? +ccp* at fdt? # AMD Cryptographic Co-processor +ufshci* at fdt? + +# NS16550 compatible serial ports +com* at fdt? + +# Generic devices +iicmux* at fdt? +iic* at iicmux? +pinctrl* at fdt? early 1 +plgpio* at fdt? early 1 +plrtc* at fdt? +pluart* at fdt? +pwmfan* at fdt? +syscon* at fdt? early 1 + +virtio* at fdt? +virtio* at pci? +vio* at virtio? +vioblk* at virtio? +viornd* at virtio? +vioscsi* at virtio? +viogpu* at virtio? +wsdisplay* at viogpu? + +simplefb* at fdt? +wsdisplay* at simplefb? + +# PCI +ppb* at pci? # PCI-PCI bridges +pci* at ppb? + +# PCI Ethernet +aq* at pci? # Aquantia aQtion Ethernet +bnxt* at pci? # Broadcom BCM573xx, BCM574xx +bge* at pci? # Broadcom BCM57xx +em* at pci? # Intel Pro/1000 Ethernet +igc* at pci? # Intel I225 Ethernet +ix* at pci? # Intel 82598EB 10Gb Ethernet +ixl* at pci? # Intel Ethernet 700 Series +ice* at pci? # Intel Ethernet 800 Series +mcx* at pci? # Mellanox ConnectX-4/5 Ethernet +mskc* at pci? # Marvell Yukon-2 +msk* at mskc? # each port of above +re* at pci? # Realtek 8169/8169S/8110S +rge* at pci? # Realtek 8125 +vmx* at pci? # VMware VMXNET3 virtual interface + +# PCI WiFi +athn* at pci? # Atheros AR9k (802.11a/g/n) +bwfm* at pci? # Broadcom FullMAC +iwx* at pci? # Intel WiFi Link 22xxx + +# PCI SCSI +ahci* at pci? flags 0x0000 # AHCI SATA controllers + # flags 0x0001 to force SATA 1 (1.5Gb/s) +nvme* at pci? # NVMe controllers +sdhc* at pci? # SD Host Controller + +# USB Controllers +ohci* at pci? # Open Host Controller +uhci* at pci? # Universal Host Controller (Intel) +ehci* at pci? # Enhanced Host Controller +xhci* at pci? # eXtensible Host Controller + +# USB bus support +usb* at ohci? +usb* at uhci? +usb* at ehci? +usb* at xhci? + +# USB devices +uhub* at usb? # USB Hubs +uhub* at uhub? # USB Hubs +umass* at uhub? # USB Mass Storage devices +uhidev* at uhub? # Human Interface Devices +ukbd* at uhidev? # USB keyboard +wskbd* at ukbd? mux 1 +aue* at uhub? # ADMtek AN986 Pegasus Ethernet +atu* at uhub? # Atmel AT76c50x based 802.11b +axe* at uhub? # ASIX Electronics AX88172 USB Ethernet +axen* at uhub? # ASIX Electronics AX88179 USB Ethernet +cue* at uhub? # CATC USB-EL1201A based Ethernet +kue* at uhub? # Kawasaki KL5KUSB101B based Ethernet +smsc* at uhub? # SMSC LAN95xx Ethernet +cdce* at uhub? # CDC Ethernet +urndis* at uhub? # Remote NDIS Ethernet +upl* at uhub? # Prolific PL2301/PL2302 host-to-host `network' +ugl* at uhub? # Genesys Logic GL620USB-A host-to-host `network' +udav* at uhub? # Davicom DM9601 based Ethernet +mos* at uhub? # MOSCHIP MCS7730/7830 10/100 Ethernet +mue* at uhub? # Microchip LAN75xx/LAN78xx Ethernet +url* at uhub? # Realtek RTL8150L based adapters +ure* at uhub? # Realtek RTL8152 based adapters +wi* at uhub? # WaveLAN IEEE 802.11DS +uath* at uhub? # Atheros AR5005UG/AR5005UX +ural* at uhub? # Ralink RT2500USB +rum* at uhub? # Ralink RT2501USB/RT2601USB +run* at uhub? # Ralink RT2700U/RT2800U/RT3000U +mtw* at uhub? # MediaTek MT7601U +otus* at uhub? # Atheros AR9001U +athn* at uhub? # Atheros AR9002U +zyd* at uhub? # Zydas ZD1211 +upgt* at uhub? # Conexant/Intersil PrismGT SoftMAC USB +urtw* at uhub? # Realtek 8187 +rsu* at uhub? # Realtek RTL8188SU/RTL8191SU/RTL8192SU +urtwn* at uhub? # Realtek RTL8188CU/RTL8192CU +bwfm* at uhub? # Broadcom FullMAC + +amphy* at mii? # AMD 79C873 PHYs +atphy* at mii? # Attansic F1 PHYs +brgphy* at mii? # Broadcom Gigabit PHYs +eephy* at mii? # Marvell 88E1000 series PHY +rgephy* at mii? # Realtek 8169S/8110S PHY +rlphy* at mii? # Realtek 8139 internal PHYs +ukphy* at mii? # "unknown" PHYs +urlphy* at mii? # Realtek RTL8150L internal PHY +ytphy* at mii? # MotorComm YT8511 PHY + +# I2C devices +abcrtc* at iic? # Abracon x80x RTC +axppmic* at iic? # AXP80x PMIC +dsxrtc* at iic? # DS3231 RTC +fusbtc* at iic? # USB Type-C controller +ihidev* at iic? # HID-over-I2C +ikbd* at ihidev? # HID-over-I2C keyboard +wskbd* at ikbd? mux 1 +islrtc* at iic? # ISL1208 RTC +maxrtc* at iic? # DS1307 RTC +mcprtc* at iic? # MCP794XX RTC +mfokrtc* at iic? # M41T8X RTC +pcagpio* at iic? # PCA9554 GPIO expander +pcamux* at iic? # PCA9548 multiplexer +iic* at pcamux? +pcfrtc* at iic? # PCF8523 RTC +pcxrtc* at iic? # PCF8563 RTC +pcyrtc* at iic? # PCF85063A/TP RTC +rkpmic* at iic? # RK808 PMIC +tcpci* at iic? # USB Type-C controller +tipd* at iic? # TPS6598x Type-C controller + +pseudo-device loop 1 +pseudo-device vlan +pseudo-device aggr +pseudo-device trunk +pseudo-device bpfilter 1 +pseudo-device rd 1 +pseudo-device bio 1 + +# mouse & keyboard multiplexor pseudo-devices +pseudo-device wsmux 2 diff --git sys/arch/loongarch64/conf/files.loongarch64 sys/arch/loongarch64/conf/files.loongarch64 new file mode 100644 index 00000000000..b0c98649ed2 --- /dev/null +++ sys/arch/loongarch64/conf/files.loongarch64 @@ -0,0 +1,153 @@ +# $OpenBSD: files.riscv64,v 1.40 2026/07/24 10:51:01 kettenis Exp $ + +# Standard stanzas config(8) can't run without +maxpartitions 16 +maxusers 2 8 128 + +# Major number for block devices, for ``root on'' lines +major { wd = 0 } +major { sd = 4 } +major { cd = 6 } +major { rd = 8 } + +file arch/loongarch64/loongarch64/autoconf.c +file arch/loongarch64/loongarch64/ast.c +file arch/loongarch64/loongarch64/bus_space.c +file arch/loongarch64/loongarch64/bus_dma.c +file arch/loongarch64/loongarch64/clock.c +file arch/loongarch64/loongarch64/conf.c +file arch/loongarch64/loongarch64/disksubr.c disk +file arch/loongarch64/loongarch64/locore.S +file arch/loongarch64/loongarch64/copy.S +file arch/loongarch64/loongarch64/copystr.S +file arch/loongarch64/loongarch64/exception.S +file arch/loongarch64/loongarch64/cpuswitch.S +file arch/loongarch64/loongarch64/machdep.c +file arch/loongarch64/loongarch64/intr.c +file arch/loongarch64/loongarch64/pmap.c +file arch/loongarch64/loongarch64/mem.c +file arch/loongarch64/loongarch64/process_machdep.c +file arch/loongarch64/loongarch64/vm_machdep.c +file arch/loongarch64/loongarch64/sig_machdep.c +file arch/loongarch64/loongarch64/support.S +file arch/loongarch64/loongarch64/syscall.c +file arch/loongarch64/loongarch64/pagezero.S +file arch/loongarch64/loongarch64/trap.c +file arch/loongarch64/loongarch64/sbi.c +file arch/loongarch64/loongarch64/fpu.c +file arch/loongarch64/loongarch64/vector.c + +file arch/loongarch64/loongarch64/db_disasm.c ddb +file arch/loongarch64/loongarch64/db_interface.c ddb +file arch/loongarch64/loongarch64/db_trace.c ddb + +file arch/loongarch64/dev/pci_machdep.c + +pseudo-device openprom +file arch/loongarch64/loongarch64/openprom.c openprom needs-flag + +# +# mainbus +# +define mainbus {} +device mainbus: fdt +attach mainbus at root +file arch/loongarch64/dev/mainbus.c mainbus + +# EFI +include "dev/efi/files.efi" +attach efi at fdt +file arch/loongarch64/dev/efi_machdep.c efi + +device smbios +attach smbios at efi +file arch/loongarch64/dev/smbios.c smbios + +# +# cpu +# +define cpu {} +device cpu +attach cpu at mainbus +file arch/loongarch64/loongarch64/cpu.c cpu + +# +# HART-specific interrupt controller +# +device intc +attach intc at cpu +file arch/loongarch64/dev/loongarch_cpu_intc.c intc + +# +# simplebus +# +device simplebus: fdt +attach simplebus at fdt +file arch/loongarch64/dev/simplebus.c simplebus + +# Paravirtual device bus and virtio +include "dev/pv/files.pv" + +file netinet/in_cksum.c +file netinet/in4_cksum.c + +# +# Machine-independent HID support +# +include "dev/hid/files.hid" + +# Machine-independent I2C drivers +include "dev/i2c/files.i2c" + +# FDT now requires drm (which is part of pci) +include "dev/mii/files.mii" +include "dev/pci/files.pci" +include "dev/sdmmc/files.sdmmc" + +# FDT support +include "dev/ofw/files.ofw" + +# Machine-independent FDT drivers +include "dev/fdt/files.fdt" + +# Machine-independent GPIO drivers +include "dev/gpio/files.gpio" + +# Machine-independent SCSI drivers +include "scsi/files.scsi" + +# Machine-independent ATA drivers +include "dev/ata/files.ata" + +# Include WSCONS stuff +include "dev/wscons/files.wscons" +include "dev/rasops/files.rasops" +include "dev/wsfont/files.wsfont" + +device pciecam: pcibus +attach pciecam at fdt +file dev/fdt/pciecam.c pciecam + +# Machine-independent USB drivers +include "dev/usb/files.usb" + +include "dev/acpi/files.acpi" + +attach acpi at fdt with acpi_fdt +file arch/loongarch64/loongarch64/acpi_machdep.c acpi_fdt +file arch/loongarch64/dev/acpicpu.c acpicpu + +define acpiiort {} +device acpiiort: acpiiort +attach acpiiort at acpi +file arch/loongarch64/dev/acpiiort.c acpiiort + +device acpipci: pcibus +attach acpipci at acpi +file arch/loongarch64/dev/acpipci.c acpipci + +device apm +attach apm at mainbus +file arch/loongarch64/dev/apm.c apm needs-flag +file arch/loongarch64/loongarch64/acpiapm.c apm + diff --git sys/arch/loongarch64/conf/kern.ldscript sys/arch/loongarch64/conf/kern.ldscript new file mode 100644 index 00000000000..81147a40f83 --- /dev/null +++ sys/arch/loongarch64/conf/kern.ldscript @@ -0,0 +1,82 @@ +/* $OpenBSD: kern.ldscript,v 1.4 2022/01/07 13:56:54 kevlo Exp $ */ + +OUTPUT_ARCH(loongarch64) + +/* Define how we want our ELF binary to look like. */ +PHDRS +{ + text PT_LOAD; + rodata PT_LOAD FLAGS (4); + data PT_LOAD; + openbsd_randomize PT_OPENBSD_RANDOMIZE; +} + +__ALIGN_SIZE = 0x200000; +__kernel_base = @KERNEL_BASE_VIRT@; + +ENTRY(_start) +SECTIONS +{ + . = __kernel_base; + PROVIDE (__text_start = .); + .text : + { + *(.text .text.*) + *(.stub) + } :text =0 + PROVIDE (_etext = .); + PROVIDE (etext = .); + + /* Move rodata to the next page, so we can nuke X and W bit on it */ + . = ALIGN(__ALIGN_SIZE); + PROVIDE (__rodata_start = .); + .rodata : + { + *(.rodata .rodata.*) + } :rodata + .openbsd.randomdata : + { + *(.openbsd.randomdata) + } :openbsd_randomize :rodata + PROVIDE (_erodata = .); + + /* Move .data to the next page, so we can add W bit on it */ + . = ALIGN(__ALIGN_SIZE); + PROVIDE (__data_start = .); + .got : + { + *(.got .got.*) + } :data + .data : + { + *(.data .data.*) + } :data + .sdata : + { + *(.sdata .sdata.*) + } :data + PROVIDE (_edata = .); + + . = ALIGN(8); + PROVIDE (__bss_start = .); + .sbss : + { + *(.dynsbss) + *(.sbss) + *(.sbss.*) + *(.scommon) + } :data + .bss : + { + *(.dynbss) + *(.bss) + *(.bss.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. */ + . = ALIGN(8); + } :data + PROVIDE (_end = .); + PROVIDE (end = .); +} diff --git sys/arch/loongarch64/dev/acpicpu.c sys/arch/loongarch64/dev/acpicpu.c new file mode 100644 index 00000000000..0c775fb70d3 --- /dev/null +++ sys/arch/loongarch64/dev/acpicpu.c @@ -0,0 +1,370 @@ +/* $OpenBSD: acpicpu.c,v 1.3 2026/04/03 14:20:23 kettenis Exp $ */ +/* + * Copyright (c) 2025 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "kstat.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +struct acpicpu_softc { + struct device sc_dev; + struct acpi_softc *sc_acpi; + struct aml_node *sc_node; + uint64_t sc_mpidr; + + uint64_t sc_highest_perf; + uint64_t sc_nominal_perf; + uint64_t sc_lowest_perf; + uint64_t sc_nominal_freq; + uint64_t sc_lowest_freq; + struct acpi_gas sc_desired_perf; + + uint64_t sc_perf; +}; + +int acpicpu_match(struct device *, void *, void *); +void acpicpu_attach(struct device *, struct device *, void *); + +const struct cfattach acpicpu_ca = { + sizeof(struct acpicpu_softc), acpicpu_match, acpicpu_attach +}; + +struct cfdriver acpicpu_cd = { + NULL, "acpicpu", DV_DULL +}; + +const char *acpicpu_hids[] = { + "ACPI0007", + NULL +}; + +uint64_t acpicpu_lowest_perf = UINT64_MAX; +uint64_t acpicpu_highest_perf = 0; +struct task acpicpu_setperf_task; + +void acpicpu_do_setperf(void *); +void acpicpu_setperf(int); +int acpicpu_cpuspeed(int *); +void acpicpu_kstat_attach(struct acpicpu_softc *); + +int +acpicpu_match(struct device *parent, void *match, void *aux) +{ + struct acpi_attach_args *aaa = aux; + struct cfdata *cf = match; + + return acpi_matchhids(aaa, acpicpu_hids, cf->cf_driver->cd_name); +} + +void +acpicpu_attach(struct device *parent, struct device *self, void *aux) +{ + struct acpi_attach_args *aaa = aux; + struct acpicpu_softc *sc = (struct acpicpu_softc *)self; + struct acpi_table_header *hdr; + struct acpi_madt *madt = NULL; + struct acpi_q *entry; + struct aml_value res; + struct cpu_info *ci; + CPU_INFO_ITERATOR cii; + caddr_t addr; + uint64_t uid = 0; + int found = 0; + + sc->sc_acpi = (struct acpi_softc *)parent; + sc->sc_node = aaa->aaa_node; + printf(" %s", sc->sc_node->name); + + aml_evalinteger(sc->sc_acpi, sc->sc_node, "_UID", 0, NULL, &uid); + + printf("\n"); + + /* Look for MADT table. */ + SIMPLEQ_FOREACH(entry, &acpi_softc->sc_tables, q_next) { + hdr = entry->q_table; + if (strncmp(hdr->signature, MADT_SIG, + sizeof(hdr->signature)) == 0) { + madt = entry->q_table; + break; + } + } + if (madt == NULL) + return; + + /* Locate the CPU in the MADT table. */ + addr = (caddr_t)(madt + 1); + while (addr < (caddr_t)madt + madt->hdr.length) { + struct acpi_madt_gicc *gicc = (struct acpi_madt_gicc *)addr; + + if (gicc->apic_type == ACPI_MADT_GICC) { + if (gicc->acpi_proc_uid == uid) { + sc->sc_mpidr = gicc->mpidr; + found = 1; + break; + } + } + + addr += gicc->length; + } + if (!found) + return; + + if (aml_evalname(sc->sc_acpi, sc->sc_node, "_CPC", 0, NULL, &res)) + return; + + if (res.type != AML_OBJTYPE_PACKAGE || res.length < 23) + return; + + /* Check number of entries in the _CPC package. */ + if (res.v_package[0]->type != AML_OBJTYPE_INTEGER || + res.v_package[0]->v_integer < 23) + return; + + /* Check revision number of the _CPC package format. */ + if (res.v_package[1]->type != AML_OBJTYPE_INTEGER || + res.v_package[1]->v_integer != 3) + return; + + if (res.v_package[2]->type != AML_OBJTYPE_INTEGER || /* or Buffer */ + res.v_package[3]->type != AML_OBJTYPE_INTEGER || /* or Buffer */ + res.v_package[4]->type != AML_OBJTYPE_INTEGER || /* or Buffer */ + res.v_package[5]->type != AML_OBJTYPE_INTEGER || /* or Buffer */ + res.v_package[6]->type != AML_OBJTYPE_BUFFER || + res.v_package[7]->type != AML_OBJTYPE_BUFFER || + res.v_package[8]->type != AML_OBJTYPE_BUFFER || + res.v_package[9]->type != AML_OBJTYPE_BUFFER || + res.v_package[10]->type != AML_OBJTYPE_BUFFER || + res.v_package[11]->type != AML_OBJTYPE_BUFFER || + res.v_package[12]->type != AML_OBJTYPE_INTEGER || /* or Buffer */ + res.v_package[13]->type != AML_OBJTYPE_BUFFER || + res.v_package[14]->type != AML_OBJTYPE_BUFFER || + res.v_package[15]->type != AML_OBJTYPE_BUFFER || + res.v_package[16]->type != AML_OBJTYPE_BUFFER || + res.v_package[17]->type != AML_OBJTYPE_INTEGER || /* or Buffer */ + res.v_package[18]->type != AML_OBJTYPE_BUFFER || + res.v_package[19]->type != AML_OBJTYPE_BUFFER || + res.v_package[20]->type != AML_OBJTYPE_INTEGER || /* or Buffer */ + res.v_package[21]->type != AML_OBJTYPE_INTEGER || /* or Buffer */ + res.v_package[22]->type != AML_OBJTYPE_INTEGER) /* or Buffer */ + return; + + memcpy(&sc->sc_desired_perf, &res.v_package[7]->v_buffer[3], + sizeof(struct acpi_gas)); + + sc->sc_highest_perf = res.v_package[2]->v_integer; + sc->sc_nominal_perf = res.v_package[3]->v_integer; + sc->sc_lowest_perf = res.v_package[5]->v_integer; + sc->sc_lowest_freq = res.v_package[21]->v_integer; + sc->sc_nominal_freq = res.v_package[22]->v_integer; + + if (acpicpu_lowest_perf > sc->sc_lowest_perf) + acpicpu_lowest_perf = sc->sc_lowest_perf; + if (acpicpu_highest_perf < sc->sc_highest_perf) + acpicpu_highest_perf = sc->sc_highest_perf; + + CPU_INFO_FOREACH(cii, ci) { + if (sc->sc_mpidr == ci->ci_mpidr) { + ci->ci_capacity = sc->sc_nominal_perf; + cpu_classify(); + break; + } + } + + task_set(&acpicpu_setperf_task, acpicpu_do_setperf, NULL); + cpu_setperf = acpicpu_setperf; + + cpu_cpuspeed = acpicpu_cpuspeed; + acpicpu_kstat_attach(sc); +} + +void +acpicpu_do_setperf(void *arg) +{ + struct acpicpu_softc *sc; + int i; + + for (i = 0; i < acpicpu_cd.cd_ndevs; i++) { + sc = acpicpu_cd.cd_devs[i]; + if (sc == NULL || sc->sc_nominal_perf == 0) + continue; + + acpi_gasio(sc->sc_acpi, ACPI_IOWRITE, + sc->sc_desired_perf.address_space_id, + sc->sc_desired_perf.address, + (1 << (sc->sc_desired_perf.access_size - 1)), + sc->sc_desired_perf.register_bit_width / 8, &sc->sc_perf); + } +} + +void +acpicpu_setperf(int level) +{ + struct acpicpu_softc *sc; + uint64_t min, max, perf; + int i; + + /* + * Map the performance level onto the CPPC performance scale. + */ + min = acpicpu_lowest_perf; + max = acpicpu_highest_perf; + perf = min + (level * (max - min)) / 100; + + for (i = 0; i < acpicpu_cd.cd_ndevs; i++) { + sc = acpicpu_cd.cd_devs[i]; + if (sc == NULL || sc->sc_nominal_perf == 0) + continue; + + /* + * Clamp performance based on the limits for this CPU. + * For now use the nominal performance as the maximum + * as setting all CPUs to the highest performance at + * the same time probably isn't going to work well. + */ + if (perf < sc->sc_lowest_perf) + sc->sc_perf = sc->sc_lowest_perf; + else if (perf > sc->sc_nominal_perf) + sc->sc_perf = sc->sc_nominal_perf; + else + sc->sc_perf = perf; + } + + task_add(systq, &acpicpu_setperf_task); +} + +uint64_t +acpicpu_calcfreq(struct acpicpu_softc *sc, uint64_t perf) +{ + uint64_t delta_perf; + uint64_t delta_freq; + + delta_freq = sc->sc_nominal_freq - sc->sc_lowest_freq; + delta_perf = sc->sc_nominal_perf - sc->sc_lowest_perf; + if (delta_perf == 0) + return sc->sc_nominal_freq; + + return sc->sc_lowest_freq + + (perf - sc->sc_lowest_perf) * delta_freq / delta_perf; +} + +int +acpicpu_cpuspeed(int *freq) +{ + struct acpicpu_softc *sc = NULL; + uint64_t perf = 0; + int i; + + /* Find the first CPU for which we know the nominal frequency. */ + for (i = 0; i < acpicpu_cd.cd_ndevs; i++) { + sc = acpicpu_cd.cd_devs[i]; + if (sc && sc->sc_nominal_freq > 0) + break; + } + if (sc == NULL) + return EOPNOTSUPP; + + acpi_gasio(sc->sc_acpi, ACPI_IOREAD, + sc->sc_desired_perf.address_space_id, sc->sc_desired_perf.address, + (1 << (sc->sc_desired_perf.access_size - 1)), + sc->sc_desired_perf.register_bit_width / 8, &perf); + *freq = acpicpu_calcfreq(sc, perf); + return 0; +} + +struct acpicpu_kstats { + struct kstat_kv ak_perf; + struct kstat_kv ak_freq; +}; + +int +acpicpu_kstat_read(struct kstat *ks) +{ + struct acpicpu_softc *sc = ks->ks_softc; + struct acpicpu_kstats *ak = ks->ks_data; + struct timespec now, diff; + uint64_t freq, perf = 0; + + /* rate limit */ + getnanouptime(&now); + timespecsub(&now, &ks->ks_updated, &diff); + if (diff.tv_sec < 1) + return 0; + + acpi_gasio(sc->sc_acpi, ACPI_IOREAD, + sc->sc_desired_perf.address_space_id, sc->sc_desired_perf.address, + (1 << (sc->sc_desired_perf.access_size - 1)), + sc->sc_desired_perf.register_bit_width / 8, &perf); + kstat_kv_u64(&ak->ak_perf) = perf; + + if (sc->sc_nominal_freq > 0) { + freq = acpicpu_calcfreq(sc, perf); + kstat_kv_freq(&ak->ak_freq) = freq * 1000000; + } + + ks->ks_updated = now; + + return 0; +} + +void +acpicpu_kstat_attach(struct acpicpu_softc *sc) +{ + struct kstat *ks; + struct acpicpu_kstats *ak; + struct cpu_info *ci; + CPU_INFO_ITERATOR cii; + + CPU_INFO_FOREACH(cii, ci) { + if (sc->sc_mpidr == ci->ci_mpidr) + break; + } + if (ci == NULL) + return; + + ks = kstat_create(ci->ci_dev->dv_xname, 0, "cppc", 0, KSTAT_T_KV, 0); + if (ks == NULL) { + printf("%s: unable to create cppc kstats\n", + sc->sc_dev.dv_xname); + return; + } + + ak = malloc(sizeof(*ak), M_DEVBUF, M_WAITOK); + + kstat_kv_init(&ak->ak_perf, "perf", KSTAT_KV_T_UINT64); + if (sc->sc_nominal_freq > 0) + kstat_kv_init(&ak->ak_freq, "freq", KSTAT_KV_T_FREQ); + + ks->ks_softc = sc; + ks->ks_data = ak; + ks->ks_datalen = sizeof(*ak); + ks->ks_read = acpicpu_kstat_read; + + kstat_install(ks); +} diff --git sys/arch/loongarch64/dev/acpiiort.c sys/arch/loongarch64/dev/acpiiort.c new file mode 100644 index 00000000000..cd95b5c9583 --- /dev/null +++ sys/arch/loongarch64/dev/acpiiort.c @@ -0,0 +1,193 @@ +/* $OpenBSD: acpiiort.c,v 1.9 2022/09/07 18:25:08 patrick Exp $ */ +/* + * Copyright (c) 2021 Patrick Wildt + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include +#include +#include + +#include + +SIMPLEQ_HEAD(, acpiiort_smmu) acpiiort_smmu_list = + SIMPLEQ_HEAD_INITIALIZER(acpiiort_smmu_list); + +int acpiiort_match(struct device *, void *, void *); +void acpiiort_attach(struct device *, struct device *, void *); + +const struct cfattach acpiiort_ca = { + sizeof(struct device), acpiiort_match, acpiiort_attach +}; + +struct cfdriver acpiiort_cd = { + NULL, "acpiiort", DV_DULL +}; + +int +acpiiort_match(struct device *parent, void *match, void *aux) +{ + struct acpi_attach_args *aaa = aux; + struct acpi_table_header *hdr; + + /* If we do not have a table, it is not us */ + if (aaa->aaa_table == NULL) + return 0; + + /* If it is an IORT table, we can attach */ + hdr = (struct acpi_table_header *)aaa->aaa_table; + if (memcmp(hdr->signature, IORT_SIG, sizeof(IORT_SIG) - 1) != 0) + return 0; + + return 1; +} + +void +acpiiort_attach(struct device *parent, struct device *self, void *aux) +{ + struct acpi_attach_args *aaa = aux; + struct acpi_iort *iort = (struct acpi_iort *)aaa->aaa_table; + struct acpi_iort_node *node; + struct acpiiort_attach_args aia; + uint32_t offset; + int i; + + printf("\n"); + + memset(&aia, 0, sizeof(aia)); + aia.aia_iot = aaa->aaa_iot; + aia.aia_memt = aaa->aaa_memt; + aia.aia_dmat = aaa->aaa_dmat; + + offset = iort->offset; + for (i = 0; i < iort->number_of_nodes; i++) { + node = (struct acpi_iort_node *)((char *)iort + offset); + aia.aia_node = node; + config_found(self, &aia, NULL); + offset += node->length; + } +} + +void +acpiiort_smmu_register(struct acpiiort_smmu *as) +{ + SIMPLEQ_INSERT_TAIL(&acpiiort_smmu_list, as, as_list); +} + +bus_dma_tag_t +acpiiort_smmu_map(struct acpi_iort_node *node, uint32_t rid, + bus_dma_tag_t dmat) +{ + struct acpiiort_smmu *as; + + SIMPLEQ_FOREACH(as, &acpiiort_smmu_list, as_list) { + if (as->as_node == node) + return as->as_map(as->as_cookie, rid, dmat); + } + + return dmat; +} + +void +acpiiort_smmu_reserve_region(struct acpi_iort_node *node, uint32_t rid, + bus_addr_t addr, bus_size_t size) +{ + struct acpiiort_smmu *as; + + SIMPLEQ_FOREACH(as, &acpiiort_smmu_list, as_list) { + if (as->as_node == node) { + as->as_reserve(as->as_cookie, rid, addr, size); + return; + } + } +} + +bus_dma_tag_t +acpiiort_device_map(struct aml_node *root, bus_dma_tag_t dmat) +{ + struct acpi_table_header *hdr; + struct acpi_iort *iort = NULL; + struct acpi_iort_node *node; + struct acpi_iort_mapping *map; + struct acpi_iort_nc_node *nc; + struct acpi_q *entry; + struct aml_node *anc; + uint32_t rid, offset; + int i; + + /* Look for IORT table. */ + SIMPLEQ_FOREACH(entry, &acpi_softc->sc_tables, q_next) { + hdr = entry->q_table; + if (strncmp(hdr->signature, IORT_SIG, + sizeof(hdr->signature)) == 0) { + iort = entry->q_table; + break; + } + } + if (iort == NULL) + return dmat; + + /* Find our named component. */ + offset = iort->offset; + for (i = 0; i < iort->number_of_nodes; i++) { + node = (struct acpi_iort_node *)((char *)iort + offset); + if (node->type == ACPI_IORT_NAMED_COMPONENT) { + nc = (struct acpi_iort_nc_node *)&node[1]; + anc = aml_searchname(acpi_softc->sc_root, + nc->device_object_name); + if (anc == root) + break; + } + offset += node->length; + } + + /* No NC found? Weird. */ + if (i >= iort->number_of_nodes) + return dmat; + + /* Find our output base towards SMMU. */ + map = (struct acpi_iort_mapping *)((char *)node + node->mapping_offset); + for (i = 0; i < node->number_of_mappings; i++) { + offset = map[i].output_reference; + + if (map[i].flags & ACPI_IORT_MAPPING_SINGLE) { + rid = map[i].output_base; + break; + } + } + + /* + * The IORT spec allows NCs to use implementation-defined IDs, whose + * interpretation is up to the device driver. For now simply take the + * mapping if there's a single one. This might change in the future. + */ + if (i >= node->number_of_mappings && node->number_of_mappings == 1) { + i = 0; + rid = map[i].output_base; + } + + /* No mapping found? Even weirder. */ + if (i >= node->number_of_mappings) + return dmat; + + node = (struct acpi_iort_node *)((char *)iort + offset); + if (node->type == ACPI_IORT_SMMU || node->type == ACPI_IORT_SMMU_V3) + return acpiiort_smmu_map(node, rid, dmat); + + return dmat; +} diff --git sys/arch/loongarch64/dev/acpiiort.h sys/arch/loongarch64/dev/acpiiort.h new file mode 100644 index 00000000000..02369755e33 --- /dev/null +++ sys/arch/loongarch64/dev/acpiiort.h @@ -0,0 +1,38 @@ +/* $OpenBSD: acpiiort.h,v 1.4 2021/06/25 17:41:22 patrick Exp $ */ +/* + * Copyright (c) 2021 Patrick Wildt + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +struct acpiiort_attach_args { + struct acpi_iort_node *aia_node; + bus_space_tag_t aia_iot; + bus_space_tag_t aia_memt; + bus_dma_tag_t aia_dmat; +}; + +struct acpiiort_smmu { + SIMPLEQ_ENTRY(acpiiort_smmu) as_list; + struct acpi_iort_node *as_node; + void *as_cookie; + bus_dma_tag_t (*as_map)(void *, uint32_t, + bus_dma_tag_t); + void (*as_reserve)(void *, uint32_t, + bus_addr_t, bus_size_t); +}; + +void acpiiort_smmu_register(struct acpiiort_smmu *); +bus_dma_tag_t acpiiort_smmu_map(struct acpi_iort_node *, uint32_t, bus_dma_tag_t); +void acpiiort_smmu_reserve_region(struct acpi_iort_node *, uint32_t, bus_addr_t, bus_size_t); +bus_dma_tag_t acpiiort_device_map(struct aml_node *, bus_dma_tag_t); diff --git sys/arch/loongarch64/dev/acpipci.c sys/arch/loongarch64/dev/acpipci.c new file mode 100644 index 00000000000..3eaac20a264 --- /dev/null +++ sys/arch/loongarch64/dev/acpipci.c @@ -0,0 +1,910 @@ +/* $OpenBSD: acpipci.c,v 1.44 2026/01/06 11:51:33 patrick Exp $ */ +/* + * Copyright (c) 2018 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +struct acpipci_mcfg { + SLIST_ENTRY(acpipci_mcfg) am_list; + + uint16_t am_segment; + uint8_t am_min_bus; + uint8_t am_max_bus; + + bus_space_tag_t am_iot; + bus_space_handle_t am_ioh; + + struct machine_pci_chipset am_pc; +}; + +struct acpipci_trans { + struct acpipci_trans *at_next; + bus_space_tag_t at_iot; + bus_addr_t at_base; + bus_size_t at_size; + bus_size_t at_offset; +}; + +struct acpipci_softc { + struct device sc_dev; + struct acpi_softc *sc_acpi; + struct aml_node *sc_node; + bus_space_tag_t sc_iot; + pci_chipset_tag_t sc_pc; + + struct bus_space sc_bus_iot; + struct bus_space sc_bus_memt; + struct acpipci_trans *sc_io_trans; + struct acpipci_trans *sc_mem_trans; + + struct extent *sc_busex; + struct extent *sc_memex; + struct extent *sc_ioex; + char sc_busex_name[32]; + char sc_ioex_name[32]; + char sc_memex_name[32]; + int sc_bus; + uint32_t sc_seg; + + struct interrupt_controller *sc_msi_ic; +}; + +struct acpipci_intr_handle { + struct machine_intr_handle aih_ih; + bus_dma_tag_t aih_dmat; + bus_dmamap_t aih_map; +}; + +int acpipci_match(struct device *, void *, void *); +void acpipci_attach(struct device *, struct device *, void *); + +const struct cfattach acpipci_ca = { + sizeof(struct acpipci_softc), acpipci_match, acpipci_attach +}; + +struct cfdriver acpipci_cd = { + NULL, "acpipci", DV_DULL +}; + +const char *acpipci_hids[] = { + "PNP0A08", + NULL +}; + +int acpipci_parse_resources(int, union acpi_resource *, void *); +int acpipci_bs_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, + bus_space_handle_t *); +paddr_t acpipci_bs_mmap(bus_space_tag_t, bus_addr_t, off_t, int, int); + +void acpipci_attach_hook(struct device *, struct device *, + struct pcibus_attach_args *); +int acpipci_bus_maxdevs(void *, int); +pcitag_t acpipci_make_tag(void *, int, int, int); +void acpipci_decompose_tag(void *, pcitag_t, int *, int *, int *); +int acpipci_conf_size(void *, pcitag_t); +pcireg_t acpipci_conf_read(void *, pcitag_t, int); +void acpipci_conf_write(void *, pcitag_t, int, pcireg_t); +int acpipci_probe_device_hook(void *, struct pci_attach_args *); + +int acpipci_intr_map(struct pci_attach_args *, pci_intr_handle_t *); +const char *acpipci_intr_string(void *, pci_intr_handle_t); +void *acpipci_intr_establish(void *, pci_intr_handle_t, int, + struct cpu_info *, int (*)(void *), void *, char *); +void acpipci_intr_disestablish(void *, void *); + +uint32_t acpipci_iort_map_msi(pci_chipset_tag_t, pcitag_t, + struct interrupt_controller **); + +extern LIST_HEAD(, interrupt_controller) interrupt_controllers; + +int +acpipci_match(struct device *parent, void *match, void *aux) +{ + struct acpi_attach_args *aaa = aux; + struct cfdata *cf = match; + + return acpi_matchhids(aaa, acpipci_hids, cf->cf_driver->cd_name); +} + +void +acpipci_attach(struct device *parent, struct device *self, void *aux) +{ + struct acpi_attach_args *aaa = aux; + struct acpipci_softc *sc = (struct acpipci_softc *)self; + struct interrupt_controller *ic; + struct pcibus_attach_args pba; + struct aml_value res; + uint64_t bbn = 0; + uint64_t seg = 0; + + sc->sc_acpi = (struct acpi_softc *)parent; + sc->sc_node = aaa->aaa_node; + printf(" %s", sc->sc_node->name); + + if (aml_evalname(sc->sc_acpi, sc->sc_node, "_CRS", 0, NULL, &res)) { + printf(": can't find resources\n"); + return; + } + + aml_evalinteger(sc->sc_acpi, sc->sc_node, "_BBN", 0, NULL, &bbn); + sc->sc_bus = bbn; + + aml_evalinteger(sc->sc_acpi, sc->sc_node, "_SEG", 0, NULL, &seg); + sc->sc_seg = seg; + + sc->sc_iot = aaa->aaa_memt; + + printf("\n"); + + /* Create extents for our address spaces. */ + snprintf(sc->sc_busex_name, sizeof(sc->sc_busex_name), + "%s pcibus", sc->sc_dev.dv_xname); + snprintf(sc->sc_ioex_name, sizeof(sc->sc_ioex_name), + "%s pciio", sc->sc_dev.dv_xname); + snprintf(sc->sc_memex_name, sizeof(sc->sc_memex_name), + "%s pcimem", sc->sc_dev.dv_xname); + sc->sc_busex = extent_create(sc->sc_busex_name, 0, 255, + M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED); + sc->sc_ioex = extent_create(sc->sc_ioex_name, 0, 0xffffffff, + M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED); + sc->sc_memex = extent_create(sc->sc_memex_name, 0, (u_long)-1, + M_DEVBUF, NULL, 0, EX_WAITOK | EX_FILLED); + + aml_parse_resource(&res, acpipci_parse_resources, sc); + + memcpy(&sc->sc_bus_iot, sc->sc_iot, sizeof(sc->sc_bus_iot)); + sc->sc_bus_iot.bus_private = sc->sc_io_trans; + sc->sc_bus_iot._space_map = acpipci_bs_map; + sc->sc_bus_iot._space_mmap = acpipci_bs_mmap; + memcpy(&sc->sc_bus_memt, sc->sc_iot, sizeof(sc->sc_bus_memt)); + sc->sc_bus_memt.bus_private = sc->sc_mem_trans; + sc->sc_bus_memt._space_map = acpipci_bs_map; + sc->sc_bus_memt._space_mmap = acpipci_bs_mmap; + + LIST_FOREACH(ic, &interrupt_controllers, ic_list) { + if (ic->ic_establish_msi) + break; + } + sc->sc_msi_ic = ic; + + sc->sc_pc = pci_lookup_segment(sc->sc_seg, sc->sc_bus); + KASSERT(sc->sc_pc->pc_intr_v == NULL); + + sc->sc_pc->pc_probe_device_hook = acpipci_probe_device_hook; + + sc->sc_pc->pc_intr_v = sc; + sc->sc_pc->pc_intr_map = acpipci_intr_map; + sc->sc_pc->pc_intr_map_msi = _pci_intr_map_msi; + sc->sc_pc->pc_intr_map_msivec = _pci_intr_map_msivec; + sc->sc_pc->pc_intr_map_msix = _pci_intr_map_msix; + sc->sc_pc->pc_intr_string = acpipci_intr_string; + sc->sc_pc->pc_intr_establish = acpipci_intr_establish; + sc->sc_pc->pc_intr_disestablish = acpipci_intr_disestablish; + + memset(&pba, 0, sizeof(pba)); + pba.pba_busname = "pci"; + pba.pba_iot = &sc->sc_bus_iot; + pba.pba_memt = &sc->sc_bus_memt; + pba.pba_dmat = aaa->aaa_dmat; + pba.pba_pc = sc->sc_pc; + pba.pba_busex = sc->sc_busex; + pba.pba_ioex = sc->sc_ioex; + pba.pba_memex = sc->sc_memex; + pba.pba_pmemex = sc->sc_memex; + pba.pba_domain = pci_ndomains++; + pba.pba_bus = sc->sc_bus; + if (sc->sc_msi_ic) { + pba.pba_flags |= PCI_FLAGS_MSI_ENABLED; + pba.pba_flags |= PCI_FLAGS_MSIVEC_ENABLED; + } + + config_found(self, &pba, NULL); +} + +int +acpipci_parse_resources(int crsidx, union acpi_resource *crs, void *arg) +{ + struct acpipci_softc *sc = arg; + struct acpipci_trans *at; + int type = AML_CRSTYPE(crs); + int restype, tflags; + u_long min, len = 0, tra; + + switch (type) { + case LR_WORD: + restype = crs->lr_word.type; + tflags = crs->lr_word.tflags; + min = crs->lr_word._min; + len = crs->lr_word._len; + tra = crs->lr_word._tra; + break; + case LR_DWORD: + restype = crs->lr_dword.type; + tflags = crs->lr_dword.tflags; + min = crs->lr_dword._min; + len = crs->lr_dword._len; + tra = crs->lr_dword._tra; + break; + case LR_QWORD: + restype = crs->lr_qword.type; + tflags = crs->lr_qword.tflags; + min = crs->lr_qword._min; + len = crs->lr_qword._len; + tra = crs->lr_qword._tra; + break; + case LR_MEM32FIXED: + restype = LR_TYPE_MEMORY; + tflags = 0; + min = crs->lr_m32fixed._bas; + len = crs->lr_m32fixed._len; + tra = 0; + break; + } + + if (len == 0) + return 0; + + switch (restype) { + case LR_TYPE_MEMORY: + if (tflags & LR_MEMORY_TTP) + return 0; + extent_free(sc->sc_memex, min, len, EX_WAITOK); + at = malloc(sizeof(struct acpipci_trans), M_DEVBUF, M_WAITOK); + at->at_iot = sc->sc_iot; + at->at_base = min; + at->at_size = len; + at->at_offset = tra; + at->at_next = sc->sc_mem_trans; + sc->sc_mem_trans = at; + break; + case LR_TYPE_IO: + /* + * Don't check _TTP as various firmwares don't set it, + * even though they should!! + */ + extent_free(sc->sc_ioex, min, len, EX_WAITOK); + at = malloc(sizeof(struct acpipci_trans), M_DEVBUF, M_WAITOK); + at->at_iot = sc->sc_iot; + at->at_base = min; + at->at_size = len; + at->at_offset = tra; + at->at_next = sc->sc_io_trans; + sc->sc_io_trans = at; + break; + case LR_TYPE_BUS: + extent_free(sc->sc_busex, min, len, EX_WAITOK); + /* + * Let _CRS minimum bus number override _BBN. + */ + sc->sc_bus = min; + break; + } + + return 0; +} + +void +acpipci_attach_hook(struct device *parent, struct device *self, + struct pcibus_attach_args *pba) +{ +} + +int +acpipci_bus_maxdevs(void *v, int bus) +{ + return 32; +} + +pcitag_t +acpipci_make_tag(void *v, int bus, int device, int function) +{ + return ((bus << 20) | (device << 15) | (function << 12)); +} + +void +acpipci_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp) +{ + if (bp != NULL) + *bp = (tag >> 20) & 0xff; + if (dp != NULL) + *dp = (tag >> 15) & 0x1f; + if (fp != NULL) + *fp = (tag >> 12) & 0x7; +} + +int +acpipci_conf_size(void *v, pcitag_t tag) +{ + return PCIE_CONFIG_SPACE_SIZE; +} + +pcireg_t +acpipci_conf_read(void *v, pcitag_t tag, int reg) +{ + struct acpipci_mcfg *am = v; + + if (tag < (am->am_min_bus << 20) || + tag >= ((am->am_max_bus + 1) << 20)) + return 0xffffffff; + + return bus_space_read_4(am->am_iot, am->am_ioh, tag | reg); +} + +void +acpipci_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data) +{ + struct acpipci_mcfg *am = v; + + if (tag < (am->am_min_bus << 20) || + tag >= ((am->am_max_bus + 1) << 20)) + return; + + bus_space_write_4(am->am_iot, am->am_ioh, tag | reg, data); +} + +int +acpipci_probe_device_hook(void *v, struct pci_attach_args *pa) +{ + struct acpipci_mcfg *am = v; + struct acpipci_trans *at; + struct acpi_table_header *hdr; + struct acpi_iort *iort = NULL; + struct acpi_iort_node *node; + struct acpi_iort_mapping *map; + struct acpi_iort_rc_node *rc; + struct acpi_q *entry; + uint32_t rid, offset; + int i; + + rid = pci_requester_id(pa->pa_pc, pa->pa_tag); + + /* Look for IORT table. */ + SIMPLEQ_FOREACH(entry, &acpi_softc->sc_tables, q_next) { + hdr = entry->q_table; + if (strncmp(hdr->signature, IORT_SIG, + sizeof(hdr->signature)) == 0) { + iort = entry->q_table; + break; + } + } + if (iort == NULL) + return 0; + + /* Find our root complex. */ + offset = iort->offset; + for (i = 0; i < iort->number_of_nodes; i++) { + node = (struct acpi_iort_node *)((char *)iort + offset); + if (node->type == ACPI_IORT_ROOT_COMPLEX) { + rc = (struct acpi_iort_rc_node *)&node[1]; + if (rc->segment == am->am_segment) + break; + } + offset += node->length; + } + + /* No RC found? Weird. */ + if (i >= iort->number_of_nodes) + return 0; + + /* Find our output base towards SMMU. */ + map = (struct acpi_iort_mapping *)((char *)node + node->mapping_offset); + for (i = 0; i < node->number_of_mappings; i++) { + offset = map[i].output_reference; + + if (map[i].flags & ACPI_IORT_MAPPING_SINGLE) { + rid = map[i].output_base; + break; + } + + /* Mapping encodes number of IDs in the range minus one. */ + if (map[i].input_base <= rid && + rid <= map[i].input_base + map[i].number_of_ids) { + rid = map[i].output_base + (rid - map[i].input_base); + break; + } + } + + /* No mapping found? Even weirder. */ + if (i >= node->number_of_mappings) + return 0; + + node = (struct acpi_iort_node *)((char *)iort + offset); + if (node->type == ACPI_IORT_SMMU || node->type == ACPI_IORT_SMMU_V3) { + pa->pa_dmat = acpiiort_smmu_map(node, rid, pa->pa_dmat); + for (at = pa->pa_iot->bus_private; at; at = at->at_next) { + acpiiort_smmu_reserve_region(node, rid, + at->at_base, at->at_size); + } + for (at = pa->pa_memt->bus_private; at; at = at->at_next) { + acpiiort_smmu_reserve_region(node, rid, + at->at_base, at->at_size); + } + } + + return 0; +} + +int +acpipci_intr_swizzle(struct pci_attach_args *pa, pci_intr_handle_t *ihp) +{ + int dev, swizpin; + pcireg_t id; + + if (pa->pa_bridgeih == NULL) + return -1; + + pci_decompose_tag(pa->pa_pc, pa->pa_tag, NULL, &dev, NULL); + swizpin = PPB_INTERRUPT_SWIZZLE(pa->pa_rawintrpin, dev); + + /* + * Qualcomm SC8280XP Root Complex violates PCI bridge + * interrupt swizzling rules. + */ + if (pa->pa_bridgetag) { + id = pci_conf_read(pa->pa_pc, *pa->pa_bridgetag, PCI_ID_REG); + if (PCI_VENDOR(id) == PCI_VENDOR_QUALCOMM && + PCI_PRODUCT(id) == PCI_PRODUCT_QUALCOMM_SC8280XP_PCIE) { + swizpin = (((swizpin - 1) + 3) % 4) + 1; + } + } + + if (pa->pa_bridgeih[swizpin - 1].ih_type == PCI_NONE) + return -1; + + *ihp = pa->pa_bridgeih[swizpin - 1]; + return 0; +} + +int +acpipci_getirq(int crsidx, union acpi_resource *crs, void *arg) +{ + int *irq = arg; + + switch (AML_CRSTYPE(crs)) { + case SR_IRQ: + *irq = ffs(letoh16(crs->sr_irq.irq_mask)) - 1; + break; + case LR_EXTIRQ: + *irq = letoh32(crs->lr_extirq.irq[0]); + break; + default: + break; + } + + return 0; +} + +int +acpipci_intr_link(struct acpipci_softc *sc, struct aml_node *node, + struct aml_value *val) +{ + struct aml_value res; + int64_t sta; + int irq = -1; + + if (val->type == AML_OBJTYPE_NAMEREF) { + node = aml_searchrel(node, aml_getname(val->v_nameref)); + if (node) + val = node->value; + } + if (val->type == AML_OBJTYPE_OBJREF) + val = val->v_objref.ref; + if (val->type != AML_OBJTYPE_DEVICE) + return -1; + + sta = acpi_getsta(sc->sc_acpi, val->node); + if ((sta & STA_PRESENT) == 0) + return -1; + + if (aml_evalname(sc->sc_acpi, val->node, "_CRS", 0, NULL, &res)) + return -1; + aml_parse_resource(&res, acpipci_getirq, &irq); + aml_freevalue(&res); + + return irq; +} + +int +acpipci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp) +{ + struct acpipci_softc *sc = pa->pa_pc->pc_intr_v; + struct aml_node *node = sc->sc_node; + struct aml_value res; + uint64_t addr, pin, source, index; + int i; + + /* + * If we're behind a bridge, we need to look for a _PRT for + * it. If we don't find a _PRT, we need to swizzle. If we're + * not behind a bridge we need to look for a _PRT on the host + * bridge node itself. + */ + if (pa->pa_bridgetag) { + node = acpi_find_pci(pa->pa_pc, *pa->pa_bridgetag); + if (node == NULL) + return acpipci_intr_swizzle(pa, ihp); + } + + if (aml_evalname(sc->sc_acpi, node, "_PRT", 0, NULL, &res)) + return acpipci_intr_swizzle(pa, ihp); + + if (res.type != AML_OBJTYPE_PACKAGE) + return -1; + + for (i = 0; i < res.length; i++) { + struct aml_value *val = res.v_package[i]; + + if (val->type != AML_OBJTYPE_PACKAGE) + continue; + if (val->length != 4) + continue; + if (val->v_package[0]->type != AML_OBJTYPE_INTEGER || + val->v_package[1]->type != AML_OBJTYPE_INTEGER || + val->v_package[3]->type != AML_OBJTYPE_INTEGER) + continue; + + addr = val->v_package[0]->v_integer; + pin = val->v_package[1]->v_integer; + if (ACPI_ADR_PCIDEV(addr) != pa->pa_device || + ACPI_ADR_PCIFUN(addr) != 0xffff || + pin != pa->pa_intrpin - 1) + continue; + + if (val->v_package[2]->type == AML_OBJTYPE_INTEGER) { + source = val->v_package[2]->v_integer; + index = val->v_package[3]->v_integer; + } else { + source = 0; + index = acpipci_intr_link(sc, node, val->v_package[2]); + } + if (source != 0 || index == -1) + continue; + + ihp->ih_pc = pa->pa_pc; + ihp->ih_tag = pa->pa_tag; + ihp->ih_intrpin = index; + ihp->ih_type = PCI_INTX; + + return 0; + } + + return -1; +} + +const char * +acpipci_intr_string(void *v, pci_intr_handle_t ih) +{ + static char irqstr[32]; + + switch (ih.ih_type) { + case PCI_MSI: + return "msi"; + case PCI_MSIX: + return "msix"; + } + + snprintf(irqstr, sizeof(irqstr), "irq %d", ih.ih_intrpin); + return irqstr; +} + +void * +acpipci_intr_establish(void *v, pci_intr_handle_t ih, int level, + struct cpu_info *ci, int (*func)(void *), void *arg, char *name) +{ + struct acpipci_softc *sc = v; + struct acpipci_intr_handle *aih; + void *cookie; + + KASSERT(ih.ih_type != PCI_NONE); + + if (ih.ih_type != PCI_INTX) { + struct interrupt_controller *ic = sc->sc_msi_ic; + bus_dma_segment_t seg; + uint64_t addr = 0, data; + + KASSERT(ic); + + /* Map Requester ID through IORT to get sideband data. */ + data = acpipci_iort_map_msi(ih.ih_pc, ih.ih_tag, &ic); + cookie = ic->ic_establish_msi(ic->ic_cookie, &addr, + &data, level, ci, func, arg, name); + if (cookie == NULL) + return NULL; + + aih = malloc(sizeof(*aih), M_DEVBUF, M_WAITOK); + aih->aih_ih.ih_ic = ic; + aih->aih_ih.ih_ih = cookie; + aih->aih_dmat = ih.ih_dmat; + + if (bus_dmamap_create(aih->aih_dmat, sizeof(uint32_t), 1, + sizeof(uint32_t), 0, BUS_DMA_WAITOK, &aih->aih_map)) { + free(aih, M_DEVBUF, sizeof(*aih)); + ic->ic_disestablish(cookie); + return NULL; + } + + memset(&seg, 0, sizeof(seg)); + seg.ds_addr = addr; + seg.ds_len = sizeof(uint32_t); + + if (bus_dmamap_load_raw(aih->aih_dmat, aih->aih_map, + &seg, 1, sizeof(uint32_t), BUS_DMA_WAITOK)) { + bus_dmamap_destroy(aih->aih_dmat, aih->aih_map); + free(aih, M_DEVBUF, sizeof(*aih)); + ic->ic_disestablish(cookie); + return NULL; + } + + addr = aih->aih_map->dm_segs[0].ds_addr; + if (ih.ih_type == PCI_MSIX) { + pci_msix_enable(ih.ih_pc, ih.ih_tag, + &sc->sc_bus_memt, ih.ih_intrpin, addr, data); + } else + pci_msi_enable(ih.ih_pc, ih.ih_tag, addr, data); + + cookie = aih; + } else { + if (ci != NULL && !CPU_IS_PRIMARY(ci)) + return NULL; + cookie = acpi_intr_establish(ih.ih_intrpin, 0, level, + func, arg, name); + } + + return cookie; +} + +void +acpipci_intr_disestablish(void *v, void *cookie) +{ + struct acpipci_intr_handle *aih = cookie; + struct interrupt_controller *ic = aih->aih_ih.ih_ic; + + if (ic->ic_establish_msi) { + ic->ic_disestablish(aih->aih_ih.ih_ih); + bus_dmamap_unload(aih->aih_dmat, aih->aih_map); + bus_dmamap_destroy(aih->aih_dmat, aih->aih_map); + free(aih, M_DEVBUF, sizeof(*aih)); + } else + acpi_intr_disestablish(cookie); +} + +/* + * Translate memory address if needed. + */ +int +acpipci_bs_map(bus_space_tag_t t, bus_addr_t addr, bus_size_t size, + int flags, bus_space_handle_t *bshp) +{ + struct acpipci_trans *at; + + for (at = t->bus_private; at; at = at->at_next) { + if (addr >= at->at_base && addr < at->at_base + at->at_size) { + return bus_space_map(at->at_iot, + addr + at->at_offset, size, flags, bshp); + } + } + + return ENXIO; +} + +paddr_t +acpipci_bs_mmap(bus_space_tag_t t, bus_addr_t addr, off_t off, + int prot, int flags) +{ + struct acpipci_trans *at; + + for (at = t->bus_private; at; at = at->at_next) { + if (addr >= at->at_base && addr < at->at_base + at->at_size) { + return bus_space_mmap(at->at_iot, + addr + at->at_offset, off, prot, flags); + } + } + + return -1; +} + +SLIST_HEAD(,acpipci_mcfg) acpipci_mcfgs = + SLIST_HEAD_INITIALIZER(acpipci_mcfgs); + +void +pci_mcfg_init(bus_space_tag_t iot, bus_addr_t addr, int segment, + int min_bus, int max_bus) +{ + struct acpipci_mcfg *am; + + am = malloc(sizeof(struct acpipci_mcfg), M_DEVBUF, M_WAITOK | M_ZERO); + am->am_segment = segment; + am->am_min_bus = min_bus; + am->am_max_bus = max_bus; + + am->am_iot = iot; + if (bus_space_map(iot, addr, (max_bus + 1) << 20, 0, &am->am_ioh)) + panic("%s: can't map config space", __func__); + + am->am_pc.pc_conf_v = am; + am->am_pc.pc_attach_hook = acpipci_attach_hook; + am->am_pc.pc_bus_maxdevs = acpipci_bus_maxdevs; + am->am_pc.pc_make_tag = acpipci_make_tag; + am->am_pc.pc_decompose_tag = acpipci_decompose_tag; + am->am_pc.pc_conf_size = acpipci_conf_size; + am->am_pc.pc_conf_read = acpipci_conf_read; + am->am_pc.pc_conf_write = acpipci_conf_write; + SLIST_INSERT_HEAD(&acpipci_mcfgs, am, am_list); +} + +pcireg_t +acpipci_dummy_conf_read(void *v, pcitag_t tag, int reg) +{ + return 0xffffffff; +} + +void +acpipci_dummy_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data) +{ +} + +struct machine_pci_chipset acpipci_dummy_chipset = { + .pc_attach_hook = acpipci_attach_hook, + .pc_bus_maxdevs = acpipci_bus_maxdevs, + .pc_make_tag = acpipci_make_tag, + .pc_decompose_tag = acpipci_decompose_tag, + .pc_conf_size = acpipci_conf_size, + .pc_conf_read = acpipci_dummy_conf_read, + .pc_conf_write = acpipci_dummy_conf_write, +}; + +pci_chipset_tag_t +pci_lookup_segment(int segment, int bus) +{ + struct acpipci_mcfg *am; + + SLIST_FOREACH(am, &acpipci_mcfgs, am_list) { + if (segment == am->am_segment && + bus >= am->am_min_bus && bus <= am->am_max_bus) + return &am->am_pc; + } + + return &acpipci_dummy_chipset; +} + +/* + * IORT support. + */ + +uint32_t acpipci_iort_map(struct acpi_iort *, uint32_t, uint32_t, + struct interrupt_controller **); + +uint32_t +acpipci_iort_map_node(struct acpi_iort *iort, + struct acpi_iort_node *node, uint32_t id, struct interrupt_controller **ic) +{ + struct acpi_iort_mapping *map = + (struct acpi_iort_mapping *)((char *)node + node->mapping_offset); + int i; + + for (i = 0; i < node->number_of_mappings; i++) { + uint32_t offset = map[i].output_reference; + + if (map[i].flags & ACPI_IORT_MAPPING_SINGLE) { + id = map[i].output_base; + return acpipci_iort_map(iort, offset, id, ic); + } + + /* Mapping encodes number of IDs in the range minus one. */ + if (map[i].input_base <= id && + id <= map[i].input_base + map[i].number_of_ids) { + id = map[i].output_base + (id - map[i].input_base); + return acpipci_iort_map(iort, offset, id, ic); + } + } + + return id; +} + +uint32_t +acpipci_iort_map(struct acpi_iort *iort, uint32_t offset, uint32_t id, + struct interrupt_controller **ic) +{ + struct acpi_iort_node *node = + (struct acpi_iort_node *)((char *)iort + offset); + struct interrupt_controller *icl; + struct acpi_iort_its_node *itsn; + int i; + + switch (node->type) { + case ACPI_IORT_ITS: + itsn = (struct acpi_iort_its_node *)&node[1]; + LIST_FOREACH(icl, &interrupt_controllers, ic_list) { + for (i = 0; i < itsn->number_of_itss; i++) { + if (icl->ic_establish_msi != NULL) { + *ic = icl; + break; + } + } + } + + return id; + case ACPI_IORT_SMMU: + case ACPI_IORT_SMMU_V3: + return acpipci_iort_map_node(iort, node, id, ic); + } + + return id; +} + +uint32_t +acpipci_iort_map_msi(pci_chipset_tag_t pc, pcitag_t tag, + struct interrupt_controller **ic) +{ + struct acpipci_softc *sc = pc->pc_intr_v; + struct acpi_table_header *hdr; + struct acpi_iort *iort = NULL; + struct acpi_iort_node *node; + struct acpi_iort_rc_node *rc; + struct acpi_q *entry; + uint32_t rid, offset; + int i; + + rid = pci_requester_id(pc, tag); + + /* Look for IORT table. */ + SIMPLEQ_FOREACH(entry, &sc->sc_acpi->sc_tables, q_next) { + hdr = entry->q_table; + if (strncmp(hdr->signature, IORT_SIG, + sizeof(hdr->signature)) == 0) { + iort = entry->q_table; + break; + } + } + if (iort == NULL) + return rid; + + /* Find our root complex and map. */ + offset = iort->offset; + for (i = 0; i < iort->number_of_nodes; i++) { + node = (struct acpi_iort_node *)((char *)iort + offset); + switch (node->type) { + case ACPI_IORT_ROOT_COMPLEX: + rc = (struct acpi_iort_rc_node *)&node[1]; + if (rc->segment == sc->sc_seg) + return acpipci_iort_map_node(iort, node, rid, + ic); + break; + } + offset += node->length; + } + + return rid; +} diff --git sys/arch/loongarch64/dev/aplic.c sys/arch/loongarch64/dev/aplic.c new file mode 100644 index 00000000000..f4eba706a60 --- /dev/null +++ sys/arch/loongarch64/dev/aplic.c @@ -0,0 +1,228 @@ +/* $OpenBSD: aplic.c,v 1.1 2026/07/24 10:51:00 kettenis Exp $ */ +/* + * Copyright (c) 2026 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define APLIC_DOMAINCFG 0x0000 +#define APLIC_DOMAINCFG_IE (1 << 8) +#define APLIC_DOMAINCFG_DM_MSI (1 << 2) +#define APLIC_SOURCECFG(x) (0x0000 + (x) * 4) +#define APLIC_SOURCECFG_SM_DETACHED (1 << 0) +#define APLIC_SOURCECFG_SM_EDGE1 (4 << 0) +#define APLIC_SOURCECFG_SM_EDGE0 (5 << 0) +#define APLIC_SOURCECFG_SM_LEVEL1 (6 << 0) +#define APLIC_SOURCECFG_SM_LEVEL0 (7 << 0) +#define APLIC_SETIP(x) (0x1c00 + (x) * 4) +#define APLIC_SETIPNUM 0x1cdc +#define APLIC_SETIE(x) (0x1e00 + (x) * 4) +#define APLIC_SETIENUM 0x1edc +#define APLIC_SETIPNUM_LE 0x2000 +#define APLIC_SETIPNUM_BE 0x2004 +#define APLIC_GENMSI 0x3000 +#define APLIC_TARGET(x) (0x3000 + (x) * 4) +#define APLIC_TARGET_HARTID_SHIFT 18 + +#define HREAD4(sc, reg) \ + (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) +#define HWRITE4(sc, reg, val) \ + bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) + +struct aplic_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + int sc_node; + + struct interrupt_controller sc_ic; +}; + +struct aplic_intrhand { + struct aplic_softc *aih_sc; + void *aih_cookie; + uint16_t aih_source; + int (*aih_func)(void *); + void *aih_arg; + int aih_eoi; +}; + +int aplic_match(struct device *, void *, void *); +void aplic_attach(struct device *, struct device *, void *); + +const struct cfattach aplic_ca = { + sizeof (struct aplic_softc), aplic_match, aplic_attach +}; + +struct cfdriver aplic_cd = { + NULL, "aplic", DV_DULL +}; + +void *aplic_intr_establish(void *, int *, int, struct cpu_info *, + int (*)(void *), void *, char *); +void aplic_intr_disestablish(void *); +void aplic_intr_barrier(void *); + +int +aplic_match(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *faa = aux; + + return OF_is_compatible(faa->fa_node, "riscv,aplic"); +} + +void +aplic_attach(struct device *parent, struct device *self, void *aux) +{ + struct aplic_softc *sc = (struct aplic_softc *)self; + struct fdt_attach_args *faa = aux; + bus_size_t reg; + + if (faa->fa_nreg < 1) { + printf(": no registers\n"); + return; + } + + sc->sc_iot = faa->fa_iot; + if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, + faa->fa_reg[0].size, 0, &sc->sc_ioh)) { + printf(": can't map registers\n"); + return; + } + sc->sc_node = faa->fa_node; + + printf("\n"); + + /* Disable all interrupts before we enable the controller. */ + for (reg = APLIC_SETIE(0); reg <= APLIC_SETIE(31); reg += 4) + HWRITE4(sc, reg, 0); + + /* Enable the controller in MSI delivery mode. */ + HWRITE4(sc, APLIC_DOMAINCFG, + APLIC_DOMAINCFG_IE | APLIC_DOMAINCFG_DM_MSI); + + sc->sc_ic.ic_node = sc->sc_node; + sc->sc_ic.ic_cookie = sc; + sc->sc_ic.ic_establish = aplic_intr_establish; + sc->sc_ic.ic_disestablish = aplic_intr_disestablish; + sc->sc_ic.ic_barrier = aplic_intr_barrier; + fdt_intr_register(&sc->sc_ic); +} + +int +aplic_intr(void *arg) +{ + struct aplic_intrhand *aih = arg; + int handled; + + handled = aih->aih_func(aih->aih_arg); + + if (aih->aih_eoi) + HWRITE4(aih->aih_sc, APLIC_SETIPNUM, aih->aih_source); + + return handled; +} + +void * +aplic_intr_establish(void *cookie, int *cells, int level, struct cpu_info *ci, + int (*func)(void *), void *arg, char *name) +{ + struct aplic_softc *sc = cookie; + struct aplic_intrhand *aih; + uint64_t addr, data; + uint32_t source = cells[0]; + uint32_t sourcecfg, target; + + if (ci == NULL) + ci = &cpu_info_primary; + + KASSERT(source > 0); + KASSERT(source < 1024); + + aih = malloc(sizeof(*aih), M_DEVBUF, M_WAITOK | M_ZERO); + aih->aih_sc = sc; + aih->aih_source = source; + aih->aih_func = func; + aih->aih_arg = arg; + + aih->aih_cookie = fdt_intr_establish_msi_cpu(sc->sc_node, &addr, &data, + level, ci, aplic_intr, aih, name); + if (aih->aih_cookie == NULL) { + free(aih, M_DEVBUF, sizeof(*aih)); + return NULL; + } + + KASSERT(data > 0); + KASSERT(data < 2048); + + /* XXX This assumes hart ID and hart index are the same. */ + target = ci->ci_hartid << APLIC_TARGET_HARTID_SHIFT | data; + + switch (cells[1]) { + case 1: + sourcecfg = APLIC_SOURCECFG_SM_EDGE1; + break; + case 2: + sourcecfg = APLIC_SOURCECFG_SM_EDGE0; + break; + case 4: + sourcecfg = APLIC_SOURCECFG_SM_LEVEL1; + aih->aih_eoi = 1; + break; + case 8: + sourcecfg = APLIC_SOURCECFG_SM_LEVEL0; + aih->aih_eoi = 1; + break; + default: + sourcecfg = APLIC_SOURCECFG_SM_DETACHED; + break; + } + + HWRITE4(sc, APLIC_SOURCECFG(source), sourcecfg); + HWRITE4(sc, APLIC_TARGET(source), target); + HWRITE4(sc, APLIC_SETIENUM, source); + + if (aih->aih_eoi) + HWRITE4(aih->aih_sc, APLIC_SETIPNUM, aih->aih_source); + + return aih; +} + +void +aplic_intr_disestablish(void *cookie) +{ + struct aplic_intrhand *aih = cookie; + + fdt_intr_disestablish(aih->aih_cookie); + free(aih, M_DEVBUF, sizeof(*aih)); +} + +void +aplic_intr_barrier(void *cookie) +{ + struct aplic_intrhand *aih = cookie; + + intr_barrier(aih->aih_cookie); +} diff --git sys/arch/loongarch64/dev/efi_machdep.c sys/arch/loongarch64/dev/efi_machdep.c new file mode 100644 index 00000000000..1740829b282 --- /dev/null +++ sys/arch/loongarch64/dev/efi_machdep.c @@ -0,0 +1,324 @@ +/* $OpenBSD: efi_machdep.c,v 1.6 2023/01/14 12:11:11 kettenis Exp $ */ + +/* + * Copyright (c) 2017 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +/* + * We need a large address space to allow identity mapping of physical + * memory on some machines. + */ +#define EFI_SPACE_BITS 48 + +extern uint32_t mmap_size; +extern uint32_t mmap_desc_size; +extern uint32_t mmap_desc_ver; + +extern EFI_MEMORY_DESCRIPTOR *mmap; + +uint64_t efi_acpi_table; +uint64_t efi_smbios_table; + +int efi_match(struct device *, void *, void *); +void efi_attach(struct device *, struct device *, void *); + +const struct cfattach efi_ca = { + sizeof(struct efi_softc), efi_match, efi_attach +}; + +void efi_map_runtime(struct efi_softc *); +int efi_gettime(struct todr_chip_handle *, struct timeval *); +int efi_settime(struct todr_chip_handle *, struct timeval *); + +label_t efi_jmpbuf; + +int +efi_match(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *faa = aux; + + return (strcmp(faa->fa_name, "efi") == 0); +} + +void +efi_attach(struct device *parent, struct device *self, void *aux) +{ + struct efi_softc *sc = (struct efi_softc *)self; + struct fdt_attach_args *faa = aux; + uint64_t system_table; + bus_space_handle_t ioh; + EFI_SYSTEM_TABLE *st; + EFI_TIME time; + EFI_STATUS status; + uint16_t major, minor; + int node, i; + + node = OF_finddevice("/chosen"); + KASSERT(node != -1); + + system_table = OF_getpropint64(node, "openbsd,uefi-system-table", 0); + KASSERT(system_table); + + if (bus_space_map(faa->fa_iot, system_table, sizeof(EFI_SYSTEM_TABLE), + BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_CACHEABLE, &ioh)) { + printf(": can't map system table\n"); + return; + } + + st = bus_space_vaddr(faa->fa_iot, ioh); + sc->sc_rs = st->RuntimeServices; + + major = st->Hdr.Revision >> 16; + minor = st->Hdr.Revision & 0xffff; + printf(": UEFI %d.%d", major, minor / 10); + if (minor % 10) + printf(".%d", minor % 10); + printf("\n"); + + /* Early implementations can be buggy. */ + if (major < 2 || (major == 2 && minor < 10)) + return; + + efi_map_runtime(sc); + + /* + * Activate our pmap such that we can access the + * FirmwareVendor and ConfigurationTable fields. + */ + efi_enter(sc); + if (st->FirmwareVendor) { + printf("%s: ", sc->sc_dev.dv_xname); + for (i = 0; st->FirmwareVendor[i]; i++) + printf("%c", st->FirmwareVendor[i]); + printf(" rev 0x%x\n", st->FirmwareRevision); + } + for (i = 0; i < st->NumberOfTableEntries; i++) { + EFI_CONFIGURATION_TABLE *ct = &st->ConfigurationTable[i]; + static EFI_GUID acpi_guid = EFI_ACPI_20_TABLE_GUID; + static EFI_GUID smbios_guid = SMBIOS_TABLE_GUID; + static EFI_GUID smbios3_guid = SMBIOS3_TABLE_GUID; + + if (efi_guidcmp(&acpi_guid, &ct->VendorGuid) == 0) + efi_acpi_table = (uint64_t)ct->VendorTable; + if (efi_guidcmp(&smbios_guid, &ct->VendorGuid) == 0) + efi_smbios_table = (uint64_t)ct->VendorTable; + if (efi_guidcmp(&smbios3_guid, &ct->VendorGuid) == 0) + efi_smbios_table = (uint64_t)ct->VendorTable; + } + efi_leave(sc); + + if (efi_smbios_table != 0) { + struct fdt_reg reg = { .addr = efi_smbios_table }; + struct fdt_attach_args fa; + + fa.fa_name = "smbios"; + fa.fa_iot = faa->fa_iot; + fa.fa_reg = ® + fa.fa_nreg = 1; + config_found(self, &fa, NULL); + } + + if (efi_enter_check(sc)) + return; + status = sc->sc_rs->GetTime(&time, NULL); + efi_leave(sc); + if (status != EFI_SUCCESS) + return; + + /* + * EDK II implementations provide an implementation of + * GetTime() that returns a fixed compiled-in time on hardware + * without a (supported) RTC. So only use this interface as a + * last resort. + */ + sc->sc_todr.cookie = sc; + sc->sc_todr.todr_gettime = efi_gettime; + sc->sc_todr.todr_settime = efi_settime; + sc->sc_todr.todr_quality = -1000; + todr_attach(&sc->sc_todr); +} + +void +efi_map_runtime(struct efi_softc *sc) +{ + EFI_MEMORY_DESCRIPTOR *desc; + int i; + + /* + * We don't really want some random executable non-OpenBSD + * code lying around in kernel space. So create a separate + * pmap and only activate it when we call runtime services. + */ + sc->sc_pm = pmap_create(); + sc->sc_pm->pm_privileged = 1; + + desc = mmap; + for (i = 0; i < mmap_size / mmap_desc_size; i++) { + if (desc->Attribute & EFI_MEMORY_RUNTIME) { + vaddr_t va = desc->VirtualStart; + paddr_t pa = desc->PhysicalStart; + int npages = desc->NumberOfPages; + vm_prot_t prot = PROT_READ | PROT_WRITE; + +#ifdef EFI_DEBUG + printf("type 0x%x pa 0x%llx va 0x%llx pages 0x%llx attr 0x%llx\n", + desc->Type, desc->PhysicalStart, + desc->VirtualStart, desc->NumberOfPages, + desc->Attribute); +#endif + + /* + * If the virtual address is still zero, use + * an identity mapping. + */ + if (va == 0) + va = pa; + + /* + * Normal memory is expected to be "write + * back" cacheable. Everything else is mapped + * as device memory. + */ + if ((desc->Attribute & EFI_MEMORY_WB) == 0) + pa |= PMAP_DEVICE; + + /* + * Only make pages marked as runtime service code + * executable. This violates the standard but it + * seems we can get away with it. + */ + if (desc->Type == EfiRuntimeServicesCode) + prot |= PROT_EXEC; + + if (desc->Attribute & EFI_MEMORY_RP) + prot &= ~PROT_READ; + if (desc->Attribute & EFI_MEMORY_XP) + prot &= ~PROT_EXEC; + if (desc->Attribute & EFI_MEMORY_RO) + prot &= ~PROT_WRITE; + + while (npages--) { + pmap_enter(sc->sc_pm, va, pa, prot, + prot | PMAP_WIRED); + va += PAGE_SIZE; + pa += PAGE_SIZE; + } + } + + desc = NextMemoryDescriptor(desc, mmap_desc_size); + } +} + +void +efi_fault(void) +{ + longjmp(&efi_jmpbuf); +} + +void +efi_enter(struct efi_softc *sc) +{ + + sc->sc_psw = intr_disable(); + + curcpu()->ci_curpcb->pcb_onfault = (void *)efi_fault; +} + +void +efi_leave(struct efi_softc *sc) +{ + curcpu()->ci_curpcb->pcb_onfault = NULL; + + intr_restore(sc->sc_psw); +} + +int +efi_gettime(struct todr_chip_handle *handle, struct timeval *tv) +{ + struct efi_softc *sc = handle->cookie; + struct clock_ymdhms dt; + EFI_TIME time; + EFI_STATUS status; + + if (efi_enter_check(sc)) + return EFAULT; + status = sc->sc_rs->GetTime(&time, NULL); + efi_leave(sc); + if (status != EFI_SUCCESS) + return EIO; + + dt.dt_year = time.Year; + dt.dt_mon = time.Month; + dt.dt_day = time.Day; + dt.dt_hour = time.Hour; + dt.dt_min = time.Minute; + dt.dt_sec = time.Second; + + if (dt.dt_sec > 59 || dt.dt_min > 59 || dt.dt_hour > 23 || + dt.dt_day > 31 || dt.dt_day == 0 || + dt.dt_mon > 12 || dt.dt_mon == 0 || + dt.dt_year < POSIX_BASE_YEAR) + return EINVAL; + + tv->tv_sec = clock_ymdhms_to_secs(&dt); + tv->tv_usec = 0; + return 0; +} + +int +efi_settime(struct todr_chip_handle *handle, struct timeval *tv) +{ + struct efi_softc *sc = handle->cookie; + struct clock_ymdhms dt; + EFI_TIME time; + EFI_STATUS status; + + clock_secs_to_ymdhms(tv->tv_sec, &dt); + + time.Year = dt.dt_year; + time.Month = dt.dt_mon; + time.Day = dt.dt_day; + time.Hour = dt.dt_hour; + time.Minute = dt.dt_min; + time.Second = dt.dt_sec; + time.Nanosecond = 0; + time.TimeZone = 0; + time.Daylight = 0; + + if (efi_enter_check(sc)) + return EFAULT; + status = sc->sc_rs->SetTime(&time); + efi_leave(sc); + if (status != EFI_SUCCESS) + return EIO; + return 0; +} diff --git sys/arch/loongarch64/dev/if_smte.c sys/arch/loongarch64/dev/if_smte.c new file mode 100644 index 00000000000..22aeca8aeb5 --- /dev/null +++ sys/arch/loongarch64/dev/if_smte.c @@ -0,0 +1,1249 @@ +/* $OpenBSD: if_smte.c,v 1.2 2026/05/11 10:25:52 kettenis Exp $ */ +/* + * Copyright (c) 2017 Patrick Wildt + * Copyright (c) 2026 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Driver for the ethernet controller on the SpacemiT K1 SoC. + */ + +#include "bpfilter.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if NBPFILTER > 0 +#include +#endif + +#include +#include + +/* DMA/MAC registers */ +#define DMA_CONFIG 0x0000 +#define DMA_CONFIG_DMA_64BIT_MODE (1U << 18) +#define DMA_CONFIG_STRICT_BURST (1U << 17) +#define DMA_CONFIG_BURST_LENGTH_MASK (0x7f << 1) +#define DMA_CONFIG_BURST_LENGTH_16 (0x10 << 1) +#define DMA_CONFIG_SOFTWARE_RESET (1U << 0) +#define DMA_CTRL 0x0004 +#define DMA_CTRL_START_STOP_RX_DMA (1U << 1) +#define DMA_CTRL_START_STOP_TX_DMA (1U << 0) +#define DMA_STATUS_IRQ 0x0008 +#define DMA_STATUS_IRQ_RX_MISSED_FRAME (1U << 7) +#define DMA_STATUS_IRQ_RX_DMA_STOPPED (1U << 6) +#define DMA_STATUS_IRQ_RX_DES_UNAVAILABLE (1U << 5) +#define DMA_STATUS_IRQ_RX_TRANSFER_DONE (1U << 4) +#define DMA_STATUS_IRQ_TX_TRANSFER_DONE (1U << 0) +#define DMA_INTR_ENABLE 0x000c +#define DMA_INTR_ENABLE_RX_MISSED_FRAME (1U << 7) +#define DMA_INTR_ENABLE_RX_DMA_STOPPED (1U << 6) +#define DMA_INTR_ENABLE_RX_DES_UNAVAILABLE (1U << 5) +#define DMA_INTR_ENABLE_RX_TRANSFER_DONE (1U << 4) +#define DMA_INTR_ENABLE_TX_TRANSFER_DONE (1U << 0) +#define DMA_TRANSMIT_AUTO_POLL_COUNTER 0x0010 +#define DMA_TRANSMIT_POLL_DEMAND 0x0014 +#define DMA_RECEIVE_POLL_DEMAND 0x0018 +#define DMA_TRANSMIT_BASE_ADDRESS 0x001c +#define DMA_RECEIVE_BASE_ADDRESS 0x0020 +#define DMA_RECEIVE_IRQ_MITIGATION 0x002c +#define DMA_RECEIVE_IRQ_MITIGATION_FRAME_COUNTER_SHIFT 0 +#define DMA_RECEIVE_IRQ_MITIGATION_TIMEOUT_COUNTER_SHIFT 8 +#define DMA_RECEIVE_IRQ_MITIGATION_MITIGATION_ENABLE (1U << 31) +#define MAC_GLOBAL_CTRL 0x0100 +#define MAC_GLOBAL_CTRL_DUPLEX_MODE (1U << 2) +#define MAC_GLOBAL_CTRL_SPEED_MASK (0x3 << 0) +#define MAC_GLOBAL_CTRL_SPEED_10 (0x0 << 0) +#define MAC_GLOBAL_CTRL_SPEED_100 (0x1 << 0) +#define MAC_GLOBAL_CTRL_SPEED_1000 (0x2 << 0) +#define MAC_TRANSMIT_CTRL 0x0104 +#define MAC_TRANSMIT_CTRL_IFG_LEN_MASK (0x7 << 4) +#define MAC_TRANSMIT_CTRL_TX_AUTO_RETRY (1U << 3) +#define MAC_TRANSMIT_CTRL_TX_ENABLE (1U << 0) +#define MAC_RECEIVE_CTRL 0x0108 +#define MAC_RECEIVE_CTRL_STORE_FORWARD (1U << 3) +#define MAC_RECEIVE_CTRL_RX_ENABLE (1U << 0) +#define MAC_MAXIMUM_FRAME_SIZE 0x010c +#define MAC_TRANSMIT_JABBER_SIZE 0x0110 +#define MAC_RECEIVE_JABBER_SIZE 0x0114 +#define MAC_ADDR_CTRL 0x0118 +#define MAC_ADDR_CTRL_PROMISCUOUS_MODE (1U << 8) +#define MAC_ADDR_CTRL_MAC_ADDR1_ENABLE (1U << 0) +#define MAC_ADDR1_HI 0x0120 +#define MAC_ADDR1_ME 0x0124 +#define MAC_ADDR1_LO 0x0128 +#define MAC_MULTICAST_HASH_TABLE1 0x0150 +#define MAC_MULTICAST_HASH_TABLE2 0x0154 +#define MAC_MULTICAST_HASH_TABLE3 0x0158 +#define MAC_MULTICAST_HASH_TABLE4 0x015c +#define MAC_MDIO_CTRL 0x01a0 +#define MAC_MDIO_CTRL_START_MDIO_TRANS (1U << 15) +#define MAC_MDIO_CTRL_MDIO_READ_WRITE (1U << 10) +#define MAC_MDIO_CTRL_REGISTER_ADDRESS_SHIFT 5 +#define MAC_MDIO_CTRL_PHY_ADDRESS_SHIFT 0 +#define MAC_MDIO_DATA 0x01a4 +#define MAC_TRANSMIT_FIFO_ALMOST_FULL 0x01c0 +#define MAC_TRANSMIT_PACKET_START_THRESHOLD 0x01c4 +#define MAC_RECEIVE_PACKET_START_THRESHOLD 0x01c8 +#define MAC_INTR_ENABLE 0x01e4 + +/* APMU registers */ +#define APMU_EMAC_CLK_RST_CTRL 0x0000 +#define APMU_EMAC_AXI_MST_ID (1U << 13) +#define APMU_EMAC_PHY_INTR_EN (1U << 12) +#define APMU_EMAC_RGMII_TXC_SRC_SEL (1U << 8) +#define APMU_EMAC_RGMII_DLINE 0x0004 +#define APMU_EMAC_RGMII_DLINE_TX_DELAY_MASK (0xff << 24) +#define APMU_EMAC_RGMII_DLINE_TX_DELAY_SHIFT 8 +#define APMU_EMAC_RGMII_DLINE_TX_STEP_MASK (0x3 << 20) +#define APMU_EMAC_RGMII_DLINE_TX_STEP_15P6 (0x0 << 20) +#define APMU_EMAC_RGMII_DLINE_TX_EN (1U << 16) +#define APMU_EMAC_RGMII_DLINE_RX_DELAY_MASK (0xff << 8) +#define APMU_EMAC_RGMII_DLINE_RX_DELAY_SHIFT 8 +#define APMU_EMAC_RGMII_DLINE_RX_STEP_MASK (0x3 << 4) +#define APMU_EMAC_RGMII_DLINE_RX_STEP_15P6 (0x0 << 4) +#define APMU_EMAC_RGMII_DLINE_RX_EN (1U << 0) + +/* Descriptors */ +struct smte_desc { + uint32_t sd_desc0; + uint32_t sd_desc1; + uint32_t sd_addr1; + uint32_t sd_addr2; +}; + +/* Rx bits */ +#define RX_DESC0_FRAME_PACKET_LENGTH_MASK (0x3fff << 0) +#define RX_DESC0_FRAME_PACKET_LENGTH_SHIFT 0 +#define RX_DESC0_FRAME_RUNT (1U << 15) +#define RX_DESC0_FRAME_CRC_ERR (1U << 20) +#define RX_DESC0_FRAME_MAX_LEN_ERR (1U << 21) +#define RX_DESC0_FRAME_JABBER_ERR (1U << 22) +#define RX_DESC0_FRAME_LENGTH_ERR (1U << 23) +#define RX_DESC0_OWN (1U << 31) +#define RX_DESC1_SIZE1_MASK (0xfffff << 0) +#define RX_DESC1_SIZE1_SHIFT 0 +#define RX_DESC1_SIZE2_MASK (0xfffff << 12) +#define RX_DESC1_SIZE2_SHIFT 12 +#define RX_DESC1_END_RING (1U << 26) + +/* Tx bits */ +#define TX_DESC0_OWN (1U << 31) +#define TX_DESC1_SIZE1_MASK (0xfff << 0) +#define TX_DESC1_SIZE1_SHIFT 0 +#define TX_DESC1_SIZE2_MASK (0xfff << 12) +#define TX_DESC1_SIZE2_SHIFT 12 +#define TX_DESC1_END_RING (1U << 26) +#define TX_DESC1_FIRST_SEGMENT (1U << 29) +#define TX_DESC1_LAST_SEGMENT (1U << 30) +#define TX_DESC1_INTERRUPT_ON_COMPLETION (1U << 31) + +#define HREAD4(sc, reg) \ + (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) +#define HWRITE4(sc, reg, val) \ + bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) +#define HSET4(sc, reg, bits) \ + HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) +#define HCLR4(sc, reg, bits) \ + HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) + +struct smte_buf { + bus_dmamap_t sb_map; + struct mbuf *sb_m; +}; + +#define SMTE_NTXDESC 1024 +#define SMTE_NTXSEGS 16 + +#define SMTE_NRXDESC 1024 + +struct smte_dmamem { + bus_dmamap_t sdm_map; + bus_dma_segment_t sdm_seg; + size_t sdm_size; + caddr_t sdm_kva; +}; +#define SMTE_DMA_MAP(_sdm) ((_sdm)->sdm_map) +#define SMTE_DMA_LEN(_sdm) ((_sdm)->sdm_size) +#define SMTE_DMA_DVA(_sdm) ((_sdm)->sdm_map->dm_segs[0].ds_addr) +#define SMTE_DMA_KVA(_sdm) ((void *)(_sdm)->sdm_kva) + +struct smte_softc { + struct device sc_dev; + int sc_node; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + bus_dma_tag_t sc_dmat; + struct regmap *sc_apmu; + uint32_t sc_apmu_offset; + void *sc_ih; + + struct arpcom sc_ac; +#define sc_lladdr sc_ac.ac_enaddr + struct mii_data sc_mii; +#define sc_media sc_mii.mii_media + int sc_link; + int sc_phyloc; + uint32_t sc_rx_delay; + uint32_t sc_tx_delay; + + struct smte_dmamem *sc_txring; + struct smte_buf *sc_txbuf; + struct smte_desc *sc_txdesc; + int sc_tx_prod; + int sc_tx_cons; + + struct smte_dmamem *sc_rxring; + struct smte_buf *sc_rxbuf; + struct smte_desc *sc_rxdesc; + int sc_rx_prod; + struct if_rxring sc_rx_ring; + int sc_rx_cons; + + struct timeout sc_tick; +}; + +#define DEVNAME(_s) ((_s)->sc_dev.dv_xname) + +int smte_match(struct device *, void *, void *); +void smte_attach(struct device *, struct device *, void *); +void smte_init(struct smte_softc *sc); +void smte_phy_setup_emac(struct smte_softc *); +void smte_phy_setup_gmac(struct smte_softc *); + +const struct cfattach smte_ca = { + sizeof(struct smte_softc), smte_match, smte_attach +}; + +struct cfdriver smte_cd = { + NULL, "smte", DV_IFNET +}; + +uint32_t smte_read(struct smte_softc *, bus_addr_t); +void smte_write(struct smte_softc *, bus_addr_t, uint32_t); + +int smte_ioctl(struct ifnet *, u_long, caddr_t); +void smte_start(struct ifqueue *); + +int smte_media_change(struct ifnet *); +void smte_media_status(struct ifnet *, struct ifmediareq *); + +int smte_mii_readreg(struct device *, int, int); +void smte_mii_writereg(struct device *, int, int, int); +void smte_mii_statchg(struct device *); + +void smte_lladdr_write(struct smte_softc *); + +void smte_tick(void *); +void smte_rxtick(void *); + +int smte_intr(void *); +void smte_tx_proc(struct smte_softc *); +void smte_rx_proc(struct smte_softc *); + +void smte_up(struct smte_softc *); +void smte_down(struct smte_softc *); +void smte_iff(struct smte_softc *); +int smte_encap(struct smte_softc *, struct mbuf *, int *, int *); + +void smte_stop_dma(struct smte_softc *); + +struct smte_dmamem * + smte_dmamem_alloc(struct smte_softc *, bus_size_t, bus_size_t); +void smte_dmamem_free(struct smte_softc *, struct smte_dmamem *); +struct mbuf *smte_alloc_mbuf(struct smte_softc *, bus_dmamap_t); +void smte_fill_rx_ring(struct smte_softc *); + +int +smte_match(struct device *parent, void *cfdata, void *aux) +{ + struct fdt_attach_args *faa = aux; + + return OF_is_compatible(faa->fa_node, "spacemit,k1-emac"); +} + +void +smte_attach(struct device *parent, struct device *self, void *aux) +{ + struct smte_softc *sc = (void *)self; + struct fdt_attach_args *faa = aux; + char phy_mode[16] = { 0 }; + struct ifnet *ifp; + uint32_t apmu[2]; + uint32_t phy; + int mii_flags = 0; + int node; + + if (faa->fa_nreg < 1) { + printf(": no registers\n"); + return; + } + + sc->sc_iot = faa->fa_iot; + if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, + faa->fa_reg[0].size, 0, &sc->sc_ioh)) { + printf(": can't map registers\n"); + return; + } + sc->sc_dmat = faa->fa_dmat; + sc->sc_node = faa->fa_node; + + if (OF_getpropintarray(sc->sc_node, "spacemit,apmu", + apmu, sizeof(apmu)) != sizeof(apmu)) { + printf(": no apmu register\n"); + goto unmap; + } + + sc->sc_apmu = regmap_byphandle(apmu[0]); + sc->sc_apmu_offset = apmu[1]; + if (sc->sc_apmu == NULL) { + printf(": can't get apmu registers\n"); + goto unmap; + } + + OF_getprop(sc->sc_node, "phy-mode", phy_mode, sizeof(phy_mode)); + if (strcmp(phy_mode, "rgmii") == 0) + mii_flags |= MIIF_SETDELAY; + else if (strcmp(phy_mode, "rgmii-rxid") == 0) + mii_flags |= MIIF_SETDELAY | MIIF_RXID; + else if (strcmp(phy_mode, "rgmii-txid") == 0) + mii_flags |= MIIF_SETDELAY | MIIF_TXID; + else if (strcmp(phy_mode, "rgmii-id") == 0) + mii_flags |= MIIF_SETDELAY | MIIF_RXID | MIIF_TXID; + + sc->sc_rx_delay = + OF_getpropint(sc->sc_node, "rx-internal-delay-ps", 0); + sc->sc_tx_delay = + OF_getpropint(sc->sc_node, "tx-internal-delay-ps", 0); + + /* Lookup PHY. */ + phy = OF_getpropint(sc->sc_node, "phy-handle", 0); + node = OF_getnodebyphandle(phy); + if (node) + sc->sc_phyloc = OF_getpropint(node, "reg", MII_PHY_ANY); + else + sc->sc_phyloc = MII_PHY_ANY; + sc->sc_mii.mii_node = node; + + OF_getprop(faa->fa_node, "local-mac-address", + &sc->sc_lladdr, ETHER_ADDR_LEN); + printf(": address %s\n", ether_sprintf(sc->sc_lladdr)); + + smte_init(sc); + + sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_NET | IPL_MPSAFE, + smte_intr, sc, sc->sc_dev.dv_xname); + if (sc->sc_ih == NULL) { + printf("%s: can't establish interrupt\n", sc->sc_dev.dv_xname); + goto unmap; + } + + timeout_set(&sc->sc_tick, smte_tick, sc); + + ifp = &sc->sc_ac.ac_if; + ifp->if_softc = sc; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_xflags = IFXF_MPSAFE; + ifp->if_ioctl = smte_ioctl; + ifp->if_qstart = smte_start; + ifq_init_maxlen(&ifp->if_snd, SMTE_NTXDESC - 1); + memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ); + + ifp->if_capabilities = IFCAP_VLAN_MTU; + + sc->sc_mii.mii_ifp = ifp; + sc->sc_mii.mii_readreg = smte_mii_readreg; + sc->sc_mii.mii_writereg = smte_mii_writereg; + sc->sc_mii.mii_statchg = smte_mii_statchg; + + ifmedia_init(&sc->sc_media, 0, smte_media_change, smte_media_status); + + mii_attach(self, &sc->sc_mii, 0xffffffff, sc->sc_phyloc, + MII_OFFSET_ANY, MIIF_NOISOLATE | mii_flags); + if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) { + printf("%s: no PHY found!\n", sc->sc_dev.dv_xname); + ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL); + ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL); + } else + ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_AUTO); + + if_attach(ifp); + ether_ifattach(ifp); + return; + +unmap: + bus_space_unmap(sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size); +} + +void +smte_mdio_bus_init(struct smte_softc *sc) +{ + uint32_t *reset_gpio; + int reset_gpiolen; + int node; + + node = OF_getnodebyname(sc->sc_node, "mdio-bus"); + if (!node) + return; + + reset_gpiolen = OF_getproplen(node, "reset-gpios"); + if (reset_gpiolen <= 0) + return; + + reset_gpio = malloc(reset_gpiolen, M_TEMP, M_WAITOK); + OF_getpropintarray(node, "reset-gpios", reset_gpio, reset_gpiolen); + gpio_controller_config_pin(reset_gpio, GPIO_CONFIG_OUTPUT); + gpio_controller_set_pin(reset_gpio, 0); + free(reset_gpio, M_TEMP, reset_gpiolen); +} + +void +smte_init(struct smte_softc *sc) +{ + uint32_t rx_delay, tx_delay; + uint32_t val; + + pinctrl_byname(sc->sc_node, "default"); + + /* Enable clock. */ + clock_enable(sc->sc_node, NULL); + reset_deassert(sc->sc_node, NULL); + + smte_mdio_bus_init(sc); + + smte_stop_dma(sc); + + val = regmap_read_4(sc->sc_apmu, + sc->sc_apmu_offset + APMU_EMAC_CLK_RST_CTRL); + val |= APMU_EMAC_AXI_MST_ID; + regmap_write_4(sc->sc_apmu, + sc->sc_apmu_offset + APMU_EMAC_CLK_RST_CTRL, val); + + /* Convert delays from ps to 15.6ps steps. */ + rx_delay = (sc->sc_rx_delay * 10 + 78) / 156; + tx_delay = (sc->sc_tx_delay * 10 + 78) / 156; + + /* Program internal delays. */ + val = regmap_read_4(sc->sc_apmu, + sc->sc_apmu_offset + APMU_EMAC_RGMII_DLINE); + val = APMU_EMAC_RGMII_DLINE_RX_EN | APMU_EMAC_RGMII_DLINE_TX_EN; + val &= ~APMU_EMAC_RGMII_DLINE_RX_STEP_MASK; + val &= ~APMU_EMAC_RGMII_DLINE_RX_DELAY_MASK; + val |= APMU_EMAC_RGMII_DLINE_RX_STEP_15P6; + val |= rx_delay << APMU_EMAC_RGMII_DLINE_RX_DELAY_SHIFT; + val &= ~APMU_EMAC_RGMII_DLINE_TX_STEP_MASK; + val &= ~APMU_EMAC_RGMII_DLINE_TX_DELAY_MASK; + val |= APMU_EMAC_RGMII_DLINE_TX_STEP_15P6; + val |= tx_delay << APMU_EMAC_RGMII_DLINE_TX_DELAY_SHIFT; + regmap_write_4(sc->sc_apmu, + sc->sc_apmu_offset + APMU_EMAC_RGMII_DLINE, val); + + /* Set up normal address filtering. */ + smte_lladdr_write(sc); + HWRITE4(sc, MAC_ADDR_CTRL, MAC_ADDR_CTRL_MAC_ADDR1_ENABLE); + HWRITE4(sc, MAC_MULTICAST_HASH_TABLE1, 0); + HWRITE4(sc, MAC_MULTICAST_HASH_TABLE2, 0); + HWRITE4(sc, MAC_MULTICAST_HASH_TABLE3, 0); + HWRITE4(sc, MAC_MULTICAST_HASH_TABLE4, 0); + + HWRITE4(sc, MAC_TRANSMIT_FIFO_ALMOST_FULL, 0x1f8); + HWRITE4(sc, MAC_TRANSMIT_PACKET_START_THRESHOLD, 1518); + HWRITE4(sc, MAC_RECEIVE_PACKET_START_THRESHOLD, 12); + + HWRITE4(sc, MAC_MAXIMUM_FRAME_SIZE, ETHER_MAX_LEN); + HWRITE4(sc, MAC_TRANSMIT_JABBER_SIZE, ETHER_MAX_DIX_LEN); + HWRITE4(sc, MAC_RECEIVE_JABBER_SIZE, ETHER_MAX_DIX_LEN); + + /* Enable receive interrupt coalescion. */ + HWRITE4(sc, DMA_RECEIVE_IRQ_MITIGATION, + (64 << DMA_RECEIVE_IRQ_MITIGATION_FRAME_COUNTER_SHIFT) | + ((600 * 312) << DMA_RECEIVE_IRQ_MITIGATION_TIMEOUT_COUNTER_SHIFT) | + DMA_RECEIVE_IRQ_MITIGATION_MITIGATION_ENABLE); + + /* Reset DMA controller. */ + HWRITE4(sc, DMA_CONFIG, DMA_CONFIG_SOFTWARE_RESET); + delay(10000); + HWRITE4(sc, DMA_CONFIG, 0); + delay(10000); + + HWRITE4(sc, DMA_CONFIG, DMA_CONFIG_STRICT_BURST | + DMA_CONFIG_DMA_64BIT_MODE | DMA_CONFIG_BURST_LENGTH_16); +} + +void +smte_lladdr_write(struct smte_softc *sc) +{ + HWRITE4(sc, MAC_ADDR1_HI, + sc->sc_lladdr[1] << 8 | sc->sc_lladdr[0] << 0); + HWRITE4(sc, MAC_ADDR1_ME, + sc->sc_lladdr[3] << 8 | sc->sc_lladdr[2] << 0); + HWRITE4(sc, MAC_ADDR1_LO, + sc->sc_lladdr[5] << 8 | sc->sc_lladdr[4] << 0); +} + +void +smte_start(struct ifqueue *ifq) +{ + struct ifnet *ifp = ifq->ifq_if; + struct smte_softc *sc = ifp->if_softc; + struct mbuf *m; + int error, idx, left, used; + + if (!sc->sc_link) { + ifq_purge(ifq); + return; + } + + idx = sc->sc_tx_prod; + left = sc->sc_tx_cons; + if (left <= idx) + left += SMTE_NTXDESC; + left -= idx; + used = 0; + + for (;;) { + if (used + SMTE_NTXSEGS + 1 > left) { + ifq_set_oactive(ifq); + break; + } + + m = ifq_dequeue(ifq); + if (m == NULL) + break; + + error = smte_encap(sc, m, &idx, &used); + if (error == EFBIG) { + m_freem(m); /* give up: drop it */ + ifp->if_oerrors++; + continue; + } + +#if NBPFILTER > 0 + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); +#endif + } + + if (used > 0) { + sc->sc_tx_prod = idx; + + /* Set a timeout in case the chip goes out to lunch. */ + ifp->if_timer = 5; + + HWRITE4(sc, DMA_TRANSMIT_POLL_DEMAND, 1); + } +} + +int +smte_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr) +{ + struct smte_softc *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *)addr; + int error = 0, s; + + s = splnet(); + + switch (cmd) { + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; + /* FALLTHROUGH */ + case SIOCSIFFLAGS: + if (ifp->if_flags & IFF_UP) { + if (ifp->if_flags & IFF_RUNNING) + error = ENETRESET; + else + smte_up(sc); + } else { + if (ifp->if_flags & IFF_RUNNING) + smte_down(sc); + } + break; + + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); + break; + + case SIOCGIFRXR: + error = if_rxr_ioctl((struct if_rxrinfo *)ifr->ifr_data, + NULL, MCLBYTES, &sc->sc_rx_ring); + break; + + default: + error = ether_ioctl(ifp, &sc->sc_ac, cmd, addr); + break; + } + + if (error == ENETRESET) { + if (ifp->if_flags & IFF_RUNNING) + smte_iff(sc); + error = 0; + } + + splx(s); + return error; +} + +int +smte_media_change(struct ifnet *ifp) +{ + struct smte_softc *sc = ifp->if_softc; + + if (LIST_FIRST(&sc->sc_mii.mii_phys)) + mii_mediachg(&sc->sc_mii); + + return 0; +} + +void +smte_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) +{ + struct smte_softc *sc = ifp->if_softc; + + if (LIST_FIRST(&sc->sc_mii.mii_phys)) { + mii_pollstat(&sc->sc_mii); + ifmr->ifm_active = sc->sc_mii.mii_media_active; + ifmr->ifm_status = sc->sc_mii.mii_media_status; + } +} + +int +smte_mii_readreg(struct device *self, int phy, int reg) +{ + struct smte_softc *sc = (void *)self; + uint32_t ctrl; + int timo; + + HWRITE4(sc, MAC_MDIO_DATA, 0); + HWRITE4(sc, MAC_MDIO_CTRL, MAC_MDIO_CTRL_START_MDIO_TRANS | + MAC_MDIO_CTRL_MDIO_READ_WRITE | + reg << MAC_MDIO_CTRL_REGISTER_ADDRESS_SHIFT | + phy << MAC_MDIO_CTRL_PHY_ADDRESS_SHIFT); + + for (timo = 100; timo > 0; timo--) { + ctrl = HREAD4(sc, MAC_MDIO_CTRL); + if ((ctrl & MAC_MDIO_CTRL_START_MDIO_TRANS) == 0) + return HREAD4(sc, MAC_MDIO_DATA); + delay(100); + } + + printf("%s: MII read timeout\n", sc->sc_dev.dv_xname); + return 0; +} + +void +smte_mii_writereg(struct device *self, int phy, int reg, int val) +{ + struct smte_softc *sc = (void *)self; + uint32_t ctrl; + int timo; + + HWRITE4(sc, MAC_MDIO_DATA, val); + HWRITE4(sc, MAC_MDIO_CTRL, MAC_MDIO_CTRL_START_MDIO_TRANS | + reg << MAC_MDIO_CTRL_REGISTER_ADDRESS_SHIFT | + phy << MAC_MDIO_CTRL_PHY_ADDRESS_SHIFT); + + for (timo = 100; timo > 0; timo--) { + ctrl = HREAD4(sc, MAC_MDIO_CTRL); + if ((ctrl & MAC_MDIO_CTRL_START_MDIO_TRANS) == 0) + return; + delay(100); + } + + printf("%s: MII write timeout\n", sc->sc_dev.dv_xname); +} + +void +smte_mii_statchg(struct device *self) +{ + struct smte_softc *sc = (void *)self; + uint32_t ctrl; + + ctrl = HREAD4(sc, MAC_GLOBAL_CTRL); + ctrl &= ~MAC_GLOBAL_CTRL_SPEED_MASK; + + switch (IFM_SUBTYPE(sc->sc_mii.mii_media_active)) { + case IFM_1000_SX: + case IFM_1000_LX: + case IFM_1000_CX: + case IFM_1000_T: + ctrl |= MAC_GLOBAL_CTRL_SPEED_1000; + sc->sc_link = 1; + break; + case IFM_100_TX: + ctrl |= MAC_GLOBAL_CTRL_SPEED_100; + sc->sc_link = 1; + break; + case IFM_10_T: + ctrl |= MAC_GLOBAL_CTRL_SPEED_10; + sc->sc_link = 1; + break; + default: + sc->sc_link = 0; + return; + } + + if (sc->sc_link == 0) + return; + + if ((sc->sc_mii.mii_media_active & IFM_GMASK) == IFM_FDX) + ctrl |= MAC_GLOBAL_CTRL_DUPLEX_MODE; + else + ctrl &= ~MAC_GLOBAL_CTRL_DUPLEX_MODE; + + HWRITE4(sc, MAC_GLOBAL_CTRL, ctrl); +} + +void +smte_tick(void *arg) +{ + struct smte_softc *sc = arg; + int s; + + s = splnet(); + mii_tick(&sc->sc_mii); + splx(s); + + timeout_add_sec(&sc->sc_tick, 1); +} + +int +smte_intr(void *arg) +{ + struct smte_softc *sc = arg; + uint32_t stat; + + stat = HREAD4(sc, DMA_STATUS_IRQ); + + if (stat & DMA_STATUS_IRQ_RX_TRANSFER_DONE || + stat & DMA_STATUS_IRQ_RX_MISSED_FRAME) + smte_rx_proc(sc); + + if (stat & DMA_STATUS_IRQ_TX_TRANSFER_DONE) + smte_tx_proc(sc); + + HWRITE4(sc, DMA_STATUS_IRQ, stat); + return 1; +} + +void +smte_tx_proc(struct smte_softc *sc) +{ + struct ifnet *ifp = &sc->sc_ac.ac_if; + struct smte_desc *txd; + struct smte_buf *txb; + int idx, txfree; + + bus_dmamap_sync(sc->sc_dmat, SMTE_DMA_MAP(sc->sc_txring), 0, + SMTE_DMA_LEN(sc->sc_txring), + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + + txfree = 0; + while (sc->sc_tx_cons != sc->sc_tx_prod) { + idx = sc->sc_tx_cons; + KASSERT(idx < SMTE_NTXDESC); + + txd = &sc->sc_txdesc[idx]; + if (txd->sd_desc0 & TX_DESC0_OWN) + break; + + txb = &sc->sc_txbuf[idx]; + if (txb->sb_m != NULL) { + bus_dmamap_sync(sc->sc_dmat, txb->sb_map, 0, + txb->sb_map->dm_mapsize, BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_dmat, txb->sb_map); + + m_freem(txb->sb_m); + txb->sb_m = NULL; + } + + txfree++; + + if (sc->sc_tx_cons == (SMTE_NTXDESC - 1)) + sc->sc_tx_cons = 0; + else + sc->sc_tx_cons++; + } + + if (sc->sc_tx_cons == sc->sc_tx_prod) + ifp->if_timer = 0; + + if (txfree) { + if (ifq_is_oactive(&ifp->if_snd)) + ifq_restart(&ifp->if_snd); + } +} + +void +smte_rx_proc(struct smte_softc *sc) +{ + struct ifnet *ifp = &sc->sc_ac.ac_if; + struct smte_desc *rxd; + struct smte_buf *rxb; + struct mbuf_list ml = MBUF_LIST_INITIALIZER(); + struct mbuf *m; + int idx, len, cnt, put; + + if ((ifp->if_flags & IFF_RUNNING) == 0) + return; + + bus_dmamap_sync(sc->sc_dmat, SMTE_DMA_MAP(sc->sc_rxring), 0, + SMTE_DMA_LEN(sc->sc_rxring), + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + + cnt = if_rxr_inuse(&sc->sc_rx_ring); + put = 0; + while (put < cnt) { + idx = sc->sc_rx_cons; + KASSERT(idx < SMTE_NRXDESC); + + rxd = &sc->sc_rxdesc[idx]; + if (rxd->sd_desc0 & RX_DESC0_OWN) + break; + + len = rxd->sd_desc0 & RX_DESC0_FRAME_PACKET_LENGTH_MASK; + rxb = &sc->sc_rxbuf[idx]; + KASSERT(rxb->sb_m != NULL); + + bus_dmamap_sync(sc->sc_dmat, rxb->sb_map, 0, + len, BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->sc_dmat, rxb->sb_map); + + m = rxb->sb_m; + rxb->sb_m = NULL; + + if (len < ETHER_CRC_LEN || len > m->m_len || + rxd->sd_desc0 & RX_DESC0_FRAME_RUNT || + rxd->sd_desc0 & RX_DESC0_FRAME_CRC_ERR || + rxd->sd_desc0 & RX_DESC0_FRAME_MAX_LEN_ERR || + rxd->sd_desc0 & RX_DESC0_FRAME_JABBER_ERR || + rxd->sd_desc0 & RX_DESC0_FRAME_LENGTH_ERR) { + ifp->if_ierrors++; + m_freem(m); + } else { + /* Strip off CRC. */ + len -= ETHER_CRC_LEN; + + m->m_pkthdr.len = m->m_len = len; + ml_enqueue(&ml, m); + } + + put++; + if (sc->sc_rx_cons == (SMTE_NRXDESC - 1)) + sc->sc_rx_cons = 0; + else + sc->sc_rx_cons++; + } + + if_rxr_put(&sc->sc_rx_ring, put); + if (ifiq_input(&ifp->if_rcv, &ml)) + if_rxr_livelocked(&sc->sc_rx_ring); + + smte_fill_rx_ring(sc); + + bus_dmamap_sync(sc->sc_dmat, SMTE_DMA_MAP(sc->sc_rxring), 0, + SMTE_DMA_LEN(sc->sc_rxring), + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); +} + +void +smte_up(struct smte_softc *sc) +{ + struct ifnet *ifp = &sc->sc_ac.ac_if; + struct smte_buf *txb, *rxb; + int i; + + /* Allocate Tx descriptor ring. */ + sc->sc_txring = smte_dmamem_alloc(sc, + SMTE_NTXDESC * sizeof(struct smte_desc), 8); + sc->sc_txdesc = SMTE_DMA_KVA(sc->sc_txring); + + sc->sc_txbuf = malloc(sizeof(struct smte_buf) * SMTE_NTXDESC, + M_DEVBUF, M_WAITOK); + for (i = 0; i < SMTE_NTXDESC; i++) { + txb = &sc->sc_txbuf[i]; + bus_dmamap_create(sc->sc_dmat, MCLBYTES, SMTE_NTXSEGS, + MCLBYTES, 0, BUS_DMA_WAITOK, &txb->sb_map); + txb->sb_m = NULL; + } + + bus_dmamap_sync(sc->sc_dmat, SMTE_DMA_MAP(sc->sc_txring), + 0, SMTE_DMA_LEN(sc->sc_txring), BUS_DMASYNC_PREWRITE); + + sc->sc_tx_prod = sc->sc_tx_cons = 0; + + HWRITE4(sc, DMA_TRANSMIT_BASE_ADDRESS, SMTE_DMA_DVA(sc->sc_txring)); + + /* Allocate Rx descriptor ring. */ + sc->sc_rxring = smte_dmamem_alloc(sc, + SMTE_NRXDESC * sizeof(struct smte_desc), 8); + sc->sc_rxdesc = SMTE_DMA_KVA(sc->sc_rxring); + + sc->sc_rxbuf = malloc(sizeof(struct smte_buf) * SMTE_NRXDESC, + M_DEVBUF, M_WAITOK); + + for (i = 0; i < SMTE_NRXDESC; i++) { + rxb = &sc->sc_rxbuf[i]; + bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, + MCLBYTES, 0, BUS_DMA_WAITOK, &rxb->sb_map); + rxb->sb_m = NULL; + } + + if_rxr_init(&sc->sc_rx_ring, 2, SMTE_NRXDESC); + + sc->sc_rx_prod = sc->sc_rx_cons = 0; + smte_fill_rx_ring(sc); + + bus_dmamap_sync(sc->sc_dmat, SMTE_DMA_MAP(sc->sc_rxring), + 0, SMTE_DMA_LEN(sc->sc_rxring), + BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); + + HWRITE4(sc, DMA_RECEIVE_BASE_ADDRESS, SMTE_DMA_DVA(sc->sc_rxring)); + + /* Configure media. */ + if (LIST_FIRST(&sc->sc_mii.mii_phys)) + mii_mediachg(&sc->sc_mii); + + /* Program promiscuous mode and multicast filters. */ + smte_iff(sc); + + /* + * Enable completion interrupts. Also enable the receive + * missed frame interrupt to triggera receive ring refills. + */ + HSET4(sc, DMA_INTR_ENABLE, DMA_INTR_ENABLE_TX_TRANSFER_DONE | + DMA_INTR_ENABLE_RX_TRANSFER_DONE); + HSET4(sc, DMA_INTR_ENABLE, DMA_INTR_ENABLE_RX_MISSED_FRAME); + + HCLR4(sc, MAC_TRANSMIT_CTRL, MAC_TRANSMIT_CTRL_IFG_LEN_MASK); + HSET4(sc, MAC_TRANSMIT_CTRL, + MAC_TRANSMIT_CTRL_TX_ENABLE | MAC_TRANSMIT_CTRL_TX_AUTO_RETRY); + + HSET4(sc, MAC_RECEIVE_CTRL, + MAC_RECEIVE_CTRL_RX_ENABLE | MAC_RECEIVE_CTRL_STORE_FORWARD); + + HWRITE4(sc, DMA_TRANSMIT_AUTO_POLL_COUNTER, 0); + HSET4(sc, DMA_CTRL, DMA_CTRL_START_STOP_TX_DMA); + HSET4(sc, DMA_CTRL, DMA_CTRL_START_STOP_RX_DMA); + + ifp->if_flags |= IFF_RUNNING; + ifq_clr_oactive(&ifp->if_snd); + + timeout_add_sec(&sc->sc_tick, 1); +} + +void +smte_down(struct smte_softc *sc) +{ + struct ifnet *ifp = &sc->sc_ac.ac_if; + struct smte_buf *txb, *rxb; + int i; + + timeout_del(&sc->sc_tick); + + ifp->if_flags &= ~IFF_RUNNING; + ifq_clr_oactive(&ifp->if_snd); + ifp->if_timer = 0; + + smte_stop_dma(sc); + + intr_barrier(sc->sc_ih); + ifq_barrier(&ifp->if_snd); + + for (i = 0; i < SMTE_NTXDESC; i++) { + txb = &sc->sc_txbuf[i]; + if (txb->sb_m != NULL) { + bus_dmamap_sync(sc->sc_dmat, txb->sb_map, 0, + txb->sb_map->dm_mapsize, BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_dmat, txb->sb_map); + m_freem(txb->sb_m); + } + bus_dmamap_destroy(sc->sc_dmat, txb->sb_map); + } + + smte_dmamem_free(sc, sc->sc_txring); + free(sc->sc_txbuf, M_DEVBUF, 0); + + for (i = 0; i < SMTE_NRXDESC; i++) { + rxb = &sc->sc_rxbuf[i]; + if (rxb->sb_m != NULL) { + bus_dmamap_sync(sc->sc_dmat, rxb->sb_map, 0, + rxb->sb_map->dm_mapsize, BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->sc_dmat, rxb->sb_map); + m_freem(rxb->sb_m); + } + bus_dmamap_destroy(sc->sc_dmat, rxb->sb_map); + } + + smte_dmamem_free(sc, sc->sc_rxring); + free(sc->sc_rxbuf, M_DEVBUF, 0); +} + +void +smte_iff(struct smte_softc *sc) +{ + struct arpcom *ac = &sc->sc_ac; + struct ifnet *ifp = &sc->sc_ac.ac_if; + struct ether_multi *enm; + struct ether_multistep step; + uint32_t crc, hashbit, hashreg; + uint16_t hash[4]; + uint32_t val; + + smte_lladdr_write(sc); + + val = MAC_ADDR_CTRL_MAC_ADDR1_ENABLE; + + ifp->if_flags &= ~IFF_ALLMULTI; + memset(hash, 0, sizeof(hash)); + if (ifp->if_flags & IFF_PROMISC) { + ifp->if_flags |= IFF_ALLMULTI; + val |= MAC_ADDR_CTRL_PROMISCUOUS_MODE; + } else if (ac->ac_multirangecnt > 0) { + ifp->if_flags |= IFF_ALLMULTI; + memset(hash, 0xff, sizeof(hash)); + } else { + ETHER_FIRST_MULTI(step, ac, enm); + while (enm != NULL) { + crc = ether_crc32_be(enm->enm_addrlo, + ETHER_ADDR_LEN) >> 26; + + hashreg = (crc >> 4); + hashbit = (crc & 0xf); + hash[hashreg] |= (1 << hashbit); + + ETHER_NEXT_MULTI(step, enm); + } + } + + HWRITE4(sc, MAC_MULTICAST_HASH_TABLE1, hash[0]); + HWRITE4(sc, MAC_MULTICAST_HASH_TABLE2, hash[1]); + HWRITE4(sc, MAC_MULTICAST_HASH_TABLE3, hash[2]); + HWRITE4(sc, MAC_MULTICAST_HASH_TABLE4, hash[3]); + HWRITE4(sc, MAC_ADDR_CTRL, val); +} + +int +smte_encap(struct smte_softc *sc, struct mbuf *m, int *idx, int *used) +{ + struct smte_desc *txd, *txd_start; + bus_dmamap_t map; + int cur, frag, i; + + cur = frag = *idx; + map = sc->sc_txbuf[cur].sb_map; + + if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT)) { + if (m_defrag(m, M_DONTWAIT)) + return EFBIG; + if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT)) + return EFBIG; + } + + /* Sync the DMA map. */ + bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, + BUS_DMASYNC_PREWRITE); + + txd = txd_start = &sc->sc_txdesc[frag]; + for (i = 0; i < map->dm_nsegs; i++) { + txd->sd_addr1 = map->dm_segs[i].ds_addr; + txd->sd_desc1 = map->dm_segs[i].ds_len; + if (frag == (SMTE_NRXDESC - 1)) + txd->sd_desc1 |= TX_DESC1_END_RING; + if (i == 0) + txd->sd_desc1 |= TX_DESC1_FIRST_SEGMENT; + if (i == (map->dm_nsegs - 1)) + txd->sd_desc1 |= TX_DESC1_LAST_SEGMENT | + TX_DESC1_INTERRUPT_ON_COMPLETION; + if (i != 0) + txd->sd_desc0 = TX_DESC0_OWN; + + bus_dmamap_sync(sc->sc_dmat, SMTE_DMA_MAP(sc->sc_txring), + frag * sizeof(*txd), sizeof(*txd), BUS_DMASYNC_PREWRITE); + + cur = frag; + if (frag == (SMTE_NTXDESC - 1)) { + txd = &sc->sc_txdesc[0]; + frag = 0; + } else { + txd++; + frag++; + } + KASSERT(frag != sc->sc_tx_cons); + } + + txd_start->sd_desc0 = TX_DESC0_OWN; + + bus_dmamap_sync(sc->sc_dmat, SMTE_DMA_MAP(sc->sc_txring), + *idx * sizeof(*txd), sizeof(*txd), BUS_DMASYNC_PREWRITE); + + KASSERT(sc->sc_txbuf[cur].sb_m == NULL); + sc->sc_txbuf[*idx].sb_map = sc->sc_txbuf[cur].sb_map; + sc->sc_txbuf[cur].sb_map = map; + sc->sc_txbuf[cur].sb_m = m; + + *idx = frag; + *used += map->dm_nsegs; + + return 0; +} + +void +smte_stop_dma(struct smte_softc *sc) +{ + HWRITE4(sc, MAC_INTR_ENABLE, 0); + HWRITE4(sc, DMA_INTR_ENABLE, 0); + + HWRITE4(sc, MAC_TRANSMIT_CTRL, 0); + HWRITE4(sc, MAC_RECEIVE_CTRL, 0); + HWRITE4(sc, DMA_CTRL, 0); +} + +struct smte_dmamem * +smte_dmamem_alloc(struct smte_softc *sc, bus_size_t size, bus_size_t align) +{ + struct smte_dmamem *sdm; + int nsegs; + + sdm = malloc(sizeof(*sdm), M_DEVBUF, M_WAITOK | M_ZERO); + sdm->sdm_size = size; + + if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, + BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &sdm->sdm_map) != 0) + goto sdmfree; + + if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0, &sdm->sdm_seg, 1, + &nsegs, BUS_DMA_WAITOK) != 0) + goto destroy; + + if (bus_dmamem_map(sc->sc_dmat, &sdm->sdm_seg, nsegs, size, + &sdm->sdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0) + goto free; + + if (bus_dmamap_load(sc->sc_dmat, sdm->sdm_map, sdm->sdm_kva, size, + NULL, BUS_DMA_WAITOK) != 0) + goto unmap; + + memset(sdm->sdm_kva, 0, size); + + return sdm; + +unmap: + bus_dmamem_unmap(sc->sc_dmat, sdm->sdm_kva, size); +free: + bus_dmamem_free(sc->sc_dmat, &sdm->sdm_seg, 1); +destroy: + bus_dmamap_destroy(sc->sc_dmat, sdm->sdm_map); +sdmfree: + free(sdm, M_DEVBUF, 0); + + return NULL; +} + +void +smte_dmamem_free(struct smte_softc *sc, struct smte_dmamem *sdm) +{ + bus_dmamem_unmap(sc->sc_dmat, sdm->sdm_kva, sdm->sdm_size); + bus_dmamem_free(sc->sc_dmat, &sdm->sdm_seg, 1); + bus_dmamap_destroy(sc->sc_dmat, sdm->sdm_map); + free(sdm, M_DEVBUF, 0); +} + +struct mbuf * +smte_alloc_mbuf(struct smte_softc *sc, bus_dmamap_t map) +{ + struct mbuf *m = NULL; + + m = MCLGETL(NULL, M_DONTWAIT, MCLBYTES); + if (m == NULL) + return NULL; + m->m_len = m->m_pkthdr.len = MCLBYTES; + m_adj(m, ETHER_ALIGN); + + if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT) != 0) { + printf("%s: could not load mbuf DMA map", DEVNAME(sc)); + m_freem(m); + return NULL; + } + + bus_dmamap_sync(sc->sc_dmat, map, 0, + m->m_pkthdr.len, BUS_DMASYNC_PREREAD); + + return m; +} + +void +smte_fill_rx_ring(struct smte_softc *sc) +{ + struct smte_desc *rxd; + struct smte_buf *rxb; + u_int slots; + + for (slots = if_rxr_get(&sc->sc_rx_ring, SMTE_NRXDESC); + slots > 0; slots--) { + rxb = &sc->sc_rxbuf[sc->sc_rx_prod]; + rxb->sb_m = smte_alloc_mbuf(sc, rxb->sb_map); + if (rxb->sb_m == NULL) + break; + + rxd = &sc->sc_rxdesc[sc->sc_rx_prod]; + rxd->sd_desc1 = rxb->sb_map->dm_segs[0].ds_len; + rxd->sd_addr1 = rxb->sb_map->dm_segs[0].ds_addr; + if (sc->sc_rx_prod == (SMTE_NRXDESC - 1)) + rxd->sd_desc1 |= RX_DESC1_END_RING; + + bus_dmamap_sync(sc->sc_dmat, SMTE_DMA_MAP(sc->sc_rxring), + sc->sc_rx_prod * sizeof(*rxd), sizeof(*rxd), + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + rxd->sd_desc0 = RX_DESC0_OWN; + + bus_dmamap_sync(sc->sc_dmat, SMTE_DMA_MAP(sc->sc_rxring), + sc->sc_rx_prod * sizeof(*rxd), sizeof(*rxd), + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + if (sc->sc_rx_prod == (SMTE_NRXDESC - 1)) + sc->sc_rx_prod = 0; + else + sc->sc_rx_prod++; + } + if_rxr_put(&sc->sc_rx_ring, slots); +} diff --git sys/arch/loongarch64/dev/imsic.c sys/arch/loongarch64/dev/imsic.c new file mode 100644 index 00000000000..3fc24b83ba0 --- /dev/null +++ sys/arch/loongarch64/dev/imsic.c @@ -0,0 +1,375 @@ +/* $OpenBSD: imsic.c,v 1.1 2026/07/24 10:51:00 kettenis Exp $ */ +/* + * Copyright (c) 2026 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "riscv64/dev/riscv_cpu_intc.h" + +#define IMSIC_EIDELIVERY 0x70 +#define IMSIC_EIDELIVERY_ENABLE (1 << 0) +#define IMSIC_EITHRESHOLD 0x72 +#define IMSIC_EIP(x) (0x80 + (x)) +#define IMSIC_EIE(x) (0xc0 + (x)) + +#define HREAD4(sc, reg) \ + (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) +#define HWRITE4(sc, reg, val) \ + bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) + +struct imsic_intrhand; + +struct imsic_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + + bus_addr_t sc_msi_addr; + + uint32_t sc_nmsi; + uint32_t sc_guest_index_bits; + uint16_t sc_threshold[NIPL]; + + struct imsic_intrhand **sc_ih; + + struct interrupt_controller sc_msi_ic; +}; + +struct imsic_intrhand { + struct imsic_softc *ih_sc; + int (*ih_func)(void *); + void *ih_arg; + int ih_ipl; + int ih_flags; + int ih_msi; + struct evcount ih_count; + struct cpu_info *ih_ci; +}; + +struct imsic_softc *imsic_sc; + +int imsic_match(struct device *, void *, void *); +void imsic_attach(struct device *, struct device *, void *); + +const struct cfattach imsic_ca = { + sizeof (struct imsic_softc), imsic_match, imsic_attach +}; + +struct cfdriver imsic_cd = { + NULL, "imsic", DV_DULL +}; + +void imsic_csr_write(uint64_t, uint64_t); +uint64_t imsic_csr_read(uint64_t); + +int imsic_spllower(int); +int imsic_splraise(int); +void imsic_splx(int); +void imsic_setipl(int); +int imsic_intr(void *); + +void *imsic_intr_establish_msi(void *, uint64_t *, uint64_t *, + int, struct cpu_info *, int (*)(void *), void *, char *); +void imsic_intr_disestablish_msi(void *); +void imsic_barrier(void *); + +int +imsic_match(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *faa = aux; + + return OF_is_compatible(faa->fa_node, "riscv,imsics"); +} + +void +imsic_attach(struct device *parent, struct device *self, void *aux) +{ + struct imsic_softc *sc = (struct imsic_softc *)self; + struct fdt_attach_args *faa = aux; + uint64_t reg; + int shift; + + if (faa->fa_nreg < 1) { + printf(": no registers\n"); + return; + } + + sc->sc_iot = faa->fa_iot; + if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, + faa->fa_reg[0].size, 0, &sc->sc_ioh)) { + printf(": can't map registers\n"); + return; + } + printf("\n"); + + sc->sc_nmsi = OF_getpropint(faa->fa_node, "riscv,num-ids", 63) + 1; + sc->sc_guest_index_bits = + OF_getpropint(faa->fa_node, "riscv,guest-index-bits", 0); + + /* + * Each MSI has its own priority, with lower numbered MSIs + * having higher priority. The architecture guarantees that + * we have at least 63 available MSIs. Divide these up among + * IPL_AUDIO, IPL_TTY, IPL_NET and IPL_BIO. Clock interrupts + * and IPIs are handled elsewhere so we don't need to worry + * about IPL_CLOCK and IPL_IPI. If we have more MSIs, divide + * them up proportionally by shifting the thresholds. + */ + shift = ffs(sc->sc_nmsi / 64) - 1; + sc->sc_threshold[IPL_NONE] = 0; + sc->sc_threshold[IPL_SOFTCLOCK] = 0; + sc->sc_threshold[IPL_SOFTNET] = 0; + sc->sc_threshold[IPL_SOFTTTY] = 0; + sc->sc_threshold[IPL_IPI] = 1; + sc->sc_threshold[IPL_HIGH] = 1; + sc->sc_threshold[IPL_CLOCK] = 1; + sc->sc_threshold[IPL_AUDIO] = 1; + sc->sc_threshold[IPL_VM] = 8 << shift; + sc->sc_threshold[IPL_TTY] = 8 << shift; + sc->sc_threshold[IPL_NET] = 16 << shift; + sc->sc_threshold[IPL_BIO] = 56 << shift; + + sc->sc_msi_addr = faa->fa_reg[0].addr; + + sc->sc_ih = mallocarray(sizeof(*sc->sc_ih), sc->sc_nmsi, + M_DEVBUF, M_WAITOK | M_ZERO); + + KASSERT(imsic_sc == NULL); + imsic_sc = sc; + + riscv_intc_intr_establish(IRQ_EXTERNAL_SUPERVISOR, 0, + imsic_intr, sc, sc->sc_dev.dv_xname); + riscv_set_intr_func(imsic_splraise, imsic_spllower, + imsic_splx, imsic_setipl); + + /* Disable all interrupts. */ + for (reg = IMSIC_EIE(0); reg <= IMSIC_EIE((sc->sc_nmsi - 1) / 32); + reg += 2) + imsic_csr_write(reg, 0); + + /* Set threshold as high as possible. */ + imsic_csr_write(IMSIC_EITHRESHOLD, 1); + + /* Enable delivery. */ + imsic_csr_write(IMSIC_EIDELIVERY, IMSIC_EIDELIVERY_ENABLE); + + csr_set(sie, SIE_SEIE); + + sc->sc_msi_ic.ic_node = faa->fa_node; + sc->sc_msi_ic.ic_cookie = sc; + sc->sc_msi_ic.ic_establish_msi = imsic_intr_establish_msi; + sc->sc_msi_ic.ic_disestablish = imsic_intr_disestablish_msi; + sc->sc_msi_ic.ic_barrier = imsic_barrier; + fdt_intr_register(&sc->sc_msi_ic); +} + +void +imsic_csr_write(uint64_t reg, uint64_t val) +{ + csr_write(siselect, reg); + csr_write(sireg, val); +} + +uint64_t +imsic_csr_read(uint64_t reg) +{ + csr_write(siselect, reg); + return csr_read(sireg); +} + +void +imsic_splx(int new) +{ + struct cpu_info *ci = curcpu(); + + if (ci->ci_ipending & riscv_smask[new]) + riscv_do_pending_intr(new); + + imsic_setipl(new); +} + +int +imsic_spllower(int new) +{ + struct cpu_info *ci = curcpu(); + int old = ci->ci_cpl; + + imsic_splx(new); + return old; +} + +int +imsic_splraise(int new) +{ + struct cpu_info *ci = curcpu(); + int old = ci->ci_cpl; + + if (old > new) + new = old; + + imsic_setipl(new); + return old; +} + +void +imsic_setipl(int new) +{ + struct imsic_softc *sc = imsic_sc; + struct cpu_info *ci = curcpu(); + u_long sie; + + sie = intr_disable(); + ci->ci_cpl = new; + imsic_csr_write(IMSIC_EITHRESHOLD, sc->sc_threshold[new]); + + /* trigger deferred timer interrupt if cpl is now low enough */ + if (ci->ci_timer_deferred && new < IPL_CLOCK) + sbi_set_timer(0); + + intr_restore(sie); +} + +int +imsic_intr(void *arg) +{ + struct imsic_softc *sc = arg; + struct imsic_intrhand *ih; + uint64_t stopei; + u_int msi; + int need_lock; + int handled; + int s; + + stopei = csr_swap(stopei, 0); + msi = (stopei & STOPEI_ID_MASK) >> STOPEI_ID_SHIFT; + if (msi >= sc->sc_nmsi) + return 0; + + ih = sc->sc_ih[msi]; + if (ih == NULL) + return 0; + + s = imsic_splraise(ih->ih_ipl); + + if (ih->ih_flags & IPL_MPSAFE) + need_lock = 0; + else + need_lock = s < IPL_SCHED; + + if (need_lock) + KERNEL_LOCK(); + + intr_enable(); + handled = ih->ih_func(ih->ih_arg); + intr_disable(); + if (handled) + ih->ih_count.ec_count++; + + if (need_lock) + KERNEL_UNLOCK(); + + imsic_splx(s); + return handled; +} + +uint64_t +imsic_msi_addr(struct imsic_softc *sc, struct cpu_info *ci) +{ + uint64_t hart_offset; + + /* XXX This assumes hart ID and hart index are the same. */ + hart_offset = ci->ci_hartid << (PAGE_SHIFT + sc->sc_guest_index_bits); + return sc->sc_msi_addr | hart_offset; +} + +void * +imsic_intr_establish_msi(void *cookie, uint64_t *addr, uint64_t *data, + int level, struct cpu_info *ci, int (*func)(void *), void *arg, char *name) +{ + struct imsic_softc *sc = cookie; + struct imsic_intrhand *ih; + uint64_t eie, reg; + int msi; + + if (ci == NULL) + ci = &cpu_info_primary; + + msi = sc->sc_threshold[level & IPL_IRQMASK]; + for (; msi < sc->sc_nmsi; msi++) { + if (sc->sc_ih[msi] == NULL) + break; + } + if (msi == sc->sc_nmsi) + return NULL; + + ih = malloc(sizeof(struct imsic_intrhand), M_DEVBUF, M_WAITOK); + ih->ih_sc = sc; + ih->ih_func = func; + ih->ih_arg = arg; + ih->ih_ipl = level & IPL_IRQMASK; + ih->ih_flags = level & IPL_FLAGMASK; + ih->ih_msi = msi; + ih->ih_ci = ci; + sc->sc_ih[msi] = ih; + + if (name) + evcount_attach(&ih->ih_count, name, &ih->ih_msi); + + /* Enable interrupt. */ + reg = IMSIC_EIE((msi / 64) * 2); + eie = imsic_csr_read(reg); + imsic_csr_write(reg, eie | (1ULL << (msi % 64))); + + *addr = imsic_msi_addr(sc, ci); + *data = msi; + return ih; +} + +void +imsic_intr_disestablish_msi(void *cookie) +{ + struct imsic_intrhand *ih = cookie; + struct imsic_softc *sc = ih->ih_sc; + uint64_t eie, reg; + + /* Disable interrupt. */ + reg = IMSIC_EIE((ih->ih_msi / 64) * 2); + eie = imsic_csr_read(reg); + imsic_csr_write(reg, eie & ~(1ULL << (ih->ih_msi % 64))); + + sc->sc_ih[ih->ih_msi] = NULL; + free(ih, M_DEVBUF, sizeof(*ih)); +} + +void +imsic_barrier(void *cookie) +{ + struct imsic_intrhand *ih = cookie; + + sched_barrier(ih->ih_ci); +} diff --git sys/arch/loongarch64/dev/loongarch_cpu_intc.c sys/arch/loongarch64/dev/loongarch_cpu_intc.c new file mode 100644 index 00000000000..fea7b6b3a48 --- /dev/null +++ sys/arch/loongarch64/dev/loongarch_cpu_intc.c @@ -0,0 +1,166 @@ +/* $OpenBSD: loongarch_cpu_intc.c,v 1.12 2026/07/24 10:51:00 kettenis Exp $ */ + +/* + * Copyright (c) 2020, Mars Li + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include +#include + +#include + +#include "loongarch_cpu_intc.h" + +struct intrhand { + int (*ih_func)(void *); /* handler */ + void *ih_arg; /* arg for handler */ + int ih_irq; /* IRQ number */ + char *ih_name; +}; + +struct intrhand* intc_handler[INTC_NIRQS] = {NULL}; +struct interrupt_controller intc_ic; + +int loongarch_intc_match(struct device *, void *, void *); +void loongarch_intc_attach(struct device *, struct device *, void *); + +void loongarch_intc_irq_handler(void *); +void *loongarch_intc_intr_establish(int, int, int (*)(void *), + void *, char *); +void loongarch_intc_intr_disestablish(void *); + + +const struct cfattach intc_ca = { + sizeof (struct device), loongarch_intc_match, loongarch_intc_attach +}; + +struct cfdriver intc_cd = { + NULL, "intc", DV_DULL +}; + +int +loongarch_intc_match(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *faa = aux; + int node = faa->fa_node; + return (OF_getproplen(node, "interrupt-controller") >= 0 && + OF_is_compatible(node, "loongarch,cpu-intc")); +} + +void +loongarch_intc_attach(struct device *parent, struct device *self, void *aux) +{ + struct fdt_attach_args *faa = aux;/* should only use fa_node field */ + + loongarch_init_smask(); + + /* hook the intr_handler */ + loongarch_set_intr_handler(loongarch_intc_irq_handler); + + printf("\n"); + + intc_ic.ic_node = faa->fa_node; + intc_ic.ic_cookie = &intc_ic; + + /* + * only allow install/uninstall handler to/from global vector + * by calling loongarch_intc_intr_establish/disestablish + */ + intc_ic.ic_establish = NULL; + intc_ic.ic_disestablish = NULL; + + loongarch_intr_register_fdt(&intc_ic); + +#ifdef MULTIPROCESSOR + extern int ipi_intr(void *); + loongarch_intc_intr_establish(IRQ_SOFTWARE_SUPERVISOR, 0, + ipi_intr, NULL, NULL); +#endif + + /* + * XXX right time to enable interrupts ?? + * might need to postpone until autoconf is finished + */ + intr_enable(); +} + + +/* global interrupt handler */ +void +loongarch_intc_irq_handler(void *frame) +{ + int irq; + struct intrhand *ih; + struct trapframe *_frame = (struct trapframe*) frame; + + KASSERTMSG(_frame->tf_scause & EXCP_INT, + "loongarch_cpu_intr: wrong frame passed"); + + irq = (_frame->tf_scause & EXCP_MASK); +#ifdef DEBUG_INTC + printf("irq %d fired\n", irq); +#endif + + ih = intc_handler[irq]; + if (ih->ih_func(ih->ih_arg ? ih->ih_arg : frame) == 0) +#ifdef DEBUG_INTC + printf("fail in handling irq %d %s\n", irq, ih->ih_name); +#else + ; +#endif /* DEBUG_INTC */ +} + +void * +loongarch_intc_intr_establish(int irqno, int dummy_level, int (*func)(void *), + void *arg, char *name) +{ + struct intrhand *ih; + u_long sie; + + if (irqno < 0 || irqno >= INTC_NIRQS) + panic("intc_intr_establish: bogus irqnumber %d: %s", + irqno, name); + + ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK); + ih->ih_func = func; + ih->ih_arg = arg; + ih->ih_irq = irqno; + ih->ih_name = name; + + sie = intr_disable(); + intc_handler[irqno] = ih; + intr_restore(sie); + + return (ih); +} + +void +loongarch_intc_intr_disestablish(void *cookie) +{ + struct intrhand *ih = cookie; + int irqno = ih->ih_irq; + u_long sie; + + sie = intr_disable(); + intc_handler[irqno] = NULL; + intr_restore(sie); + + free(ih, M_DEVBUF, 0); +} diff --git sys/arch/loongarch64/dev/loongarch_cpu_intc.h sys/arch/loongarch64/dev/loongarch_cpu_intc.h new file mode 100644 index 00000000000..ed039924662 --- /dev/null +++ sys/arch/loongarch64/dev/loongarch_cpu_intc.h @@ -0,0 +1,27 @@ +/* $OpenBSD: loongarch_cpu_intc.h,v 1.4 2024/05/22 05:51:49 jsg Exp $ */ + +/* + * Copyright (c) 2020 Mars Li + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _LOONGARCH_CPU_INTC_H_ +#define _LOONGARCH_CPU_INTC_H_ + +void *loongarch_intc_intr_establish(int, int, int (*func)(void *), + void *, char *); +void loongarch_intc_intr_disestablish(void *cookie); + +#endif /* _LOONGARCH_CPU_INTC_H_ */ + diff --git sys/arch/loongarch64/dev/mainbus.c sys/arch/loongarch64/dev/mainbus.c new file mode 100644 index 00000000000..baaf3e18a5e --- /dev/null +++ sys/arch/loongarch64/dev/mainbus.c @@ -0,0 +1,367 @@ +/* $OpenBSD: mainbus.c,v 1.16 2026/06/22 21:12:12 kettenis Exp $ */ + +/* + * Copyright (c) 2016 Patrick Wildt + * Copyright (c) 2017 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include +#include +#include + +int mainbus_match(struct device *, void *, void *); +void mainbus_attach(struct device *, struct device *, void *); + +void mainbus_attach_node(struct device *, int, cfmatch_t); +int mainbus_match_status(struct device *, void *, void *); +void mainbus_attach_cpus(struct device *, cfmatch_t); +int mainbus_match_primary(struct device *, void *, void *); +int mainbus_match_secondary(struct device *, void *, void *); +void mainbus_attach_framebuffer(struct device *); + +struct mainbus_softc { + struct device sc_dev; + int sc_node; + bus_space_tag_t sc_iot; + bus_dma_tag_t sc_dmat; + int sc_acells; + int sc_scells; + int *sc_ranges; + int sc_rangeslen; + int sc_early; + int sc_early_nodes[64]; +}; + +const struct cfattach mainbus_ca = { + sizeof(struct mainbus_softc), mainbus_match, mainbus_attach +}; + +struct cfdriver mainbus_cd = { + NULL, "mainbus", DV_DULL +}; + +struct machine_bus_dma_tag mainbus_dma_tag = { + NULL, + BUS_DMA_COHERENT, + 0, (paddr_t)-1, + _dmamap_create, + _dmamap_destroy, + _dmamap_load, + _dmamap_load_mbuf, + _dmamap_load_uio, + _dmamap_load_raw, + _dmamap_load_buffer, + _dmamap_unload, + _dmamap_sync, + _dmamem_alloc, + _dmamem_alloc_range, + _dmamem_free, + _dmamem_map, + _dmamem_unmap, + _dmamem_mmap, +}; + +/* + * Mainbus takes care of FDT and non-FDT machines, so we + * always attach. + */ +int +mainbus_match(struct device *parent, void *cfdata, void *aux) +{ + return (1); +} + +void +mainbus_attach(struct device *parent, struct device *self, void *aux) +{ + struct mainbus_softc *sc = (struct mainbus_softc *)self; + char prop[128]; + int node, len; + + loongarch_intr_init_fdt(); + + sc->sc_node = OF_peer(0); + sc->sc_iot = &loongarch64_bs_tag; + sc->sc_dmat = &mainbus_dma_tag; + sc->sc_acells = OF_getpropint(OF_peer(0), "#address-cells", 1); + sc->sc_scells = OF_getpropint(OF_peer(0), "#size-cells", 1); + + if (OF_getpropbool(sc->sc_node, "dma-noncoherent")) + sc->sc_dmat->_flags &= ~BUS_DMA_COHERENT; + + len = OF_getprop(sc->sc_node, "model", prop, sizeof(prop)); + if (len > 0) { + printf(": %s\n", prop); + hw_prod = malloc(len, M_DEVBUF, M_NOWAIT); + if (hw_prod) + strlcpy(hw_prod, prop, len); + } else + printf(": unknown model\n"); + + len = OF_getprop(sc->sc_node, "serial-number", prop, sizeof(prop)); + if (len > 0) { + hw_serial = malloc(len, M_DEVBUF, M_NOWAIT); + if (hw_serial) + strlcpy(hw_serial, prop, len); + } + + /* Attach primary CPU first. */ + mainbus_attach_cpus(self, mainbus_match_primary); + + /* Attach secondary CPUs. */ + mainbus_attach_cpus(self, mainbus_match_secondary); + + sc->sc_rangeslen = OF_getproplen(OF_peer(0), "ranges"); + if (sc->sc_rangeslen > 0 && !(sc->sc_rangeslen % sizeof(uint32_t))) { + sc->sc_ranges = malloc(sc->sc_rangeslen, M_TEMP, M_WAITOK); + OF_getpropintarray(OF_peer(0), "ranges", sc->sc_ranges, + sc->sc_rangeslen); + } + + /* Scan the whole tree. */ + sc->sc_early = 1; + for (node = OF_child(sc->sc_node); node != 0; node = OF_peer(node)) + mainbus_attach_node(self, node, NULL); + + sc->sc_early = 0; + for (node = OF_child(sc->sc_node); node != 0; node = OF_peer(node)) + mainbus_attach_node(self, node, NULL); + + mainbus_attach_framebuffer(self); +} + +int +mainbus_print(void *aux, const char *pnp) +{ + struct fdt_attach_args *fa = aux; + char buf[32]; + + if (!pnp) + return (QUIET); + + if (OF_getprop(fa->fa_node, "status", buf, sizeof(buf)) > 0 && + strcmp(buf, "disabled") == 0) + return (QUIET); + + if (OF_getprop(fa->fa_node, "name", buf, sizeof(buf)) > 0) { + buf[sizeof(buf) - 1] = 0; + if (strcmp(buf, "aliases") == 0 || + strcmp(buf, "chosen") == 0 || + strcmp(buf, "cpus") == 0 || + strcmp(buf, "memory") == 0 || + strcmp(buf, "reserved-memory") == 0 || + strcmp(buf, "thermal-zones") == 0 || + strncmp(buf, "__", 2) == 0) + return (QUIET); + printf("\"%s\"", buf); + } else + printf("node %u", fa->fa_node); + + printf(" at %s", pnp); + + return (UNCONF); +} + +/* + * Look for a driver that wants to be attached to this node. + */ +void +mainbus_attach_node(struct device *self, int node, cfmatch_t submatch) +{ + struct mainbus_softc *sc = (struct mainbus_softc *)self; + struct fdt_attach_args fa; + int i, len, line; + uint32_t *cell, *reg; + struct device *child; + cfprint_t print = NULL; + + /* Skip if already attached early. */ + for (i = 0; i < nitems(sc->sc_early_nodes); i++) { + if (sc->sc_early_nodes[i] == node) + return; + if (sc->sc_early_nodes[i] == 0) + break; + } + + memset(&fa, 0, sizeof(fa)); + fa.fa_name = ""; + fa.fa_node = node; + fa.fa_iot = sc->sc_iot; + fa.fa_dmat = sc->sc_dmat; + fa.fa_acells = sc->sc_acells; + fa.fa_scells = sc->sc_scells; + + len = OF_getproplen(node, "reg"); + line = (sc->sc_acells + sc->sc_scells) * sizeof(uint32_t); + if (len > 0 && (len % line) == 0) { + reg = malloc(len, M_TEMP, M_WAITOK); + OF_getpropintarray(node, "reg", reg, len); + + fa.fa_reg = malloc((len / line) * sizeof(struct fdt_reg), + M_DEVBUF, M_WAITOK); + fa.fa_nreg = (len / line); + + for (i = 0, cell = reg; i < len / line; i++) { + if (sc->sc_acells >= 1) + fa.fa_reg[i].addr = cell[0]; + if (sc->sc_acells == 2) { + fa.fa_reg[i].addr <<= 32; + fa.fa_reg[i].addr |= cell[1]; + } + cell += sc->sc_acells; + if (sc->sc_scells >= 1) + fa.fa_reg[i].size = cell[0]; + if (sc->sc_scells == 2) { + fa.fa_reg[i].size <<= 32; + fa.fa_reg[i].size |= cell[1]; + } + cell += sc->sc_scells; + } + + free(reg, M_TEMP, len); + } + + len = OF_getproplen(node, "interrupts"); + if (len > 0 && (len % sizeof(uint32_t)) == 0) { + fa.fa_intr = malloc(len, M_DEVBUF, M_WAITOK); + fa.fa_nintr = len / sizeof(uint32_t); + + OF_getpropintarray(node, "interrupts", fa.fa_intr, len); + } + + if (OF_getpropbool(node, "dma-noncoherent")) { + fa.fa_dmat = malloc(sizeof(*sc->sc_dmat), + M_DEVBUF, M_WAITOK | M_ZERO); + memcpy(fa.fa_dmat, sc->sc_dmat, sizeof(*sc->sc_dmat)); + fa.fa_dmat->_flags &= ~BUS_DMA_COHERENT; + } else if (OF_getpropbool(node, "dma-coherent")) { + fa.fa_dmat = malloc(sizeof(*sc->sc_dmat), + M_DEVBUF, M_WAITOK | M_ZERO); + memcpy(fa.fa_dmat, sc->sc_dmat, sizeof(*sc->sc_dmat)); + fa.fa_dmat->_flags |= BUS_DMA_COHERENT; + } + + if (submatch == NULL && sc->sc_early == 0) + print = mainbus_print; + if (submatch == NULL) + submatch = mainbus_match_status; + + child = config_found_sm(self, &fa, print, submatch); + + /* Record nodes that we attach early. */ + if (child && sc->sc_early) { + for (i = 0; i < nitems(sc->sc_early_nodes); i++) { + if (sc->sc_early_nodes[i] != 0) + continue; + sc->sc_early_nodes[i] = node; + break; + } + } + + free(fa.fa_reg, M_DEVBUF, fa.fa_nreg * sizeof(struct fdt_reg)); + free(fa.fa_intr, M_DEVBUF, fa.fa_nintr * sizeof(uint32_t)); +} + +int +mainbus_match_status(struct device *parent, void *match, void *aux) +{ + struct mainbus_softc *sc = (struct mainbus_softc *)parent; + struct fdt_attach_args *fa = aux; + struct cfdata *cf = match; + char buf[32]; + + if (OF_getprop(fa->fa_node, "status", buf, sizeof(buf)) > 0 && + strcmp(buf, "disabled") == 0) + return 0; + + if (cf->cf_loc[0] == sc->sc_early) + return (*cf->cf_attach->ca_match)(parent, match, aux); + + return 0; +} + +void +mainbus_attach_cpus(struct device *self, cfmatch_t match) +{ + struct mainbus_softc *sc = (struct mainbus_softc *)self; + int node = OF_finddevice("/cpus"); + int acells, scells; + char buf[32]; + + if (node == -1) + return; + + acells = sc->sc_acells; + scells = sc->sc_scells; + sc->sc_acells = OF_getpropint(node, "#address-cells", 2); + sc->sc_scells = OF_getpropint(node, "#size-cells", 0); + + ncpusfound = 0; + for (node = OF_child(node); node != 0; node = OF_peer(node)) { + if (OF_getprop(node, "status", buf, sizeof(buf)) > 0 && + strcmp(buf, "disabled") == 0) + continue; + + if (OF_getprop(node, "device_type", buf, sizeof(buf)) > 0 && + strcmp(buf, "cpu") == 0) + ncpusfound++; + + mainbus_attach_node(self, node, match); + } + + sc->sc_acells = acells; + sc->sc_scells = scells; +} + +int +mainbus_match_primary(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *fa = aux; + struct cfdata *cf = match; + + if (fa->fa_nreg < 1 || fa->fa_reg[0].addr != boot_hart) + return 0; + + return (*cf->cf_attach->ca_match)(parent, match, aux); +} + +int +mainbus_match_secondary(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *fa = aux; + struct cfdata *cf = match; + + if (fa->fa_nreg < 1 || fa->fa_reg[0].addr == boot_hart) + return 0; + + return (*cf->cf_attach->ca_match)(parent, match, aux); +} + +void +mainbus_attach_framebuffer(struct device *self) +{ + int node = OF_finddevice("/chosen"); + + if (node == -1) + return; + + for (node = OF_child(node); node != 0; node = OF_peer(node)) + mainbus_attach_node(self, node, NULL); +} diff --git sys/arch/loongarch64/dev/mpfclock.c sys/arch/loongarch64/dev/mpfclock.c new file mode 100644 index 00000000000..7b39405941b --- /dev/null +++ sys/arch/loongarch64/dev/mpfclock.c @@ -0,0 +1,235 @@ +/* $OpenBSD: mpfclock.c,v 1.1 2022/01/05 03:32:44 visa Exp $ */ + +/* + * Copyright (c) 2022 Visa Hankala + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Driver for PolarFire SoC MSS clock controller. + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +extern void (*cpuresetfn)(void); + +#define CLOCK_CONFIG_CR 0x0008 +#define CLOCK_CONFIG_CR_AHB_DIV_SHIFT 4 +#define CLOCK_CONFIG_CR_AXI_DIV_SHIFT 2 +#define CLOCK_CONFIG_CR_CPU_DIV_SHIFT 0 +#define CLOCK_CONFIG_CR_DIV_MASK 0x3 +#define MSS_RESET_CR 0x0018 +#define SUBBLK_CLOCK_CR 0x0084 +#define SUBBLK_RESET_CR 0x0088 + +#define CLK_CPU 0 +#define CLK_AXI 1 +#define CLK_AHB 2 +#define CLK_ENVM 3 +#define CLK_MAC0 4 +#define CLK_MAC1 5 +#define CLK_MMC 6 +#define CLK_TIMER 7 +#define CLK_MMUART0 8 +#define CLK_MMUART1 9 +#define CLK_MMUART2 10 +#define CLK_MMUART3 11 +#define CLK_MMUART4 12 +#define CLK_SPI0 13 +#define CLK_SPI1 14 +#define CLK_I2C0 15 +#define CLK_I2C1 16 +#define CLK_CAN0 17 +#define CLK_CAN1 18 +#define CLK_USB 19 +#define CLK_RESERVED 20 /* FPGA in SUBBLK_RESET_CR */ +#define CLK_RTC 21 +#define CLK_QSPI 22 +#define CLK_GPIO0 23 +#define CLK_GPIO1 24 +#define CLK_GPIO2 25 +#define CLK_DDRC 26 +#define CLK_FIC0 27 +#define CLK_FIC1 28 +#define CLK_FIC2 29 +#define CLK_FIC3 30 +#define CLK_ATHENA 31 +#define CLK_CFM 32 + +struct mpfclock_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + uint32_t sc_clkcfg; + uint32_t sc_refclk; + + struct clock_device sc_cd; +}; + +#define HREAD4(sc, reg) \ + (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) +#define HWRITE4(sc, reg, val) \ + bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) + +int mpfclock_match(struct device *, void *, void *); +void mpfclock_attach(struct device *, struct device *, void *); + +void mpfclock_enable(void *, uint32_t *, int); +uint32_t mpfclock_get_frequency(void *, uint32_t *); +int mpfclock_set_frequency(void *, uint32_t *, uint32_t); + +void mpfclock_cpureset(void); + +const struct cfattach mpfclock_ca = { + sizeof(struct mpfclock_softc), mpfclock_match, mpfclock_attach +}; + +struct cfdriver mpfclock_cd = { + NULL, "mpfclock", DV_DULL +}; + +struct mutex mpfclock_mtx = MUTEX_INITIALIZER(IPL_HIGH); +struct mpfclock_softc *mpfclock_sc; + +int +mpfclock_match(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *faa = aux; + + if (faa->fa_nreg < 1) + return 0; + return OF_is_compatible(faa->fa_node, "microchip,mpfs-clkcfg"); +} + +void +mpfclock_attach(struct device *parent, struct device *self, void *aux) +{ + struct fdt_attach_args *faa = aux; + struct mpfclock_softc *sc = (struct mpfclock_softc *)self; + + sc->sc_refclk = clock_get_frequency_idx(faa->fa_node, 0); + if (sc->sc_refclk == 0) { + printf(": can't get refclk frequency\n"); + return; + } + + sc->sc_iot = faa->fa_iot; + if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, + faa->fa_reg[0].size, 0, &sc->sc_ioh) != 0) { + printf(": can't map registers\n"); + return; + } + + sc->sc_clkcfg = HREAD4(sc, CLOCK_CONFIG_CR); + + printf(": %u MHz ref clock\n", (sc->sc_refclk + 500000) / 1000000); + + sc->sc_cd.cd_node = faa->fa_node; + sc->sc_cd.cd_cookie = sc; + sc->sc_cd.cd_enable = mpfclock_enable; + sc->sc_cd.cd_get_frequency = mpfclock_get_frequency; + sc->sc_cd.cd_set_frequency = mpfclock_set_frequency; + clock_register(&sc->sc_cd); + + mpfclock_sc = sc; + cpuresetfn = mpfclock_cpureset; +} + +uint32_t +mpfclock_get_frequency(void *cookie, uint32_t *cells) +{ + struct mpfclock_softc *sc = cookie; + uint32_t div, shift; + uint32_t idx = cells[0]; + + if (idx == CLK_MMC) + return 200000000; + + if (idx > CLK_AHB) + idx = CLK_AHB; + + switch (idx) { + case CLK_CPU: + shift = CLOCK_CONFIG_CR_CPU_DIV_SHIFT; + break; + case CLK_AXI: + shift = CLOCK_CONFIG_CR_AXI_DIV_SHIFT; + break; + case CLK_AHB: + shift = CLOCK_CONFIG_CR_AHB_DIV_SHIFT; + break; + default: + panic("%s: invalid idx %u\n", __func__, idx); + } + + div = 1U << ((sc->sc_clkcfg >> shift) & CLOCK_CONFIG_CR_DIV_MASK); + + return sc->sc_refclk / div; +} + +int +mpfclock_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) +{ + return -1; +} + +void +mpfclock_enable(void *cookie, uint32_t *cells, int on) +{ + struct mpfclock_softc *sc = cookie; + uint32_t idx = cells[0]; + uint32_t bit, val; + + if (idx < CLK_ENVM || idx - CLK_ENVM > 31) + return; + bit = 1U << (idx - CLK_ENVM); + + mtx_enter(&mpfclock_mtx); + if (on) { + val = HREAD4(sc, SUBBLK_CLOCK_CR); + val |= bit; + HWRITE4(sc, SUBBLK_CLOCK_CR, val); + + val = HREAD4(sc, SUBBLK_RESET_CR); + val &= ~bit; + HWRITE4(sc, SUBBLK_RESET_CR, val); + } else { + val = HREAD4(sc, SUBBLK_RESET_CR); + val |= bit; + HWRITE4(sc, SUBBLK_RESET_CR, val); + + val = HREAD4(sc, SUBBLK_CLOCK_CR); + val &= ~bit; + HWRITE4(sc, SUBBLK_CLOCK_CR, val); + } + mtx_leave(&mpfclock_mtx); +} + +void +mpfclock_cpureset(void) +{ + struct mpfclock_softc *sc = mpfclock_sc; + + HWRITE4(sc, MSS_RESET_CR, 0xdead); +} diff --git sys/arch/loongarch64/dev/mpfgpio.c sys/arch/loongarch64/dev/mpfgpio.c new file mode 100644 index 00000000000..7d8b049dfa1 --- /dev/null +++ sys/arch/loongarch64/dev/mpfgpio.c @@ -0,0 +1,294 @@ +/* $OpenBSD: mpfgpio.c,v 1.1 2022/02/18 10:51:43 visa Exp $ */ + +/* + * Copyright (c) 2022 Visa Hankala + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Driver for PolarFire SoC MSS GPIO controller. + */ + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#include "gpio.h" + +#define MPFGPIO_CONFIG(i) (0x0000 + (i) * 4) +#define MPFGPIO_CONFIG_EN_INT (1 << 3) +#define MPFGPIO_CONFIG_EN_OE_BUF (1 << 2) +#define MPFGPIO_CONFIG_EN_IN (1 << 1) +#define MPFGPIO_CONFIG_EN_OUT (1 << 0) +#define MPFGPIO_GPIN 0x0084 +#define MPFGPIO_GPOUT 0x0088 +#define MPFGPIO_CLEAR_BITS 0x00a0 +#define MPFGPIO_SET_BITS 0x00a4 + +#define MPFGPIO_MAX_PINS 32 + +struct mpfgpio_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + uint32_t sc_npins; + + struct gpio_controller sc_gc; + + struct gpio_chipset_tag sc_gpio_tag; + gpio_pin_t sc_gpio_pins[MPFGPIO_MAX_PINS]; + uint8_t sc_gpio_claimed[MPFGPIO_MAX_PINS]; +}; + +#define HREAD4(sc, reg) \ + (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) +#define HWRITE4(sc, reg, val) \ + bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) + +int mpfgpio_match(struct device *, void *, void*); +void mpfgpio_attach(struct device *, struct device *, void *); + +void mpfgpio_config_pin(void *, uint32_t *, int); +int mpfgpio_get_pin(void *, uint32_t *); +void mpfgpio_set_pin(void *, uint32_t *, int); + +int mpfgpio_pin_read(void *, int); +void mpfgpio_pin_write(void *, int, int); +void mpfgpio_pin_ctl(void *, int, int); +void mpfgpio_attach_gpio(struct device *); + +const struct cfattach mpfgpio_ca = { + sizeof(struct mpfgpio_softc), mpfgpio_match, mpfgpio_attach +}; + +struct cfdriver mpfgpio_cd = { + NULL, "mpfgpio", DV_DULL +}; + +int +mpfgpio_match(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *faa = aux; + + if (faa->fa_nreg < 1) + return 0; + return OF_is_compatible(faa->fa_node, "microchip,mpfs-gpio"); +} + +void +mpfgpio_attach(struct device *parent, struct device *self, void *aux) +{ + struct fdt_attach_args *faa = aux; + struct mpfgpio_softc *sc = (struct mpfgpio_softc *)self; + unsigned int unit; + + sc->sc_iot = faa->fa_iot; + + unit = (faa->fa_reg[0].addr >> 12) & 0x3; + switch (unit) { + case 0: + sc->sc_npins = 14; + break; + case 1: + sc->sc_npins = 24; + break; + case 2: + sc->sc_npins = 32; + break; + default: + printf(": unexpected GPIO unit %u\n", unit); + return; + } + KASSERT(sc->sc_npins <= MPFGPIO_MAX_PINS); + + if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, faa->fa_reg[0].size, + 0, &sc->sc_ioh) != 0) { + printf(": can't map registers\n"); + return; + } + + clock_enable_all(faa->fa_node); + + printf(": unit %u\n", unit); + + sc->sc_gc.gc_node = faa->fa_node; + sc->sc_gc.gc_cookie = sc; + sc->sc_gc.gc_config_pin = mpfgpio_config_pin; + sc->sc_gc.gc_get_pin = mpfgpio_get_pin; + sc->sc_gc.gc_set_pin = mpfgpio_set_pin; + gpio_controller_register(&sc->sc_gc); + +#if NGPIO > 0 + config_mountroot(self, mpfgpio_attach_gpio); +#endif +} + +void +mpfgpio_config_pin(void *cookie, uint32_t *cells, int config) +{ + struct mpfgpio_softc *sc = cookie; + uint32_t pin = cells[0]; + uint32_t val; + + if (pin >= sc->sc_npins) + return; + + val = HREAD4(sc, MPFGPIO_CONFIG(pin)); + if (config & GPIO_CONFIG_OUTPUT) { + val &= ~MPFGPIO_CONFIG_EN_IN; + val |= MPFGPIO_CONFIG_EN_OUT; + } else { + val |= MPFGPIO_CONFIG_EN_IN; + val &= ~MPFGPIO_CONFIG_EN_OUT; + } + val &= ~MPFGPIO_CONFIG_EN_INT; + HWRITE4(sc, MPFGPIO_CONFIG(pin), val); + + sc->sc_gpio_claimed[pin] = 1; +} + +int +mpfgpio_get_pin(void *cookie, uint32_t *cells) +{ + struct mpfgpio_softc *sc = cookie; + uint32_t pin = cells[0]; + uint32_t flags = cells[1]; + int val; + + if (pin >= sc->sc_npins) + return 0; + + val = (HREAD4(sc, MPFGPIO_GPIN) >> pin) & 1; + if (flags & GPIO_ACTIVE_LOW) + val = !val; + return val; +} + +void +mpfgpio_set_pin(void *cookie, uint32_t *cells, int val) +{ + struct mpfgpio_softc *sc = cookie; + uint32_t pin = cells[0]; + uint32_t flags = cells[1]; + + if (pin >= sc->sc_npins) + return; + + if (flags & GPIO_ACTIVE_LOW) + val = !val; + if (val) + HWRITE4(sc, MPFGPIO_SET_BITS, (1U << (pin % 32))); + else + HWRITE4(sc, MPFGPIO_CLEAR_BITS, (1U << (pin % 32))); +} + +#if NGPIO > 0 +int +mpfgpio_pin_read(void *cookie, int pin) +{ + struct mpfgpio_softc *sc = cookie; + uint32_t cells[2]; + + cells[0] = pin; + cells[1] = 0; + + return mpfgpio_get_pin(sc, cells) ? GPIO_PIN_HIGH : GPIO_PIN_LOW; +} + +void +mpfgpio_pin_write(void *cookie, int pin, int val) +{ + struct mpfgpio_softc *sc = cookie; + uint32_t cells[2]; + + cells[0] = pin; + cells[1] = 0; + + mpfgpio_set_pin(sc, cells, val); +} + +void +mpfgpio_pin_ctl(void *cookie, int pin, int flags) +{ + struct mpfgpio_softc *sc = cookie; + uint32_t cells[2]; + uint32_t config = 0; + + cells[0] = pin; + cells[1] = 0; + + if (flags & GPIO_PIN_OUTPUT) + config |= GPIO_CONFIG_OUTPUT; + + mpfgpio_config_pin(sc, cells, config); +} + +static const struct gpio_chipset_tag mpfgpio_gpio_tag = { + .gp_pin_read = mpfgpio_pin_read, + .gp_pin_write = mpfgpio_pin_write, + .gp_pin_ctl = mpfgpio_pin_ctl, +}; + +void +mpfgpio_attach_gpio(struct device *parent) +{ + struct gpiobus_attach_args gba; + struct mpfgpio_softc *sc = (struct mpfgpio_softc *)parent; + uint32_t cfgreg, pin; + int flags, state; + + for (pin = 0; pin < sc->sc_npins; pin++) { + /* Skip pins claimed by other devices. */ + if (sc->sc_gpio_claimed[pin]) + continue; + + cfgreg = HREAD4(sc, MPFGPIO_CONFIG(pin)); + if (cfgreg & MPFGPIO_CONFIG_EN_OUT) + flags = GPIO_PIN_SET | GPIO_PIN_OUTPUT; + else if (cfgreg & MPFGPIO_CONFIG_EN_IN) + flags = GPIO_PIN_SET | GPIO_PIN_INPUT; + else + flags = GPIO_PIN_SET; + + state = (HREAD4(sc, MPFGPIO_GPIN) >> pin) & 1; + + sc->sc_gpio_pins[pin].pin_caps = + GPIO_PIN_INPUT | GPIO_PIN_OUTPUT; + sc->sc_gpio_pins[pin].pin_flags = flags; + sc->sc_gpio_pins[pin].pin_state = state; + sc->sc_gpio_pins[pin].pin_num = pin; + } + + sc->sc_gpio_tag = mpfgpio_gpio_tag; + sc->sc_gpio_tag.gp_cookie = sc; + + gba.gba_name = "gpio"; + gba.gba_gc = &sc->sc_gpio_tag; + gba.gba_pins = sc->sc_gpio_pins; + gba.gba_npins = sc->sc_npins; + + config_found(&sc->sc_dev, &gba, gpiobus_print); +} +#endif diff --git sys/arch/loongarch64/dev/mpfiic.c sys/arch/loongarch64/dev/mpfiic.c new file mode 100644 index 00000000000..ae74c97fc00 --- /dev/null +++ sys/arch/loongarch64/dev/mpfiic.c @@ -0,0 +1,401 @@ +/* $OpenBSD: mpfiic.c,v 1.1 2022/02/16 13:07:36 visa Exp $ */ + +/* + * Copyright (c) 2022 Visa Hankala + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Driver for PolarFire SoC MSS I2C controller. + */ + +#include +#include +#include +#include + +#include +#include + +#define _I2C_PRIVATE +#include + +#include +#include +#include +#include + +#define I2C_CTRL 0x0000 +#define I2C_CTRL_CR2 (1 << 7) +#define I2C_CTRL_ENS1 (1 << 6) +#define I2C_CTRL_STA (1 << 5) +#define I2C_CTRL_STO (1 << 4) +#define I2C_CTRL_SI (1 << 3) +#define I2C_CTRL_AA (1 << 2) +#define I2C_CTRL_CR1 (1 << 1) +#define I2C_CTRL_CR0 (1 << 0) +#define I2C_STATUS 0x0004 +#define I2C_DATA 0x0008 +#define I2C_SLAVE0ADR 0x000c +#define I2C_SMBUS 0x0010 +#define I2C_FREQ 0x0014 +#define I2C_GLITCHREG 0x0018 +#define I2C_SLAVE1ADR 0x001c + +#define I2C_STATUS_START 0x08 +#define I2C_STATUS_RESTART 0x10 +#define I2C_STATUS_SLAW_ACK 0x18 +#define I2C_STATUS_DATAW_ACK 0x28 +#define I2C_STATUS_LOSTARB 0x38 +#define I2C_STATUS_SLAR_ACK 0x40 +#define I2C_STATUS_DATAR_ACK 0x50 +#define I2C_STATUS_DATAR_NACK 0x58 +#define I2C_STATUS_IDLE 0xf8 + +struct mpfiic_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + int sc_node; + + struct i2c_bus sc_i2c_bus; + struct i2c_controller sc_i2c_tag; + struct rwlock sc_i2c_lock; + + uint32_t sc_bus_freq; /* in Hz */ + uint8_t sc_ctrl; + uint8_t sc_start_sent; +}; + +#define HREAD4(sc, reg) \ + (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) +#define HWRITE4(sc, reg, val) \ + bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) + +int mpfiic_match(struct device *, void *, void*); +void mpfiic_attach(struct device *, struct device *, void *); + +int mpfiic_i2c_acquire_bus(void *, int); +void mpfiic_i2c_release_bus(void *, int); +int mpfiic_i2c_send_start(void *, int); +int mpfiic_i2c_send_stop(void *, int); +int mpfiic_i2c_initiate_xfer(void *, i2c_addr_t, int); +int mpfiic_i2c_read_byte(void *, uint8_t *, int); +int mpfiic_i2c_write_byte(void *, uint8_t, int); +void mpfiic_i2c_scan(struct device *, struct i2cbus_attach_args *, void *); + +int mpfiic_wait(struct mpfiic_softc *, uint8_t); + +const struct cfattach mpfiic_ca = { + sizeof(struct mpfiic_softc), mpfiic_match, mpfiic_attach +}; + +struct cfdriver mpfiic_cd = { + NULL, "mpfiic", DV_DULL +}; + +static struct { + uint32_t div; + uint32_t cr; +} mpfiic_clk_divs[] = { +#ifdef notused + /* BCLK */ + { 8, I2C_CTRL_CR2 | I2C_CTRL_CR1 | I2C_CTRL_CR0 }, +#endif + /* PCLK */ + { 60, I2C_CTRL_CR2 | I2C_CTRL_CR1 }, + { 120, I2C_CTRL_CR2 | I2C_CTRL_CR0 }, + { 160, I2C_CTRL_CR1 | I2C_CTRL_CR0 }, + { 192, I2C_CTRL_CR1 }, + { 224, I2C_CTRL_CR0 }, + { 256, 0 }, + { 960, I2C_CTRL_CR2 }, +}; + +int +mpfiic_match(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *faa = aux; + + if (faa->fa_nreg < 1) + return 0; + return OF_is_compatible(faa->fa_node, "microchip,mpfs-i2c"); +} + +void +mpfiic_attach(struct device *parent, struct device *self, void *aux) +{ + struct i2cbus_attach_args iba; + struct fdt_attach_args *faa = aux; + struct mpfiic_softc *sc = (struct mpfiic_softc *)self; + uint32_t i, bus_freq, clock_freq; + + sc->sc_node = faa->fa_node; + sc->sc_iot = faa->fa_iot; + + clock_freq = clock_get_frequency(sc->sc_node, NULL); + bus_freq = OF_getpropint(sc->sc_node, "clock-frequency", 100000); + + /* Determine clock divider, assumes PCLK. */ + for (i = 0; i < nitems(mpfiic_clk_divs) - 1; i++) { + if (clock_freq / mpfiic_clk_divs[i].div <= bus_freq) + break; + } + sc->sc_bus_freq = clock_freq / mpfiic_clk_divs[i].div; + sc->sc_ctrl = mpfiic_clk_divs[i].cr | I2C_CTRL_ENS1; + + if (sc->sc_bus_freq == 0) { + printf(": invalid bus frequency\n"); + return; + } + + if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, faa->fa_reg[0].size, + 0, &sc->sc_ioh) != 0) { + printf(": can't map registers\n"); + return; + } + + clock_enable_all(sc->sc_node); + + /* Initialize the device. */ + HWRITE4(sc, I2C_CTRL, sc->sc_ctrl); + HWRITE4(sc, I2C_CTRL, 0); + + /* Disable slave address comparison. */ + HWRITE4(sc, I2C_SLAVE0ADR, 0); + HWRITE4(sc, I2C_SLAVE1ADR, 0); + + /* Disable SMBus logic, operate in standard I2C mode. */ + HWRITE4(sc, I2C_SMBUS, 0); + + printf("\n"); + + rw_init(&sc->sc_i2c_lock, "iiclk"); + sc->sc_i2c_tag.ic_cookie = sc; + sc->sc_i2c_tag.ic_acquire_bus = mpfiic_i2c_acquire_bus; + sc->sc_i2c_tag.ic_release_bus = mpfiic_i2c_release_bus; + sc->sc_i2c_tag.ic_send_start = mpfiic_i2c_send_start; + sc->sc_i2c_tag.ic_send_stop = mpfiic_i2c_send_stop; + sc->sc_i2c_tag.ic_initiate_xfer = mpfiic_i2c_initiate_xfer; + sc->sc_i2c_tag.ic_read_byte = mpfiic_i2c_read_byte; + sc->sc_i2c_tag.ic_write_byte = mpfiic_i2c_write_byte; + + memset(&iba, 0, sizeof(iba)); + iba.iba_name = "iic"; + iba.iba_tag = &sc->sc_i2c_tag; + iba.iba_bus_scan = mpfiic_i2c_scan; + iba.iba_bus_scan_arg = &sc->sc_node; + config_found(self, &iba, iicbus_print); + + sc->sc_i2c_bus.ib_node = faa->fa_node; + sc->sc_i2c_bus.ib_ic = &sc->sc_i2c_tag; + i2c_register(&sc->sc_i2c_bus); +} + +int +mpfiic_i2c_acquire_bus(void *arg, int flags) +{ + struct mpfiic_softc *sc = arg; + + if (cold || (flags & I2C_F_POLL)) + return 0; + + return rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR); +} + +void +mpfiic_i2c_release_bus(void *arg, int flags) +{ + struct mpfiic_softc *sc = arg; + + if (cold || (flags & I2C_F_POLL)) + return; + + rw_exit(&sc->sc_i2c_lock); +} + +int +mpfiic_i2c_send_start(void *cookie, int flags) +{ + struct mpfiic_softc *sc = cookie; + int error; + uint8_t nstatus; + + HWRITE4(sc, I2C_CTRL, sc->sc_ctrl | I2C_CTRL_STA); + + if (sc->sc_start_sent) + nstatus = I2C_STATUS_RESTART; + else + nstatus = I2C_STATUS_START; + error = mpfiic_wait(sc, nstatus); + if (error != 0) + return error; + + sc->sc_start_sent = 1; + + return 0; +} + +int +mpfiic_i2c_send_stop(void *cookie, int flags) +{ + struct mpfiic_softc *sc = cookie; + + sc->sc_start_sent = 0; + + HWRITE4(sc, I2C_CTRL, sc->sc_ctrl | I2C_CTRL_STO); + + /* Let a few bus clock cycles pass. */ + delay(4 * 1000000 / sc->sc_bus_freq); + + /* Disable the device. This resets the state machine. */ + HWRITE4(sc, I2C_CTRL, 0); + + return 0; +} + +int +mpfiic_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags) +{ + struct mpfiic_softc *sc = cookie; + int error; + uint8_t mode, nstatus; + + if (addr >= 0x80) + return EINVAL; + + error = mpfiic_i2c_send_start(sc, flags); + if (error != 0) + return error; + + if (flags & I2C_F_READ) { + mode = 0x01; + nstatus = I2C_STATUS_SLAR_ACK; + } else { + mode = 0x00; + nstatus = I2C_STATUS_SLAW_ACK; + } + + HWRITE4(sc, I2C_DATA, (addr << 1) | mode); + HWRITE4(sc, I2C_CTRL, sc->sc_ctrl); + + return mpfiic_wait(sc, nstatus); +} + +int +mpfiic_i2c_read_byte(void *cookie, uint8_t *datap, int flags) +{ + struct mpfiic_softc *sc = cookie; + int error; + uint8_t ack = 0, nstatus; + + if ((flags & I2C_F_LAST) == 0) + ack = I2C_CTRL_AA; + HWRITE4(sc, I2C_CTRL, sc->sc_ctrl | ack); + + if (flags & I2C_F_LAST) + nstatus = I2C_STATUS_DATAR_NACK; + else + nstatus = I2C_STATUS_DATAR_ACK; + error = mpfiic_wait(sc, nstatus); + if (error != 0) + return error; + + *datap = HREAD4(sc, I2C_DATA); + + if (flags & I2C_F_STOP) + error = mpfiic_i2c_send_stop(sc, flags); + + return error; +} + +int +mpfiic_i2c_write_byte(void *cookie, uint8_t data, int flags) +{ + struct mpfiic_softc *sc = cookie; + int error; + + HWRITE4(sc, I2C_DATA, data); + HWRITE4(sc, I2C_CTRL, sc->sc_ctrl); + + error = mpfiic_wait(sc, I2C_STATUS_DATAW_ACK); + if (error != 0) + return error; + + if (flags & I2C_F_STOP) + error = mpfiic_i2c_send_stop(sc, flags); + + return error; +} + +void +mpfiic_i2c_scan(struct device *self, struct i2cbus_attach_args *iba, void *arg) +{ + struct i2c_attach_args ia; + char status[32]; + char *compat; + uint32_t reg[1]; + int iba_node = *(int *)arg; + int len, node; + + for (node = OF_child(iba_node); node != 0; node = OF_peer(node)) { + memset(status, 0, sizeof(status)); + if (OF_getprop(node, "status", status, sizeof(status)) > 0 && + strcmp(status, "disabled") == 0) + continue; + + memset(reg, 0, sizeof(reg)); + if (OF_getprop(node, "reg", ®, sizeof(reg)) != sizeof(reg)) + continue; + + len = OF_getproplen(node, "compatible"); + if (len <= 0) + continue; + + compat = malloc(len, M_TEMP, M_WAITOK); + OF_getprop(node, "compatible", compat, len); + + memset(&ia, 0, sizeof(ia)); + ia.ia_tag = iba->iba_tag; + ia.ia_addr = bemtoh32(®[0]); + ia.ia_name = compat; + ia.ia_namelen = len; + ia.ia_cookie = &node; + config_found(self, &ia, iic_print); + + free(compat, M_TEMP, len); + } +} + +int +mpfiic_wait(struct mpfiic_softc *sc, uint8_t nstatus) +{ + int timeout; + uint8_t ctrl, status; + + for (timeout = 100000; timeout > 0; timeout--) { + ctrl = HREAD4(sc, I2C_CTRL); + if (ctrl & I2C_CTRL_SI) + break; + delay(1); + } + if (timeout == 0) + return ETIMEDOUT; + + status = HREAD4(sc, I2C_STATUS); + if (status != nstatus) + return EIO; + + return 0; +} diff --git sys/arch/loongarch64/dev/pci_machdep.c sys/arch/loongarch64/dev/pci_machdep.c new file mode 100644 index 00000000000..02b1a9767c7 --- /dev/null +++ sys/arch/loongarch64/dev/pci_machdep.c @@ -0,0 +1,175 @@ +/* $OpenBSD: pci_machdep.c,v 1.3 2026/05/10 08:47:22 kettenis Exp $ */ + +/* + * Copyright (c) 2019 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include + +#include +#include + +void +pci_msi_enable(pci_chipset_tag_t pc, pcitag_t tag, + bus_addr_t addr, uint32_t data) +{ + pcireg_t reg; + int off; + + if (pci_get_capability(pc, tag, PCI_CAP_MSI, &off, ®) == 0) + panic("%s: no msi capability", __func__); + + if (reg & PCI_MSI_MC_C64) { + pci_conf_write(pc, tag, off + PCI_MSI_MA, addr); + pci_conf_write(pc, tag, off + PCI_MSI_MAU32, addr >> 32); + pci_conf_write(pc, tag, off + PCI_MSI_MD64, data); + } else { + pci_conf_write(pc, tag, off + PCI_MSI_MA, addr); + pci_conf_write(pc, tag, off + PCI_MSI_MD32, data); + } + pci_conf_write(pc, tag, off, reg | PCI_MSI_MC_MSIE); +} + +int +pci_msix_table_map(pci_chipset_tag_t pc, pcitag_t tag, + bus_space_tag_t memt, bus_space_handle_t *memh) +{ + bus_addr_t base; + pcireg_t reg, table, type; + int bir, offset; + int off, tblsz; + + if (pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, ®) == 0) + panic("%s: no msix capability", __func__); + + table = pci_conf_read(pc, tag, off + PCI_MSIX_TABLE); + bir = (table & PCI_MSIX_TABLE_BIR); + offset = (table & PCI_MSIX_TABLE_OFF); + tblsz = PCI_MSIX_MC_TBLSZ(reg) + 1; + + bir = PCI_MAPREG_START + bir * 4; + type = pci_mapreg_type(pc, tag, bir); + if (pci_mapreg_info(pc, tag, bir, type, &base, NULL, NULL) || + bus_space_map(memt, base + offset, tblsz * 16, 0, memh)) + return -1; + + return 0; +} + +void +pci_msix_table_unmap(pci_chipset_tag_t pc, pcitag_t tag, + bus_space_tag_t memt, bus_space_handle_t memh) +{ + pcireg_t reg; + int tblsz; + + if (pci_get_capability(pc, tag, PCI_CAP_MSIX, NULL, ®) == 0) + panic("%s: no msix capability", __func__); + + tblsz = PCI_MSIX_MC_TBLSZ(reg) + 1; + bus_space_unmap(memt, memh, tblsz * 16); +} + +void +pci_msix_enable(pci_chipset_tag_t pc, pcitag_t tag, bus_space_tag_t memt, + int vec, bus_addr_t addr, uint32_t data) +{ + bus_space_handle_t memh; + pcireg_t reg; + uint32_t ctrl; + int off; + + if (pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, ®) == 0) + panic("%s: no msix capability", __func__); + + KASSERT(vec <= PCI_MSIX_MC_TBLSZ(reg)); + + if (pci_msix_table_map(pc, tag, memt, &memh)) + panic("%s: cannot map registers", __func__); + + bus_space_write_4(memt, memh, PCI_MSIX_MA(vec), addr); + bus_space_write_4(memt, memh, PCI_MSIX_MAU32(vec), addr >> 32); + bus_space_write_4(memt, memh, PCI_MSIX_MD(vec), data); + bus_space_barrier(memt, memh, PCI_MSIX_MA(vec), 16, + BUS_SPACE_BARRIER_WRITE); + ctrl = bus_space_read_4(memt, memh, PCI_MSIX_VC(vec)); + bus_space_write_4(memt, memh, PCI_MSIX_VC(vec), + ctrl & ~PCI_MSIX_VC_MASK); + + pci_msix_table_unmap(pc, tag, memt, memh); + + pci_conf_write(pc, tag, off, reg | PCI_MSIX_MC_MSIXE); +} + +int +_pci_intr_map_msi(struct pci_attach_args *pa, pci_intr_handle_t *ihp) +{ + pci_chipset_tag_t pc = pa->pa_pc; + pcitag_t tag = pa->pa_tag; + + if ((pa->pa_flags & PCI_FLAGS_MSI_ENABLED) == 0 || + pci_get_capability(pc, tag, PCI_CAP_MSI, NULL, NULL) == 0) + return -1; + + ihp->ih_pc = pa->pa_pc; + ihp->ih_tag = pa->pa_tag; + ihp->ih_intrpin = 0; + ihp->ih_type = PCI_MSI; + ihp->ih_dmat = pa->pa_dmat; + + return 0; +} + +int +_pci_intr_map_msivec(struct pci_attach_args *pa, int vec, + pci_intr_handle_t *ihp) +{ + return -1; +} + +int +_pci_intr_map_msix(struct pci_attach_args *pa, int vec, + pci_intr_handle_t *ihp) +{ + pci_chipset_tag_t pc = pa->pa_pc; + pcitag_t tag = pa->pa_tag; + pcireg_t reg, table, type; + int bir, off; + + if ((pa->pa_flags & PCI_FLAGS_MSI_ENABLED) == 0 || + pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, ®) == 0) + return -1; + + if (vec > PCI_MSIX_MC_TBLSZ(reg)) + return -1; + + table = pci_conf_read(pc, tag, off + PCI_MSIX_TABLE); + bir = PCI_MAPREG_START + (table & PCI_MSIX_TABLE_BIR) * 4; + type = pci_mapreg_type(pc, tag, bir); + if (pci_mapreg_assign(pa, bir, type, NULL, NULL)) + return -1; + + ihp->ih_pc = pa->pa_pc; + ihp->ih_tag = pa->pa_tag; + ihp->ih_intrpin = vec; + ihp->ih_type = PCI_MSIX; + ihp->ih_dmat = pa->pa_dmat; + + return 0; +} + diff --git sys/arch/loongarch64/dev/plic.c sys/arch/loongarch64/dev/plic.c new file mode 100644 index 00000000000..983073aa000 --- /dev/null +++ sys/arch/loongarch64/dev/plic.c @@ -0,0 +1,736 @@ +/* $OpenBSD: plic.c,v 1.13 2024/09/04 07:54:51 mglocker Exp $ */ + +/* + * Copyright (c) 2020, Mars Li + * Copyright (c) 2020, Brian Bamsch + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "loongarch64/dev/loongarch_cpu_intc.h" + +#include +#include + +/* + * This driver implements a version of the RISC-V PLIC with the actual layout + * specified in chapter 8 of the SiFive U5 Coreplex Series Manual: + * + * https://static.dev.sifive.com/U54-MC-RVCoreIP.pdf + * + * The largest number supported by devices marked as 'sifive,plic-1.0.0', is + * 1024, of which device 0 is defined as non-existent by the RISC-V Privileged + * Spec. + */ + +#define PLIC_MAX_IRQS 1024 + +#define PLIC_PRIORITY_BASE 0x000000U + +#define PLIC_ENABLE_BASE 0x002000U +#define PLIC_ENABLE_STRIDE 0x80U +#define IRQ_ENABLE 1 +#define IRQ_DISABLE 0 + +#define PLIC_CONTEXT_BASE 0x200000U +#define PLIC_CONTEXT_STRIDE 0x1000U +#define PLIC_CONTEXT_THRESHOLD 0x0U +#define PLIC_CONTEXT_CLAIM 0x4U + +#define PLIC_PRIORITY(n) (PLIC_PRIORITY_BASE + (n) * sizeof(uint32_t)) +#define PLIC_ENABLE(sc, n, h) \ + (sc->sc_contexts[h].enable_offset + ((n) / 32) * sizeof(uint32_t)) +#define PLIC_THRESHOLD(sc, h) \ + (sc->sc_contexts[h].context_offset + PLIC_CONTEXT_THRESHOLD) +#define PLIC_CLAIM(sc, h) \ + (sc->sc_contexts[h].context_offset + PLIC_CONTEXT_CLAIM) + + +struct plic_intrhand { + TAILQ_ENTRY(plic_intrhand) ih_list; /* link on intrq list */ + int (*ih_func)(void *); /* handler */ + void *ih_arg; /* arg for handler */ + int ih_ipl; /* IPL_* */ + int ih_flags; + int ih_irq; /* IRQ number */ + struct evcount ih_count; + char *ih_name; + struct cpu_info *ih_ci; +}; + +/* + * One interrupt source could have multiple handler attached, + * each handler could have different priority level, + * we track the max and min priority level. + */ +struct plic_irqsrc { + TAILQ_HEAD(, plic_intrhand) is_list; /* handler list */ + int is_irq_max; /* IRQ to mask while handling */ + int is_irq_min; /* lowest IRQ when shared */ +}; + +struct plic_context { + bus_size_t enable_offset; + bus_size_t context_offset; +}; + +struct plic_softc { + struct device sc_dev; + int sc_node; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + struct plic_irqsrc *sc_isrcs; + struct plic_context sc_contexts[MAXCPUS]; + int sc_ndev; + struct interrupt_controller sc_intc; +}; +struct plic_softc *plic = NULL; + +int plic_match(struct device *, void *, void *); +void plic_attach(struct device *, struct device *, void *); +int plic_irq_handler(void *); +int plic_irq_dispatch(uint32_t, void *); +void *plic_intr_establish(int, int, struct cpu_info *, + int (*)(void *), void *, char *); +void *plic_intr_establish_fdt(void *, int *, int, struct cpu_info *, + int (*)(void *), void *, char *); +void plic_intr_disestablish(void *); +void plic_intr_route(void *, int, struct cpu_info *); +void plic_intr_barrier(void *); + +void plic_splx(int); +int plic_spllower(int); +int plic_splraise(int); +void plic_setipl(int); +void plic_calc_mask(void); + +/* helper function */ +int plic_get_cpuid(int); +void plic_set_priority(int, uint32_t); +void plic_set_threshold(int, uint32_t); +void plic_intr_route_grid(int, int, int); +void plic_intr_enable_with_pri(int, uint32_t, int); +void plic_intr_disable(int, int); + + +const struct cfattach plic_ca = { + sizeof(struct plic_softc), plic_match, plic_attach, +}; + +struct cfdriver plic_cd = { + NULL, "plic", DV_DULL +}; + +int plic_attached = 0; + +int +plic_match(struct device *parent, void *cfdata, void *aux) +{ + struct fdt_attach_args *faa = aux; + + if (plic_attached) + return 0; // Only expect one instance of PLIC + + return (OF_is_compatible(faa->fa_node, "loongarch,plic0") || + OF_is_compatible(faa->fa_node, "sifive,plic-1.0.0") || + OF_is_compatible(faa->fa_node, "thead,c900-plic")); +} + +void +plic_attach(struct device *parent, struct device *dev, void *aux) +{ + struct plic_softc *sc; + struct fdt_attach_args *faa; + uint32_t *cells; + uint32_t irq; + int cpu; + int node; + int len; + int ncell; + int context; + int i; + struct cpu_info *ci; + CPU_INFO_ITERATOR cii; + + if (plic_attached) + return; + + plic = sc = (struct plic_softc *)dev; + faa = (struct fdt_attach_args *)aux; + + if (faa->fa_nreg < 1) + return; + + sc->sc_node = node = faa->fa_node; + sc->sc_iot = faa->fa_iot; + + /* determine number of devices sending intr to this ic */ + sc->sc_ndev = OF_getpropint(faa->fa_node, "loongarch,ndev", -1); + if (sc->sc_ndev < 0) { + printf(": unable to resolve number of devices\n"); + return; + } + + if (sc->sc_ndev >= PLIC_MAX_IRQS) { + printf(": invalid ndev (%d)\n", sc->sc_ndev); + return; + } + + /* map interrupt controller to va space */ + if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, + faa->fa_reg[0].size, 0, &sc->sc_ioh)) + panic("%s: bus_space_map failed!", __func__); + + sc->sc_isrcs = mallocarray(PLIC_MAX_IRQS, sizeof(struct plic_irqsrc), + M_DEVBUF, M_ZERO | M_NOWAIT); + + for (irq = 1; irq <= sc->sc_ndev; irq++) { + TAILQ_INIT(&sc->sc_isrcs[irq].is_list); + plic_set_priority(irq, 0);// Mask interrupt + } + + /* + * Calculate the per-cpu enable and context register offsets. + * + * This is tricky for a few reasons. The PLIC divides the interrupt + * enable, threshold, and claim bits by "context" + * + * The tricky part is that the PLIC spec imposes no restrictions on how + * these contexts are laid out. So for example, there is no guarantee + * that each CPU will have both a machine mode and supervisor context, + * or that different PLIC implementations will organize the context + * registers in the same way. On top of this, we must handle the fact + * that cpuid != hartid, as they may have been renumbered during boot. + * We perform the following steps: + * + * 1. Examine the PLIC's "interrupts-extended" property and skip any + * entries that are not for supervisor external interrupts. + * + * 2. Walk up the device tree to find the corresponding CPU, using node + * property to identify the cpuid. + * + * 3. Calculate the register offsets based on the context number. + */ + len = OF_getproplen(node, "interrupts-extended"); + if (len <= 0) { + printf(": could not find interrupts-extended\n"); + return; + } + + cells = malloc(len, M_TEMP, M_WAITOK); + ncell = len / sizeof(*cells); + if (OF_getpropintarray(node, "interrupts-extended", cells, len) < 0) { + printf(": failed to read interrupts-extended\n"); + free(cells, M_TEMP, len); + return; + } + + for (i = 0, context = 0; i < ncell; i += 2, context++) { + /* Skip M-mode external interrupts */ + if (cells[i + 1] != IRQ_EXTERNAL_SUPERVISOR) + continue; + + /* Get the corresponding cpuid. */ + cpu = plic_get_cpuid(OF_getnodebyphandle(cells[i])); + if (cpu < 0) + continue; + + /* + * Set the enable and context register offsets for the CPU. + * + * We assume S-mode handler always comes later than M-mode + * handler, but this might be a little fragile. + * + * XXX + * sifive spec doesn't list hart0 S-mode enable/contexts + * in its memory map, but QEMU emulates hart0 S-mode + * enable/contexts? Otherwise the following offset calculation + * would point to hart1 M-mode enable/contexts. + */ + sc->sc_contexts[cpu].enable_offset = PLIC_ENABLE_BASE + + context * PLIC_ENABLE_STRIDE; + sc->sc_contexts[cpu].context_offset = PLIC_CONTEXT_BASE + + context * PLIC_CONTEXT_STRIDE; + } + + free(cells, M_TEMP, len); + + /* Set CPU interrupt priority thresholds to minimum */ + CPU_INFO_FOREACH(cii, ci) { + plic_set_threshold(ci->ci_cpuid, 0); + } + + plic_setipl(IPL_HIGH); /* XXX ??? */ + plic_calc_mask(); + + /* + * insert self into the external interrupt handler entry in + * global interrupt handler vector + */ + loongarch_intc_intr_establish(IRQ_EXTERNAL_SUPERVISOR, 0, + plic_irq_handler, NULL, "plic0"); + + /* + * From now on, spl update must be enforced to plic, so + * spl* routine should be updated. + */ + loongarch_set_intr_func(plic_splraise, plic_spllower, + plic_splx, plic_setipl); + + plic_attached = 1; + + /* enable external interrupt */ + + sc->sc_intc.ic_node = faa->fa_node; + sc->sc_intc.ic_cookie = sc; + sc->sc_intc.ic_establish = plic_intr_establish_fdt; + sc->sc_intc.ic_disestablish = plic_intr_disestablish; + sc->sc_intc.ic_route = plic_intr_route; + // sc->sc_intc.ic_cpu_enable = XXX Per-CPU Initialization? + sc->sc_intc.ic_barrier = plic_intr_barrier; + + loongarch_intr_register_fdt(&sc->sc_intc); + + printf("\n"); +} + +int +plic_irq_handler(void *frame) +{ + struct plic_softc* sc; + uint32_t pending; + uint32_t cpu; + int handled = 0; + + sc = plic; + cpu = cpu_number(); + + pending = bus_space_read_4(sc->sc_iot, sc->sc_ioh, + PLIC_CLAIM(sc, cpu)); + + if (pending >= sc->sc_ndev) { + printf("plic0: pending %x\n", pending); + return 0; + } + + if (pending) { + handled = plic_irq_dispatch(pending, frame); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, + PLIC_CLAIM(sc, cpu), pending); + +//#define DEBUG_INTC +#ifdef DEBUG_INTC + if (handled == 0) { + printf("plic handled == 0 on pending %d\n", pending); + } +#endif /* DEBUG_INTC */ + } + + return handled; +} + +int +plic_irq_dispatch(uint32_t irq, void *frame) +{ + int pri, s; + int handled = 0; + struct plic_softc* sc; + struct plic_intrhand *ih; + void *arg; + +#ifdef DEBUG_INTC + printf("plic irq %d fired\n", irq); +#endif + + sc = plic; + pri = sc->sc_isrcs[irq].is_irq_max; + s = plic_splraise(pri); + TAILQ_FOREACH(ih, &sc->sc_isrcs[irq].is_list, ih_list) { +#ifdef MULTIPROCESSOR + int need_lock; + + if (ih->ih_flags & IPL_MPSAFE) + need_lock = 0; + else + need_lock = s < IPL_SCHED; + + if (need_lock) + KERNEL_LOCK(); +#endif + + if (ih->ih_arg) + arg = ih->ih_arg; + else + arg = frame; + + intr_enable(); + handled = ih->ih_func(arg); + intr_disable(); + if (handled) + ih->ih_count.ec_count++; + +#ifdef MULTIPROCESSOR + if (need_lock) + KERNEL_UNLOCK(); +#endif + } + + plic_splx(s); + return handled; +} + +void * +plic_intr_establish(int irqno, int level, struct cpu_info *ci, + int (*func)(void *), void *arg, char *name) +{ + struct plic_softc *sc = plic; + struct plic_intrhand *ih; + u_long sie; + + if (irqno < 0 || irqno >= PLIC_MAX_IRQS) + panic("plic_intr_establish: bogus irqnumber %d: %s", + irqno, name); + + if (ci == NULL) + ci = &cpu_info_primary; + + ih = malloc(sizeof *ih, M_DEVBUF, M_WAITOK); + ih->ih_func = func; + ih->ih_arg = arg; + ih->ih_ipl = level & IPL_IRQMASK; + ih->ih_flags = level & IPL_FLAGMASK; + ih->ih_irq = irqno; + ih->ih_name = name; + ih->ih_ci = ci; + + sie = intr_disable(); + + TAILQ_INSERT_TAIL(&sc->sc_isrcs[irqno].is_list, ih, ih_list); + + if (name != NULL) + evcount_attach(&ih->ih_count, name, &ih->ih_irq); + +#ifdef DEBUG_INTC + printf("%s irq %d level %d [%s]\n", __func__, irqno, level, + name); +#endif + + plic_calc_mask(); + + intr_restore(sie); + return (ih); +} + +void * +plic_intr_establish_fdt(void *cookie, int *cell, int level, + struct cpu_info *ci, int (*func)(void *), void *arg, char *name) +{ + return plic_intr_establish(cell[0], level, ci, func, arg, name); +} + +void +plic_intr_disestablish(void *cookie) +{ + struct plic_softc *sc = plic; + struct plic_intrhand *ih = cookie; + int irqno = ih->ih_irq; + u_long sie; + + sie = intr_disable(); + + TAILQ_REMOVE(&sc->sc_isrcs[irqno].is_list, ih, ih_list); + if (ih->ih_name != NULL) + evcount_detach(&ih->ih_count); + + intr_restore(sie); + + free(ih, M_DEVBUF, 0); +} + +void +plic_intr_route(void *cookie, int enable, struct cpu_info *ci) +{ + struct plic_softc *sc = plic; + struct plic_intrhand *ih = cookie; + + int irq = ih->ih_irq; + int cpu = ci->ci_cpuid; + uint32_t min_pri = sc->sc_isrcs[irq].is_irq_min; + + if (enable == IRQ_ENABLE) { + plic_intr_enable_with_pri(irq, min_pri, cpu); + } else { + plic_intr_route_grid(irq, IRQ_DISABLE, cpu); + } +} + +void +plic_intr_barrier(void *cookie) +{ + struct plic_intrhand *ih = cookie; + + sched_barrier(ih->ih_ci); +} + +void +plic_splx(int new) +{ + /* XXX + * how to do pending external interrupt ? + * After set the new threshold, if there is any pending + * external interrupts whose priority is now greater than the + * threshold, they will get passed through plic to cpu, + * trigger a new claim/complete cycle. + * So there is no need to handle pending external intr here. + * + */ + struct cpu_info *ci = curcpu(); + + /* Pending software intr is handled here */ + if (ci->ci_ipending & loongarch_smask[new]) + loongarch_do_pending_intr(new); + + plic_setipl(new); +} + +int +plic_spllower(int new) +{ + struct cpu_info *ci = curcpu(); + int old = ci->ci_cpl; + plic_splx(new); + return (old); +} + +int +plic_splraise(int new) +{ + struct cpu_info *ci = curcpu(); + int old; + old = ci->ci_cpl; + + /* + * setipl must always be called because there is a race window + * where the variable is updated before the mask is set + * an interrupt occurs in that window without the mask always + * being set, the hardware might not get updated on the next + * splraise completely messing up spl protection. + */ + if (old > new) + new = old; + + plic_setipl(new); + + return (old); +} + +void +plic_setipl(int new) +{ + struct cpu_info *ci = curcpu(); + u_long sie; + + /* disable here is only to keep hardware in sync with ci->ci_cpl */ + sie = intr_disable(); + ci->ci_cpl = new; + + /* higher values are higher priority */ + plic_set_threshold(ci->ci_cpuid, new); + + /* trigger deferred timer interrupt if cpl is now low enough */ + if (ci->ci_timer_deferred && new < IPL_CLOCK) + sbi_set_timer(0); + + intr_restore(sie); +} + + /* + * update the max/min priority for an interrupt src, + * and enforce the updated priority to plic. + * this should be called whenever a new handler is attached. + */ +void +plic_calc_mask(void) +{ + struct cpu_info *ci = curcpu(); + struct plic_softc *sc = plic; + struct plic_intrhand *ih; + int irq; + + /* PLIC irq 0 is reserved, thus we start from 1 */ + for (irq = 1; irq <= sc->sc_ndev; irq++) { + int max = IPL_NONE; + int min = IPL_HIGH; + TAILQ_FOREACH(ih, &sc->sc_isrcs[irq].is_list, ih_list) { + if (ih->ih_ipl > max) + max = ih->ih_ipl; + + if (ih->ih_ipl < min) + min = ih->ih_ipl; + } + + if (max == IPL_NONE) + min = IPL_NONE; + + if (sc->sc_isrcs[irq].is_irq_max == max && + sc->sc_isrcs[irq].is_irq_min == min) + continue; + + sc->sc_isrcs[irq].is_irq_max = max; + sc->sc_isrcs[irq].is_irq_min = min; + + /* Enable interrupts at lower levels, clear -> enable */ + /* Set interrupt priority/enable */ + if (min != IPL_NONE) { + plic_intr_enable_with_pri(irq, min, ci->ci_cpuid); + } else { + plic_intr_disable(irq, ci->ci_cpuid); + } + } + + plic_setipl(ci->ci_cpl); +} + +/***************** helper functions *****************/ + +/* + * OpenBSD saves cpu node info in ci struct, so we can search + * cpuid by node matching + */ +int +plic_get_cpuid(int intc) +{ + uint32_t hart; + int parent_node; + struct cpu_info *ci; + CPU_INFO_ITERATOR cii; + + /* Check the interrupt controller layout. */ + if (OF_getpropintarray(intc, "#interrupt-cells", &hart, + sizeof(hart)) < 0) { + printf(": could not find #interrupt-cells for phandle %u\n", intc); + return (-1); + } + + /* + * The parent of the interrupt-controller is the CPU we are + * interested in, so search for its OF node index. + */ + parent_node = OF_parent(intc); + CPU_INFO_FOREACH(cii, ci) { + if (ci->ci_node == parent_node) + return ci->ci_cpuid; + } + return -1; +} + +/* update priority for intr src 'irq' */ +void +plic_set_priority(int irq, uint32_t pri) +{ + struct plic_softc *sc = plic; + uint32_t prival; + + /* + * sifive plic only has 0 - 7 priority levels, yet OpenBSD defines + * 0 - 12 priority levels(level 1 - 4 are for SOFT*, level 12 + * is for IPI. They should NEVER be passed to plic. + * So we calculate plic priority in the following way: + */ + if (pri <= 4 || pri >= 12)//invalid input + prival = 0;//effectively disable this intr source + else + prival = pri - 4; + + bus_space_write_4(sc->sc_iot, sc->sc_ioh, + PLIC_PRIORITY(irq), prival); +} + +/* update threshold for 'cpu' */ +void +plic_set_threshold(int cpu, uint32_t threshold) +{ + struct plic_softc *sc = plic; + uint32_t prival; + + if (threshold < 4) // enable everything (as far as plic is concerned) + prival = 0; + else if (threshold >= 12) // invalid priority level ? + prival = IPL_HIGH - 4; // XXX Device-specific high threshold + else // everything else + prival = threshold - 4; // XXX Device-specific threshold offset + + bus_space_write_4(sc->sc_iot, sc->sc_ioh, + PLIC_THRESHOLD(sc, cpu), prival); +} + +/* + * turns on/off the route from intr source 'irq' + * to context 'ci' based on 'enable' + */ +void +plic_intr_route_grid(int irq, int enable, int cpu) +{ + struct plic_softc *sc = plic; + uint32_t val, mask; + + if (irq == 0) + return; + + KASSERT(cpu < MAXCPUS); + + mask = (1 << (irq % 32)); + val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, + PLIC_ENABLE(sc, irq, cpu)); + if (enable == IRQ_ENABLE) + val |= mask; + else + val &= ~mask; + + bus_space_write_4(sc->sc_iot, sc->sc_ioh, + PLIC_ENABLE(sc, irq, cpu), val); +} + +/* + * Enable intr src 'irq' to cpu 'cpu' by setting: + * - priority + * - threshold + * - enable bit + */ +void +plic_intr_enable_with_pri(int irq, uint32_t min_pri, int cpu) +{ + plic_set_priority(irq, min_pri); + plic_set_threshold(cpu, min_pri-1); + plic_intr_route_grid(irq, IRQ_ENABLE, cpu); +} + +void +plic_intr_disable(int irq, int cpu) +{ + plic_set_priority(irq, 0); + plic_set_threshold(cpu, IPL_HIGH); + plic_intr_route_grid(irq, IRQ_DISABLE, cpu); +} +/***************** end of helper functions *****************/ diff --git sys/arch/loongarch64/dev/sgmsi.c sys/arch/loongarch64/dev/sgmsi.c new file mode 100644 index 00000000000..1e44a867f4a --- /dev/null +++ sys/arch/loongarch64/dev/sgmsi.c @@ -0,0 +1,192 @@ +/* $OpenBSD: sgmsi.c,v 1.1 2025/12/02 19:57:29 kettenis Exp $ */ +/* + * Copyright (c) 2025 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +struct sgmsi_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_clr_ioh; + + uint32_t sc_msi_mask; + bus_addr_t sc_msi_addr; + uint32_t sc_msi_range[4]; + struct interrupt_controller sc_msi_ic; +}; + +struct sgmsi_intrhand { + struct sgmsi_softc *ih_sc; + int (*ih_func)(void *); + void *ih_arg; + int ih_msi; + struct interrupt_controller *ih_ic; + void *ih_cookie; +}; + +int sgmsi_match(struct device *, void *, void *); +void sgmsi_attach(struct device *, struct device *, void *); + +const struct cfattach sgmsi_ca = { + sizeof (struct sgmsi_softc), sgmsi_match, sgmsi_attach +}; + +struct cfdriver sgmsi_cd = { + NULL, "sgmsi", DV_DULL +}; + +void *sgmsi_intr_establish_msi(void *, uint64_t *, uint64_t *, + int, struct cpu_info *, int (*)(void *), void *, char *); +void sgmsi_intr_disestablish_msi(void *); +void sgmsi_barrier(void *); + +int +sgmsi_match(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *faa = aux; + + return OF_is_compatible(faa->fa_node, "sophgo,sg2042-msi"); +} + +void +sgmsi_attach(struct device *parent, struct device *self, void *aux) +{ + struct sgmsi_softc *sc = (struct sgmsi_softc *)self; + struct fdt_attach_args *faa = aux; + int idx; + + if (OF_getpropintarray(faa->fa_node, "msi-ranges", sc->sc_msi_range, + sizeof(sc->sc_msi_range)) != sizeof(sc->sc_msi_range)) { + printf(": invalid msi-ranges property\n"); + return; + } + sc->sc_msi_mask = (1UL << sc->sc_msi_range[3]) - 1; + + idx = OF_getindex(faa->fa_node, "doorbell", "reg-names"); + if (idx < 0 || idx >= faa->fa_nreg) { + printf(": no doorbell registers\n"); + return; + } + sc->sc_msi_addr = faa->fa_reg[idx].addr; + + sc->sc_iot = faa->fa_iot; + idx = OF_getindex(faa->fa_node, "clr", "reg-names"); + if (idx < 0 || idx >= faa->fa_nreg) { + printf(": no clr registers\n"); + return; + } + if (bus_space_map(sc->sc_iot, faa->fa_reg[idx].addr, + faa->fa_reg[idx].size, 0, &sc->sc_clr_ioh)) { + printf(": can't map registers\n"); + return; + } + printf("\n"); + + sc->sc_msi_ic.ic_node = faa->fa_node; + sc->sc_msi_ic.ic_cookie = sc; + sc->sc_msi_ic.ic_establish_msi = sgmsi_intr_establish_msi; + sc->sc_msi_ic.ic_disestablish = sgmsi_intr_disestablish_msi; + sc->sc_msi_ic.ic_barrier = sgmsi_barrier; + fdt_intr_register(&sc->sc_msi_ic); +} + +int +sgmsi_intr(void *arg) +{ + struct sgmsi_intrhand *ih = arg; + struct sgmsi_softc *sc = ih->ih_sc; + + /* ACK the interrupt. */ + bus_space_write_4(sc->sc_iot, sc->sc_clr_ioh, 0, (1U << ih->ih_msi)); + + return ih->ih_func(ih->ih_arg); +} + +extern LIST_HEAD(, interrupt_controller) interrupt_controllers; + +void * +sgmsi_intr_establish_msi(void *cookie, uint64_t *addr, uint64_t *data, + int level, struct cpu_info *ci, int (*func)(void *), void *arg, char *name) +{ + struct sgmsi_softc *sc = cookie; + struct sgmsi_intrhand *ih; + struct interrupt_controller *ic; + uint32_t cells[2]; + int msi; + + msi = ffs(sc->sc_msi_mask) - 1; + if (msi == -1) + return NULL; + cells[0] = sc->sc_msi_range[1] + msi; + cells[1] = sc->sc_msi_range[2]; + + /* Lookup the parent interrupt controller. */ + LIST_FOREACH(ic, &interrupt_controllers, ic_list) { + if (ic->ic_phandle == sc->sc_msi_range[0]) + break; + } + if (ic == NULL) + return NULL; + + ih = malloc(sizeof(struct sgmsi_intrhand), M_DEVBUF, M_WAITOK); + ih->ih_sc = sc; + ih->ih_func = func; + ih->ih_arg = arg; + ih->ih_msi = msi; + ih->ih_ic = ic; + ih->ih_cookie = ic->ic_establish(ic->ic_cookie, cells, level, + ci, sgmsi_intr, ih, name); + if (ih->ih_cookie == NULL) { + free(ih, M_DEVBUF, sizeof(*ih)); + return NULL; + } + sc->sc_msi_mask &= ~(1U << ih->ih_msi); + + /* ACK the interrupt. */ + bus_space_write_4(sc->sc_iot, sc->sc_clr_ioh, 0, (1U << ih->ih_msi)); + + *addr = sc->sc_msi_addr; + *data = (1U << ih->ih_msi); + return ih; +} + +void +sgmsi_intr_disestablish_msi(void *cookie) +{ + struct sgmsi_intrhand *ih = cookie; + + ih->ih_ic->ic_disestablish(ih->ih_cookie); + ih->ih_sc->sc_msi_mask |= (1U << ih->ih_msi); + free(ih, M_DEVBUF, sizeof(*ih)); +} + +void +sgmsi_barrier(void *cookie) +{ + struct sgmsi_intrhand *ih = cookie; + + ih->ih_ic->ic_barrier(ih->ih_cookie); +} diff --git sys/arch/loongarch64/dev/simplebus.c sys/arch/loongarch64/dev/simplebus.c new file mode 100644 index 00000000000..5ef2f3be745 --- /dev/null +++ sys/arch/loongarch64/dev/simplebus.c @@ -0,0 +1,437 @@ +/* $OpenBSD: simplebus.c,v 1.11 2026/07/19 11:53:08 kettenis Exp $ */ + +/* + * Copyright (c) 2016 Patrick Wildt + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +int simplebus_match(struct device *, void *, void *); +void simplebus_attach(struct device *, struct device *, void *); + +void simplebus_check_dma(struct simplebus_softc *); + +void simplebus_attach_node(struct device *, int); +int simplebus_bs_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, + bus_space_handle_t *); +int simplebus_dmamap_load_buffer(bus_dma_tag_t, bus_dmamap_t, void *, + bus_size_t, struct proc *, int, paddr_t *, int *, int *, int *, int); + +const struct cfattach simplebus_ca = { + sizeof(struct simplebus_softc), simplebus_match, simplebus_attach +}; + +struct cfdriver simplebus_cd = { + NULL, "simplebus", DV_DULL +}; + +/* + * Simplebus is a generic bus with no special casings. + */ +int +simplebus_match(struct device *parent, void *cfdata, void *aux) +{ + struct fdt_attach_args *fa = (struct fdt_attach_args *)aux; + + if (fa->fa_node == 0) + return (0); + + if (!OF_is_compatible(fa->fa_node, "simple-bus")) + return (0); + + return (1); +} + +void +simplebus_attach(struct device *parent, struct device *self, void *aux) +{ + struct simplebus_softc *sc = (struct simplebus_softc *)self; + struct fdt_attach_args *fa = (struct fdt_attach_args *)aux; + char name[32]; + int node; + + sc->sc_node = fa->fa_node; + sc->sc_iot = fa->fa_iot; + sc->sc_dmat = fa->fa_dmat; + sc->sc_acells = OF_getpropint(sc->sc_node, "#address-cells", + fa->fa_acells); + sc->sc_scells = OF_getpropint(sc->sc_node, "#size-cells", + fa->fa_scells); + sc->sc_pacells = fa->fa_acells; + sc->sc_pscells = fa->fa_scells; + + if (OF_getprop(sc->sc_node, "name", name, sizeof(name)) > 0) { + name[sizeof(name) - 1] = 0; + printf(": \"%s\"", name); + } + + printf("\n"); + + memcpy(&sc->sc_bus, sc->sc_iot, sizeof(sc->sc_bus)); + sc->sc_bus.bus_private = sc; + sc->sc_bus._space_map = simplebus_bs_map; + + sc->sc_rangeslen = OF_getproplen(sc->sc_node, "ranges"); + if (sc->sc_rangeslen > 0 && + (sc->sc_rangeslen % sizeof(uint32_t)) == 0) { + sc->sc_ranges = malloc(sc->sc_rangeslen, M_TEMP, M_WAITOK); + OF_getpropintarray(sc->sc_node, "ranges", sc->sc_ranges, + sc->sc_rangeslen); + } + + memcpy(&sc->sc_dma, sc->sc_dmat, sizeof(sc->sc_dma)); + sc->sc_dma._dmamap_load_buffer = simplebus_dmamap_load_buffer; + sc->sc_dma._cookie = sc; + sc->sc_dma._low = 0; + sc->sc_dma._high = (paddr_t)-1; + + sc->sc_dmarangeslen = OF_getproplen(sc->sc_node, "dma-ranges"); + if (sc->sc_dmarangeslen > 0 && + (sc->sc_dmarangeslen % sizeof(uint32_t)) == 0) { + sc->sc_dmaranges = malloc(sc->sc_dmarangeslen, + M_TEMP, M_WAITOK); + OF_getpropintarray(sc->sc_node, "dma-ranges", + sc->sc_dmaranges, sc->sc_dmarangeslen); + + simplebus_check_dma(sc); + } + + /* Scan the whole tree. */ + sc->sc_early = 1; + for (node = OF_child(sc->sc_node); node; node = OF_peer(node)) + simplebus_attach_node(self, node); + + sc->sc_early = 0; + for (node = OF_child(sc->sc_node); node; node = OF_peer(node)) + simplebus_attach_node(self, node); +} + +int +simplebus_submatch(struct device *self, void *match, void *aux) +{ + struct simplebus_softc *sc = (struct simplebus_softc *)self; + struct cfdata *cf = match; + + if (cf->cf_loc[0] == sc->sc_early) + return (*cf->cf_attach->ca_match)(self, match, aux); + return 0; +} + +int +simplebus_print(void *aux, const char *pnp) +{ + struct fdt_attach_args *fa = aux; + char name[32]; + + if (!pnp) + return (QUIET); + + if (OF_getprop(fa->fa_node, "name", name, sizeof(name)) > 0) { + name[sizeof(name) - 1] = 0; + printf("\"%s\"", name); + } else + printf("node %u", fa->fa_node); + + printf(" at %s", pnp); + + return (UNCONF); +} + +/* + * Look for a driver that wants to be attached to this node. + */ +void +simplebus_attach_node(struct device *self, int node) +{ + struct simplebus_softc *sc = (struct simplebus_softc *)self; + struct fdt_attach_args fa; + int i, len, line; + uint32_t *cell, *reg; + struct device *child; + + if (OF_getproplen(node, "compatible") <= 0) + return; + + if (!OF_is_enabled(node)) + return; + + /* Skip if already attached early. */ + for (i = 0; i < nitems(sc->sc_early_nodes); i++) { + if (sc->sc_early_nodes[i] == node) + return; + if (sc->sc_early_nodes[i] == 0) + break; + } + + memset(&fa, 0, sizeof(fa)); + fa.fa_name = ""; + fa.fa_node = node; + fa.fa_iot = &sc->sc_bus; + fa.fa_dmat = &sc->sc_dma; + fa.fa_acells = sc->sc_acells; + fa.fa_scells = sc->sc_scells; + + len = OF_getproplen(node, "reg"); + line = (sc->sc_acells + sc->sc_scells) * sizeof(uint32_t); + if (len > 0 && line > 0 && (len % line) == 0) { + reg = malloc(len, M_TEMP, M_WAITOK); + OF_getpropintarray(node, "reg", reg, len); + + fa.fa_reg = malloc((len / line) * sizeof(struct fdt_reg), + M_DEVBUF, M_WAITOK | M_ZERO); + fa.fa_nreg = (len / line); + + for (i = 0, cell = reg; i < len / line; i++) { + if (sc->sc_acells >= 1) + fa.fa_reg[i].addr = cell[0]; + if (sc->sc_acells == 2) { + fa.fa_reg[i].addr <<= 32; + fa.fa_reg[i].addr |= cell[1]; + } + cell += sc->sc_acells; + if (sc->sc_scells >= 1) + fa.fa_reg[i].size = cell[0]; + if (sc->sc_scells == 2) { + fa.fa_reg[i].size <<= 32; + fa.fa_reg[i].size |= cell[1]; + } + cell += sc->sc_scells; + } + + free(reg, M_TEMP, len); + } + + len = OF_getproplen(node, "interrupts"); + if (len > 0 && (len % sizeof(uint32_t)) == 0) { + fa.fa_intr = malloc(len, M_DEVBUF, M_WAITOK); + fa.fa_nintr = len / sizeof(uint32_t); + + OF_getpropintarray(node, "interrupts", fa.fa_intr, len); + } + + if (OF_getpropbool(node, "dma-noncoherent")) { + fa.fa_dmat = malloc(sizeof(sc->sc_dma), + M_DEVBUF, M_WAITOK | M_ZERO); + memcpy(fa.fa_dmat, &sc->sc_dma, sizeof(sc->sc_dma)); + fa.fa_dmat->_flags &= ~BUS_DMA_COHERENT; + } else if (OF_getpropbool(node, "dma-coherent")) { + fa.fa_dmat = malloc(sizeof(sc->sc_dma), + M_DEVBUF, M_WAITOK | M_ZERO); + memcpy(fa.fa_dmat, &sc->sc_dma, sizeof(sc->sc_dma)); + fa.fa_dmat->_flags |= BUS_DMA_COHERENT; + } + +#ifdef DEBUG_AUTOCONF + if (OF_getprop(fa.fa_node, "name", buf, sizeof(buf)) > 0) + printf("\ncurrent parent: %s, current node: %d-%s\n", self->dv_xname, fa.fa_node, buf); +#endif + + child = config_found_sm(self, &fa, sc->sc_early ? NULL : + simplebus_print, simplebus_submatch); + + /* Record nodes that we attach early. */ + if (child && sc->sc_early) { + for (i = 0; i < nitems(sc->sc_early_nodes); i++) { + if (sc->sc_early_nodes[i] != 0) + continue; + sc->sc_early_nodes[i] = node; + break; + } + } + + free(fa.fa_reg, M_DEVBUF, fa.fa_nreg * sizeof(struct fdt_reg)); + free(fa.fa_intr, M_DEVBUF, fa.fa_nintr * sizeof(uint32_t)); +} + +/* + * Translate memory address if needed. + */ +int +simplebus_bs_map(bus_space_tag_t t, bus_addr_t bpa, bus_size_t size, + int flag, bus_space_handle_t *bshp) +{ + struct simplebus_softc *sc = t->bus_private; + uint64_t addr, rfrom, rto, rsize; + uint32_t *range; + int parent, rlen, rone; + + addr = bpa; + parent = OF_parent(sc->sc_node); + if (parent == 0) + return bus_space_map(sc->sc_iot, addr, size, flag, bshp); + + if (sc->sc_rangeslen < 0) + return EINVAL; + if (sc->sc_rangeslen == 0) + return bus_space_map(sc->sc_iot, addr, size, flag, bshp); + + rlen = sc->sc_rangeslen / sizeof(uint32_t); + rone = sc->sc_pacells + sc->sc_acells + sc->sc_scells; + + /* For each range. */ + for (range = sc->sc_ranges; rlen >= rone; rlen -= rone, range += rone) { + /* Extract from and size, so we can see if we fit. */ + rfrom = range[0]; + if (sc->sc_acells == 2) + rfrom = (rfrom << 32) + range[1]; + rsize = range[sc->sc_acells + sc->sc_pacells]; + if (sc->sc_scells == 2) + rsize = (rsize << 32) + + range[sc->sc_acells + sc->sc_pacells + 1]; + + /* Try next, if we're not in the range. */ + if (addr < rfrom || (addr + size) > (rfrom + rsize)) + continue; + + /* All good, extract to address and translate. */ + rto = range[sc->sc_acells]; + if (sc->sc_pacells == 2) + rto = (rto << 32) + range[sc->sc_acells + 1]; + + addr -= rfrom; + addr += rto; + + return bus_space_map(sc->sc_iot, addr, size, flag, bshp); + } + + return ESRCH; +} + +int +simplebus_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map, void *buf, + bus_size_t buflen, struct proc *p, int flags, paddr_t *lastaddrp, + int *segp, int *usedp, int *lastbouncep, int first) +{ + struct simplebus_softc *sc = t->_cookie; + int rlen, rone, seg; + int firstseg = *segp; + int error; + + error = sc->sc_dmat->_dmamap_load_buffer(sc->sc_dmat, map, buf, buflen, + p, flags, lastaddrp, segp, usedp, lastbouncep, first); + if (error) + return error; + + if (sc->sc_dmaranges == NULL) + return 0; + + rlen = sc->sc_dmarangeslen / sizeof(uint32_t); + rone = sc->sc_pacells + sc->sc_acells + sc->sc_scells; + + /* For each segment. */ + for (seg = firstseg; seg <= *segp; seg++) { + uint64_t addr, size, rfrom, rto, rsize; + uint32_t *range; + + addr = map->dm_segs[seg].ds_addr; + size = map->dm_segs[seg].ds_len; + + /* For each range. */ + for (range = sc->sc_dmaranges; rlen >= rone; + rlen -= rone, range += rone) { + /* Extract from and size, so we can see if we fit. */ + rfrom = range[sc->sc_acells]; + if (sc->sc_pacells == 2) + rfrom = (rfrom << 32) + range[sc->sc_acells + 1]; + + rsize = range[sc->sc_acells + sc->sc_pacells]; + if (sc->sc_scells == 2) + rsize = (rsize << 32) + + range[sc->sc_acells + sc->sc_pacells + 1]; + + /* Try next, if we're not in the range. */ + if (addr < rfrom || (addr + size) > (rfrom + rsize)) + continue; + + /* All good, extract to address and translate. */ + rto = range[0]; + if (sc->sc_acells == 2) + rto = (rto << 32) + range[1]; + + map->dm_segs[seg].ds_addr -= rfrom; + map->dm_segs[seg].ds_addr += rto; + break; + } + } + + return 0; +} + +void +simplebus_check_dma(struct simplebus_softc *sc) +{ + struct uvm_constraint_range constraint; + uint64_t raddr, rsize; + uint64_t low = UINT64_MAX, high = 0; + uint32_t *range; + int rlen, rone; + + /* + * Find the lowest range of physical memory that is + * DMA-reachable through this bus. This may not cover all + * DMA-reachable memory, but hopefully it will be enough for a + * usable system. + */ + + rlen = sc->sc_dmarangeslen / sizeof(uint32_t); + rone = sc->sc_pacells + sc->sc_acells + sc->sc_scells; + + for (range = sc->sc_dmaranges; rlen >= rone; + rlen -= rone, range += rone) { + /* Extract parent address and size. */ + raddr = range[sc->sc_acells]; + if (sc->sc_pacells == 2) + raddr = (raddr << 32) + range[sc->sc_acells + 1]; + + rsize = range[sc->sc_acells + sc->sc_pacells]; + if (sc->sc_scells == 2) + rsize = (rsize << 32) + + range[sc->sc_acells + sc->sc_pacells + 1]; + + if (OF_translate(OF_parent(sc->sc_node), "dma-ranges", + &raddr, &rsize)) + continue; + + if (raddr < low) { + low = raddr; + high = raddr + rsize - 1; + } + } + + if (high > 0) { + constraint.ucr_low = high + 1; + constraint.ucr_high = no_constraint.ucr_high; + if (uvm_pagecount(&constraint) > 0) + sc->sc_dma._high = high; + } + + if (low > 0) { + constraint.ucr_low = no_constraint.ucr_low; + constraint.ucr_high = low - 1; + if (uvm_pagecount(&constraint) > 0) + sc->sc_dma._low = low; + } +} diff --git sys/arch/loongarch64/dev/smbios.c sys/arch/loongarch64/dev/smbios.c new file mode 100644 index 00000000000..9bde1b5881a --- /dev/null +++ sys/arch/loongarch64/dev/smbios.c @@ -0,0 +1,473 @@ +/* $OpenBSD: smbios.c,v 1.8 2022/10/29 20:35:50 kettenis Exp $ */ +/* + * Copyright (c) 2006 Gordon Willem Klok + * Copyright (c) 2019 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +struct smbios_entry smbios_entry; + +const char *smbios_uninfo[] = { + "System", + "Not ", + "To be", + "SYS-" +}; + +char smbios_bios_date[64]; +char smbios_board_vendor[64]; +char smbios_board_prod[64]; +char smbios_board_serial[64]; + +void smbios_info(char *); +char *fixstring(char *); + +struct smbios_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; +}; + +int smbios_match(struct device *, void *, void *); +void smbios_attach(struct device *, struct device *, void *); + +const struct cfattach smbios_ca = { + sizeof(struct device), smbios_match, smbios_attach +}; + +struct cfdriver smbios_cd = { + NULL, "smbios", DV_DULL +}; + +int +smbios_match(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *faa = aux; + + return (strcmp(faa->fa_name, "smbios") == 0); +} + +void +smbios_attach(struct device *parent, struct device *self, void *aux) +{ + struct smbios_softc *sc = (struct smbios_softc *)self; + struct fdt_attach_args *faa = aux; + struct smbios_struct_bios *sb; + struct smbtable bios; + char scratch[64]; + char sig[5]; + char *sminfop; + bus_addr_t addr; + bus_size_t size; + bus_space_handle_t ioh; + + sc->sc_iot = faa->fa_iot; + if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, sizeof(sig), + BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE, &ioh)) { + printf(": can't map SMBIOS entry point structure\n"); + return; + } + bus_space_read_region_1(sc->sc_iot, ioh, 0, sig, sizeof(sig)); + bus_space_unmap(sc->sc_iot, ioh, sizeof(sig)); + + if (strncmp(sig, "_SM_", 4) == 0) { + struct smbhdr *hdr; + uint8_t *p, checksum = 0; + int i; + + if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, sizeof(*hdr), + BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE, &ioh)) { + printf(": can't map SMBIOS entry point structure\n"); + return; + } + + hdr = bus_space_vaddr(sc->sc_iot, ioh); + if (hdr->len != sizeof(*hdr)) { + bus_space_unmap(sc->sc_iot, ioh, sizeof(*hdr)); + printf("\n"); + return; + } + for (i = 0, p = (uint8_t *)hdr; i < hdr->len; i++) + checksum += p[i]; + if (checksum != 0) { + bus_space_unmap(sc->sc_iot, ioh, sizeof(*hdr)); + printf("\n"); + return; + } + + printf(": SMBIOS %d.%d", hdr->majrev, hdr->minrev); + + smbios_entry.len = hdr->size; + smbios_entry.mjr = hdr->majrev; + smbios_entry.min = hdr->minrev; + smbios_entry.count = hdr->count; + + addr = hdr->addr; + size = hdr->size; + bus_space_unmap(sc->sc_iot, ioh, sizeof(*hdr)); + } else if (strncmp(sig, "_SM3_", 5) == 0) { + struct smb3hdr *hdr; + uint8_t *p, checksum = 0; + int i; + + if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, sizeof(*hdr), + BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE, &ioh)) { + printf(": can't map SMBIOS entry point structure\n"); + return; + } + + hdr = bus_space_vaddr(sc->sc_iot, ioh); + if (hdr->len != sizeof(*hdr) || hdr->epr != 0x01) { + bus_space_unmap(sc->sc_iot, ioh, sizeof(*hdr)); + printf("\n"); + return; + } + for (i = 0, p = (uint8_t *)hdr; i < hdr->len; i++) + checksum += p[i]; + if (checksum != 0) { + bus_space_unmap(sc->sc_iot, ioh, sizeof(*hdr)); + printf("\n"); + return; + } + + printf(": SMBIOS %d.%d.%d", hdr->majrev, hdr->minrev, + hdr->docrev); + + smbios_entry.len = hdr->size; + smbios_entry.mjr = hdr->majrev; + smbios_entry.min = hdr->minrev; + smbios_entry.count = -1; + + addr = hdr->addr; + size = hdr->size; + bus_space_unmap(sc->sc_iot, ioh, sizeof(*hdr)); + } else { + printf(": unsupported SMBIOS entry point\n"); + return; + } + + if (bus_space_map(sc->sc_iot, addr, size, + BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE, &ioh)) { + printf(": can't map SMBIOS structure table\n"); + return; + } + smbios_entry.addr = bus_space_vaddr(sc->sc_iot, ioh); + + bios.cookie = 0; + if (smbios_find_table(SMBIOS_TYPE_BIOS, &bios)) { + sb = bios.tblhdr; + printf("\n%s:", sc->sc_dev.dv_xname); + if ((smbios_get_string(&bios, sb->vendor, + scratch, sizeof(scratch))) != NULL) + printf(" vendor %s", + fixstring(scratch)); + if ((smbios_get_string(&bios, sb->version, + scratch, sizeof(scratch))) != NULL) + printf(" version \"%s\"", + fixstring(scratch)); + if ((smbios_get_string(&bios, sb->release, + scratch, sizeof(scratch))) != NULL) { + sminfop = fixstring(scratch); + if (sminfop != NULL) { + strlcpy(smbios_bios_date, + sminfop, + sizeof(smbios_bios_date)); + printf(" date %s", sminfop); + } + } + + smbios_info(sc->sc_dev.dv_xname); + } + + bus_space_unmap(sc->sc_iot, ioh, size); + + printf("\n"); + return; +} + +/* + * smbios_find_table() takes a caller supplied smbios struct type and + * a pointer to a handle (struct smbtable) returning one if the structure + * is successfully located and zero otherwise. Callers should take care + * to initialize the cookie field of the smbtable structure to zero before + * the first invocation of this function. + * Multiple tables of the same type can be located by repeatedly calling + * smbios_find_table with the same arguments. + */ +int +smbios_find_table(uint8_t type, struct smbtable *st) +{ + uint8_t *va, *end; + struct smbtblhdr *hdr; + int ret = 0, tcount = 1; + + va = smbios_entry.addr; + end = va + smbios_entry.len; + + /* + * The cookie field of the smtable structure is used to locate + * multiple instances of a table of an arbitrary type. Following the + * successful location of a table, the type is encoded as bits 0:7 of + * the cookie value, the offset in terms of the number of structures + * preceding that referenced by the handle is encoded in bits 15:31. + */ + if ((st->cookie & 0xfff) == type && st->cookie >> 16) { + if ((uint8_t *)st->hdr >= va && (uint8_t *)st->hdr < end) { + hdr = st->hdr; + if (hdr->type == type) { + va = (uint8_t *)hdr + hdr->size; + for (; va + 1 < end; va++) + if (*va == 0 && *(va + 1) == 0) + break; + va += 2; + tcount = st->cookie >> 16; + } + } + } + for (; va + sizeof(struct smbtblhdr) < end && + tcount <= smbios_entry.count; tcount++) { + hdr = (struct smbtblhdr *)va; + if (hdr->type == type) { + ret = 1; + st->hdr = hdr; + st->tblhdr = va + sizeof(struct smbtblhdr); + st->cookie = (tcount + 1) << 16 | type; + break; + } + if (hdr->type == SMBIOS_TYPE_EOT) + break; + va += hdr->size; + for (; va + 1 < end; va++) + if (*va == 0 && *(va + 1) == 0) + break; + va += 2; + } + return ret; +} + +char * +smbios_get_string(struct smbtable *st, uint8_t indx, char *dest, size_t len) +{ + uint8_t *va, *end; + char *ret = NULL; + int i; + + va = (uint8_t *)st->hdr + st->hdr->size; + end = smbios_entry.addr + smbios_entry.len; + for (i = 1; va < end && i < indx && *va; i++) + while (*va++) + ; + if (i == indx) { + if (va + len < end) { + ret = dest; + memcpy(ret, va, len); + ret[len - 1] = '\0'; + } + } + + return ret; +} + +char * +fixstring(char *s) +{ + char *p, *e; + int i; + + for (i = 0; i < nitems(smbios_uninfo); i++) + if ((strncasecmp(s, smbios_uninfo[i], + strlen(smbios_uninfo[i]))) == 0) + return NULL; + /* + * Remove leading and trailing whitespace + */ + for (p = s; *p == ' '; p++) + ; + /* + * Special case entire string is whitespace + */ + if (p == s + strlen(s)) + return NULL; + for (e = s + strlen(s) - 1; e > s && *e == ' '; e--) + ; + if (p > s || e < s + strlen(s) - 1) { + memmove(s, p, e - p + 1); + s[e - p + 1] = '\0'; + } + + return s; +} + +void +smbios_info(char *str) +{ + char *sminfop, sminfo[64]; + struct smbtable stbl, btbl; + struct smbios_sys *sys; + struct smbios_board *board; + int i, infolen, uuidf, havebb; + char *p; + + if (smbios_entry.mjr < 2) + return; + /* + * According to the spec the system table among others is required, + * if it is not we do not bother with this smbios implementation. + */ + stbl.cookie = btbl.cookie = 0; + if (!smbios_find_table(SMBIOS_TYPE_SYSTEM, &stbl)) + return; + havebb = smbios_find_table(SMBIOS_TYPE_BASEBOARD, &btbl); + + sys = (struct smbios_sys *)stbl.tblhdr; + if (havebb) { + board = (struct smbios_board *)btbl.tblhdr; + + sminfop = NULL; + if ((p = smbios_get_string(&btbl, board->vendor, + sminfo, sizeof(sminfo))) != NULL) + sminfop = fixstring(p); + if (sminfop) + strlcpy(smbios_board_vendor, sminfop, + sizeof(smbios_board_vendor)); + + sminfop = NULL; + if ((p = smbios_get_string(&btbl, board->product, + sminfo, sizeof(sminfo))) != NULL) + sminfop = fixstring(p); + if (sminfop) + strlcpy(smbios_board_prod, sminfop, + sizeof(smbios_board_prod)); + + sminfop = NULL; + if ((p = smbios_get_string(&btbl, board->serial, + sminfo, sizeof(sminfo))) != NULL) + sminfop = fixstring(p); + if (sminfop) + strlcpy(smbios_board_serial, sminfop, + sizeof(smbios_board_serial)); + } + /* + * Some smbios implementations have no system vendor or + * product strings, some have very uninformative data which is + * harder to work around and we must rely upon various + * heuristics to detect this. In both cases we attempt to fall + * back on the base board information in the perhaps naive + * belief that motherboard vendors will supply this + * information. + */ + sminfop = NULL; + if ((p = smbios_get_string(&stbl, sys->vendor, sminfo, + sizeof(sminfo))) != NULL) + sminfop = fixstring(p); + if (sminfop == NULL) { + if (havebb) { + if ((p = smbios_get_string(&btbl, board->vendor, + sminfo, sizeof(sminfo))) != NULL) + sminfop = fixstring(p); + } + } + if (sminfop) { + infolen = strlen(sminfop) + 1; + hw_vendor = malloc(infolen, M_DEVBUF, M_NOWAIT); + if (hw_vendor) + strlcpy(hw_vendor, sminfop, infolen); + sminfop = NULL; + } + if ((p = smbios_get_string(&stbl, sys->product, sminfo, + sizeof(sminfo))) != NULL) + sminfop = fixstring(p); + if (sminfop == NULL) { + if (havebb) { + if ((p = smbios_get_string(&btbl, board->product, + sminfo, sizeof(sminfo))) != NULL) + sminfop = fixstring(p); + } + } + if (sminfop) { + infolen = strlen(sminfop) + 1; + hw_prod = malloc(infolen, M_DEVBUF, M_NOWAIT); + if (hw_prod) + strlcpy(hw_prod, sminfop, infolen); + sminfop = NULL; + } + if (hw_vendor != NULL && hw_prod != NULL) + printf("\n%s: %s %s", str, hw_vendor, hw_prod); + if ((p = smbios_get_string(&stbl, sys->version, sminfo, + sizeof(sminfo))) != NULL) + sminfop = fixstring(p); + if (sminfop) { + infolen = strlen(sminfop) + 1; + hw_ver = malloc(infolen, M_DEVBUF, M_NOWAIT); + if (hw_ver) + strlcpy(hw_ver, sminfop, infolen); + sminfop = NULL; + } + if ((p = smbios_get_string(&stbl, sys->serial, sminfo, + sizeof(sminfo))) != NULL) + sminfop = fixstring(p); + if (sminfop) { + infolen = strlen(sminfop) + 1; + for (i = 0; i < infolen - 1; i++) + enqueue_randomness(sminfop[i]); + hw_serial = malloc(infolen, M_DEVBUF, M_NOWAIT); + if (hw_serial) + strlcpy(hw_serial, sminfop, infolen); + } + if (smbios_entry.mjr > 2 || (smbios_entry.mjr == 2 && + smbios_entry.min >= 1)) { + /* + * If the uuid value is all 0xff the uuid is present but not + * set, if its all 0 then the uuid isn't present at all. + */ + uuidf = SMBIOS_UUID_NPRESENT|SMBIOS_UUID_NSET; + for (i = 0; i < sizeof(sys->uuid); i++) { + if (sys->uuid[i] != 0xff) + uuidf &= ~SMBIOS_UUID_NSET; + if (sys->uuid[i] != 0) + uuidf &= ~SMBIOS_UUID_NPRESENT; + } + + if (uuidf & SMBIOS_UUID_NPRESENT) + hw_uuid = NULL; + else if (uuidf & SMBIOS_UUID_NSET) + hw_uuid = "Not Set"; + else { + for (i = 0; i < sizeof(sys->uuid); i++) + enqueue_randomness(sys->uuid[i]); + hw_uuid = malloc(SMBIOS_UUID_REPLEN, M_DEVBUF, + M_NOWAIT); + if (hw_uuid) { + snprintf(hw_uuid, SMBIOS_UUID_REPLEN, + SMBIOS_UUID_REP, + sys->uuid[0], sys->uuid[1], sys->uuid[2], + sys->uuid[3], sys->uuid[4], sys->uuid[5], + sys->uuid[6], sys->uuid[7], sys->uuid[8], + sys->uuid[9], sys->uuid[10], sys->uuid[11], + sys->uuid[12], sys->uuid[13], sys->uuid[14], + sys->uuid[15]); + } + } + } +} diff --git sys/arch/loongarch64/dev/sxitimer.c sys/arch/loongarch64/dev/sxitimer.c new file mode 100644 index 00000000000..4bd996fd973 --- /dev/null +++ sys/arch/loongarch64/dev/sxitimer.c @@ -0,0 +1,177 @@ +/* $OpenBSD: sxitimer.c,v 1.2 2024/10/17 01:57:18 jsg Exp $ */ +/* + * Copyright (c) 2024 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +/* Registers */ +#define TMR_IRQ_EN 0x0000 +#define TMR1_IRQ_EN (1 << 1) +#define TMR0_IRQ_EN (1 << 0) +#define TMR_IRQ_STA 0x0004 +#define TMR1_IRQ_PEND (1 << 1) +#define TMR0_IRQ_PEND (1 << 0) +#define TMR0_CTRL 0x0010 +#define TMR0_MODE_SINGLE (1 << 7) +#define TMR0_CLK_PRES_1 (0 << 4) +#define TMR0_CLK_SRC_OSC24M (1 << 2) +#define TMR0_RELOAD (1 << 1) +#define TMR0_EN (1 << 0) +#define TMR0_INTV_VALUE 0x0014 + +#define HREAD4(sc, reg) \ + (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) +#define HWRITE4(sc, reg, val) \ + bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) + +struct sxitimer_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + + uint32_t sc_ticks_per_second; + uint64_t sc_nsec_cycle_ratio; + uint64_t sc_nsec_max; + void *sc_ih; +}; + +int sxitimer_match(struct device *, void *, void *); +void sxitimer_attach(struct device *, struct device *, void *); + +const struct cfattach sxitimer_ca = { + sizeof (struct sxitimer_softc), sxitimer_match, sxitimer_attach +}; + +struct cfdriver sxitimer_cd = { + NULL, "sxitimer", DV_DULL +}; + +void sxitimer_startclock(void); +int sxitimer_intr(void *); +void sxitimer_rearm(void *, uint64_t); +void sxitimer_trigger(void *); + +struct intrclock sxitimer_intrclock = { + .ic_rearm = sxitimer_rearm, + .ic_trigger = sxitimer_trigger +}; + +int +sxitimer_match(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *faa = aux; + + return OF_is_compatible(faa->fa_node, "allwinner,sun20i-d1-timer"); +} + +void +sxitimer_attach(struct device *parent, struct device *self, void *aux) +{ + struct sxitimer_softc *sc = (struct sxitimer_softc *)self; + struct fdt_attach_args *faa = aux; + + if (faa->fa_nreg < 1) { + printf(": no registers\n"); + return; + } + + sc->sc_iot = faa->fa_iot; + if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, + faa->fa_reg[0].size, 0, &sc->sc_ioh)) { + printf(": can't map registers\n"); + return; + } + + HWRITE4(sc, TMR_IRQ_EN, 0); + + sc->sc_ticks_per_second = clock_get_frequency(faa->fa_node, NULL); + sc->sc_nsec_cycle_ratio = + sc->sc_ticks_per_second * (1ULL << 32) / 1000000000; + sc->sc_nsec_max = UINT64_MAX / sc->sc_nsec_cycle_ratio; + + sxitimer_intrclock.ic_cookie = sc; + cpu_startclock_fcn = sxitimer_startclock; + + sc->sc_ih = fdt_intr_establish_idx(faa->fa_node, 0, IPL_CLOCK, + sxitimer_intr, NULL, sc->sc_dev.dv_xname); + if (sc->sc_ih == NULL) { + printf("can't establish interrupt\n"); + return; + } + + HWRITE4(sc, TMR0_INTV_VALUE, 0); + HWRITE4(sc, TMR0_CTRL, TMR0_MODE_SINGLE | TMR0_CLK_PRES_1 | + TMR0_CLK_SRC_OSC24M | TMR0_RELOAD | TMR0_EN); + HWRITE4(sc, TMR_IRQ_STA, TMR0_IRQ_PEND); + HWRITE4(sc, TMR_IRQ_EN, TMR0_IRQ_EN); + + printf(": %u kHz\n", sc->sc_ticks_per_second / 1000); +} + +void +sxitimer_startclock(void) +{ + clockintr_cpu_init(&sxitimer_intrclock); + clockintr_trigger(); +} + +int +sxitimer_intr(void *frame) +{ + struct sxitimer_softc *sc = sxitimer_intrclock.ic_cookie; + + HWRITE4(sc, TMR_IRQ_STA, TMR0_IRQ_PEND); + return clockintr_dispatch(frame); +} + +void +sxitimer_rearm(void *cookie, uint64_t nsecs) +{ + struct sxitimer_softc *sc = cookie; + uint32_t cycles; + + if (nsecs > sc->sc_nsec_max) + nsecs = sc->sc_nsec_max; + cycles = (nsecs * sc->sc_nsec_cycle_ratio) >> 32; + if (cycles > UINT32_MAX) + cycles = UINT32_MAX; + if (cycles < 1) + cycles = 1; + HWRITE4(sc, TMR0_INTV_VALUE, cycles); + HWRITE4(sc, TMR0_CTRL, TMR0_MODE_SINGLE | TMR0_CLK_PRES_1 | + TMR0_CLK_SRC_OSC24M | TMR0_RELOAD | TMR0_EN); +} + +void +sxitimer_trigger(void *cookie) +{ + struct sxitimer_softc *sc = cookie; + + HWRITE4(sc, TMR0_INTV_VALUE, 1); + HWRITE4(sc, TMR0_CTRL, TMR0_MODE_SINGLE | TMR0_CLK_PRES_1 | + TMR0_CLK_SRC_OSC24M | TMR0_RELOAD | TMR0_EN); +} diff --git sys/arch/loongarch64/include/_float.h sys/arch/loongarch64/include/_float.h new file mode 100644 index 00000000000..c987f2e3363 --- /dev/null +++ sys/arch/loongarch64/include/_float.h @@ -0,0 +1,96 @@ +/* $OpenBSD: _float.h,v 1.1 2021/04/23 02:42:16 drahn Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MACHINE__FLOAT_H_ +#define _MACHINE__FLOAT_H_ + +#define __FLT_RADIX 2 /* b */ +#define __FLT_ROUNDS __flt_rounds() +#define __FLT_EVAL_METHOD 0 /* no promotions */ + +#define __FLT_MANT_DIG 24 /* p */ +#define __FLT_EPSILON 1.19209290E-7F /* b**(1-p) */ +#define __FLT_DIG 6 /* floor((p-1)*log10(b))+(b == 10) */ +#define __FLT_MIN_EXP (-125) /* emin */ +#define __FLT_MIN 1.17549435E-38F /* b**(emin-1) */ +#define __FLT_MIN_10_EXP (-37) /* ceil(log10(b**(emin-1))) */ +#define __FLT_MAX_EXP 128 /* emax */ +#define __FLT_MAX 3.40282347E+38F /* (1-b**(-p))*b**emax */ +#define __FLT_MAX_10_EXP 38 /* floor(log10((1-b**(-p))*b**emax)) */ + +#define __DBL_MANT_DIG 53 +#define __DBL_EPSILON 2.2204460492503131E-16 +#define __DBL_DIG 15 +#define __DBL_MIN_EXP (-1021) +#define __DBL_MIN 2.2250738585072014E-308 +#define __DBL_MIN_10_EXP (-307) +#define __DBL_MAX_EXP 1024 +#define __DBL_MAX 1.7976931348623157E+308 +#define __DBL_MAX_10_EXP 308 + +#ifdef __LDBL_MANT_DIG__ +#define __LDBL_MANT_DIG __LDBL_MANT_DIG__ +#define __LDBL_EPSILON __LDBL_EPSILON__ +#define __LDBL_DIG __LDBL_DIG__ +#define __LDBL_MIN_EXP __LDBL_MIN_EXP__ +#define __LDBL_MIN __LDBL_MIN__ +#define __LDBL_MIN_10_EXP __LDBL_MIN_10_EXP__ +#define __LDBL_MAX_EXP __LDBL_MAX_EXP__ +#define __LDBL_MAX __LDBL_MAX__ +#define __LDBL_MAX_10_EXP __LDBL_MAX_10_EXP__ +#else +#define __LDBL_MANT_DIG DBL_MANT_DIG +#define __LDBL_EPSILON DBL_EPSILON +#define __LDBL_DIG DBL_DIG +#define __LDBL_MIN_EXP DBL_MIN_EXP +#define __LDBL_MIN DBL_MIN +#define __LDBL_MIN_10_EXP DBL_MIN_10_EXP +#define __LDBL_MAX_EXP DBL_MAX_EXP +#define __LDBL_MAX DBL_MAX +#define __LDBL_MAX_10_EXP DBL_MAX_10_EXP +#endif + +#define __DECIMAL_DIG 17 + +#endif /* _MACHINE__FLOAT_H_ */ diff --git sys/arch/loongarch64/include/_types.h sys/arch/loongarch64/include/_types.h new file mode 100644 index 00000000000..6a106c61ffc --- /dev/null +++ sys/arch/loongarch64/include/_types.h @@ -0,0 +1,146 @@ +/* $OpenBSD: _types.h,v 1.5 2023/07/02 19:02:28 cheloha Exp $ */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)types.h 8.3 (Berkeley) 1/5/94 + * @(#)ansi.h 8.2 (Berkeley) 1/4/94 + */ + +#ifndef _MACHINE__TYPES_H_ +#define _MACHINE__TYPES_H_ + +#if defined(_KERNEL) +typedef struct label_t { + long val[14]; +} label_t; +#endif + +/* + * _ALIGN(p) rounds p (pointer or byte index) up to a correctly-aligned + * value for all data types (int, long, ...). The result is an + * unsigned long and must be cast to any desired pointer type. + * + * _ALIGNED_POINTER is a boolean macro that checks whether an address + * is valid to fetch data elements of type t from on this architecture. + * This does not reflect the optimal alignment, just the possibility + * (within reasonable limits). + */ +#define _ALIGNBYTES (sizeof(long) - 1) +#define _STACKALIGNBYTES 15 +#define _ALIGN(p) (((unsigned long)(p) + _ALIGNBYTES) & ~_ALIGNBYTES) +#define _ALIGNED_POINTER(p,t) ((((unsigned long)(p)) & (sizeof(t) - 1)) == 0) +#define _MAX_PAGE_SHIFT 12 /* same as PAGE_SHIFT */ + +/* 7.18.1.1 Exact-width integer types */ +typedef signed char __int8_t; +typedef unsigned char __uint8_t; +typedef short __int16_t; +typedef unsigned short __uint16_t; +typedef int __int32_t; +typedef unsigned int __uint32_t; +/* LONGLONG */ +typedef long long __int64_t; +/* LONGLONG */ +typedef unsigned long long __uint64_t; + +/* 7.18.1.2 Minimum-width integer types */ +typedef __int8_t __int_least8_t; +typedef __uint8_t __uint_least8_t; +typedef __int16_t __int_least16_t; +typedef __uint16_t __uint_least16_t; +typedef __int32_t __int_least32_t; +typedef __uint32_t __uint_least32_t; +typedef __int64_t __int_least64_t; +typedef __uint64_t __uint_least64_t; + +/* 7.18.1.3 Fastest minimum-width integer types */ +typedef __int32_t __int_fast8_t; +typedef __uint32_t __uint_fast8_t; +typedef __int32_t __int_fast16_t; +typedef __uint32_t __uint_fast16_t; +typedef __int32_t __int_fast32_t; +typedef __uint32_t __uint_fast32_t; +typedef __int64_t __int_fast64_t; +typedef __uint64_t __uint_fast64_t; +#define __INT_FAST8_MIN INT32_MIN +#define __INT_FAST16_MIN INT32_MIN +#define __INT_FAST32_MIN INT32_MIN +#define __INT_FAST64_MIN INT64_MIN +#define __INT_FAST8_MAX INT32_MAX +#define __INT_FAST16_MAX INT32_MAX +#define __INT_FAST32_MAX INT32_MAX +#define __INT_FAST64_MAX INT64_MAX +#define __UINT_FAST8_MAX UINT32_MAX +#define __UINT_FAST16_MAX UINT32_MAX +#define __UINT_FAST32_MAX UINT32_MAX +#define __UINT_FAST64_MAX UINT64_MAX + +/* 7.18.1.4 Integer types capable of holding object pointers */ +typedef long __intptr_t; +typedef unsigned long __uintptr_t; + +/* 7.18.1.5 Greatest-width integer types */ +typedef __int64_t __intmax_t; +typedef __uint64_t __uintmax_t; + +/* Register size */ +typedef long __register_t; + +/* VM system types */ +typedef unsigned long __vaddr_t; +typedef unsigned long __paddr_t; +typedef unsigned long __vsize_t; +typedef unsigned long __psize_t; + +/* Standard system types */ +typedef double __double_t; +typedef float __float_t; +typedef long __ptrdiff_t; +typedef unsigned long __size_t; +typedef long __ssize_t; +#if defined(__GNUC__) && __GNUC__ >= 3 +typedef __builtin_va_list __va_list; +#else +typedef char * __va_list; +#endif + +/* Wide character support types */ +#ifndef __cplusplus +#ifdef __WCHAR_UNSIGNED__ +typedef unsigned int __wchar_t; +#else +typedef int __wchar_t; +#endif +#endif +typedef int __wint_t; +typedef int __rune_t; +typedef void * __wctrans_t; +typedef void * __wctype_t; + +#endif /* _MACHINE__TYPES_H_ */ diff --git sys/arch/loongarch64/include/acpiapm.h sys/arch/loongarch64/include/acpiapm.h new file mode 100644 index 00000000000..f9cefdcdfe9 --- /dev/null +++ sys/arch/loongarch64/include/acpiapm.h @@ -0,0 +1,23 @@ +/* $OpenBSD: acpiapm.h,v 1.1 2019/01/23 09:57:36 phessler Exp $ */ +/* + * Copyright (c) 2007 Ted Unangst + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +extern int (*acpiapm_open)(dev_t, int, int, struct proc *); +extern int (*acpiapm_close)(dev_t, int, int, struct proc *); +extern int (*acpiapm_ioctl)(dev_t, u_long, caddr_t, int, struct proc *); +extern int (*acpiapm_kqfilter)(dev_t, struct knote *); + diff --git sys/arch/loongarch64/include/apmvar.h sys/arch/loongarch64/include/apmvar.h new file mode 100644 index 00000000000..d45dffd1081 --- /dev/null +++ sys/arch/loongarch64/include/apmvar.h @@ -0,0 +1,122 @@ +/* $OpenBSD: apmvar.h,v 1.1 2023/11/06 20:59:26 jca Exp $ */ + +/* + * Copyright (c) 2001 Alexander Guy + * Copyright (c) 1995 John T. Kohl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef _MACHINE_APMVAR_H_ +#define _MACHINE_APMVAR_H_ + +#include + +/* Advanced Power Management (v1.0 and v1.1 specification) + * functions/defines/etc. + */ + +/* These definitions make up the heart of the user-land interface + * to the APM devices. + */ + +#define APM_AC_OFF 0x00 +#define APM_AC_ON 0x01 +#define APM_AC_BACKUP 0x02 +#define APM_AC_UNKNOWN 0xff +#define APM_BATT_HIGH 0x00 +#define APM_BATT_LOW 0x01 +#define APM_BATT_CRITICAL 0x02 +#define APM_BATT_CHARGING 0x03 +#define APM_BATT_UNKNOWN 0xff +#define APM_BATT_LIFE_UNKNOWN 0xff + +#define APM_NOEVENT 0x0000 +#define APM_STANDBY_REQ 0x0001 +#define APM_SUSPEND_REQ 0x0002 +#define APM_NORMAL_RESUME 0x0003 +#define APM_CRIT_RESUME 0x0004 /* suspend/resume happened + without us */ +#define APM_BATTERY_LOW 0x0005 +#define APM_POWER_CHANGE 0x0006 +#define APM_UPDATE_TIME 0x0007 +#define APM_CRIT_SUSPEND_REQ 0x0008 +#define APM_USER_STANDBY_REQ 0x0009 +#define APM_USER_SUSPEND_REQ 0x000A +#define APM_SYS_STANDBY_RESUME 0x000B +#define APM_CAPABILITY_CHANGE 0x000C /* apm v1.2 */ +#define APM_USER_HIBERNATE_REQ 0x000D +#define APM_EVENT_MASK 0xffff + +#define APM_EVENT_COMPOSE(t,i) ((((i) & 0x7fff) << 16)|((t) & APM_EVENT_MASK)) +#define APM_EVENT_TYPE(e) ((e) & APM_EVENT_MASK) +#define APM_EVENT_INDEX(e) ((e) >> 16) + +/* + * LP (Laptop Package) + * + * Copyright (C) 1994 by HOSOKAWA Tatsumi + * + * This software may be used, modified, copied, and distributed, in + * both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + */ + +#define APM_BATTERY_ABSENT 4 + +struct apm_power_info { + u_char battery_state; + u_char ac_state; + u_char battery_life; + u_char spare1; + u_int minutes_left; /* estimate */ + u_int spare2[6]; +}; + +struct apm_ctl { + u_int dev; + u_int mode; +}; + +#define APM_IOC_REJECT _IOW('A', 0, struct apm_event_info) /* reject request # */ +#define APM_IOC_STANDBY _IO('A', 1) /* put system into standby */ +#define APM_IOC_SUSPEND _IO('A', 2) /* put system into suspend */ +#define APM_IOC_GETPOWER _IOR('A', 3, struct apm_power_info) /* fetch battery state */ +#define APM_IOC_DEV_CTL _IOW('A', 5, struct apm_ctl) /* put device into mode */ +#define APM_IOC_PRN_CTL _IOW('A', 6, int ) /* driver power status msg */ +#define APM_PRINT_ON 0 /* driver power status displayed */ +#define APM_PRINT_OFF 1 /* driver power status not displayed */ +#define APM_PRINT_PCT 2 /* driver power status only displayed + if the percentage changes */ +#define APM_IOC_STANDBY_REQ _IO('A', 7) /* request standby */ +#define APM_IOC_SUSPEND_REQ _IO('A', 8) /* request suspend */ +#define APM_IOC_HIBERNATE _IO('A', 9) /* put system into hibernate */ + +#endif /* _MACHINE_APMVAR_H_ */ diff --git sys/arch/loongarch64/include/asm.h sys/arch/loongarch64/include/asm.h new file mode 100644 index 00000000000..0ba2b97f03f --- /dev/null +++ sys/arch/loongarch64/include/asm.h @@ -0,0 +1,125 @@ +/* $OpenBSD: asm.h,v 1.8 2022/12/06 00:08:38 jca Exp $ */ + +/* + * Copyright (c) 2020 Brian Bamsch + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)asm.h 5.5 (Berkeley) 5/7/91 + */ + +#ifndef _MACHINE_ASM_H_ +#define _MACHINE_ASM_H_ + +#define _C_LABEL(x) x +#define _ASM_LABEL(x) x + +#ifdef __STDC__ +# define __CONCAT(x,y) x ## y +# define __STRING(x) #x +#else +# define __CONCAT(x,y) x/**/y +# define __STRING(x) "x" +#endif + +#ifndef _ALIGN_TEXT +# define _ALIGN_TEXT .align 0 +#endif + +/* NB == No Binding: use .globl or .weak as necessary */ +#define _ENTRY_NB(x) \ + .text; .p2align 1; .type x,@function; x: +#define _ENTRY(x) .globl x; _ENTRY_NB(x) + +#if defined(PROF) || defined(GPROF) +// XXX Profiler Support +#define _PROF_PROLOGUE \ + addi.d $sp, $sp, -16; \ + st.d $ra, $sp, 8; \ + st.d $fp, $sp, 0; \ + move $fp, $sp; \ + bl __mcount; \ + ld.d $ra, $sp, 8; \ + ld.d $fp, $sp, 0; \ + addi.d $sp, $sp, 16; +#else +#define _PROF_PROLOGUE +#endif + +#if defined(_RET_PROTECTOR) +// XXX Retguard Support +#error RETGUARD not yet supported for loongarch64 +#else +#define RETGUARD_CALC_COOKIE(reg) +#define RETGUARD_LOAD_RANDOM(x, reg) +#define RETGUARD_SETUP(x, reg) +#define RETGUARD_CHECK(x, reg) +#define RETGUARD_PUSH(reg) +#define RETGUARD_POP(reg) +#define RETGUARD_SYMBOL(x) +#endif + +#define ENTRY(y) _ENTRY(y); _PROF_PROLOGUE +#define ENTRY_NP(y) _ENTRY(y) +#define ENTRY_NB(y) _ENTRY_NB(y); _PROF_PROLOGUE +#define ASENTRY(y) _ENTRY(y); _PROF_PROLOGUE +#define ASENTRY_NP(y) _ENTRY(y) +#define END(y) .size y, . - y +#define EENTRY(sym) .globl sym; sym: +#define EEND(sym) + +#ifdef __PIC__ +#define PIC_SYM(x,y) x(y) +#else +#define PIC_SYM(x,y) x +#endif + +#define STRONG_ALIAS(alias,sym) \ + .global alias; \ + alias = sym +#define WEAK_ALIAS(alias,sym) \ + .weak alias; \ + alias = sym + +#define SWAP_FAULT_HANDLER(handler, tmp0, tmp1) \ + ld.d tmp0, $tp, CI_CURPCB; /* Load the pcb */ \ + ld.d tmp1, tmp0, PCB_ONFAULT; /* Save old handler */ \ + st.d handler, tmp0, PCB_ONFAULT; /* Set the handler */ \ + move handler, tmp1 + +#define SET_FAULT_HANDLER(handler, pcb) \ + ld.d pcb, $tp, CI_CURPCB; /* Load the pcb */ \ + st.d handler, pcb, PCB_ONFAULT /* Set the handler */ + +#define ENTER_USER_ACCESS(tmp) \ + +#define EXIT_USER_ACCESS(tmp) \ + +#endif /* _MACHINE_ASM_H_ */ diff --git sys/arch/loongarch64/include/atomic.h sys/arch/loongarch64/include/atomic.h new file mode 100644 index 00000000000..fcaf369a454 --- /dev/null +++ sys/arch/loongarch64/include/atomic.h @@ -0,0 +1,50 @@ +/* $OpenBSD: atomic.h,v 1.5 2024/01/24 12:25:50 jca Exp $ */ + +/* Public Domain */ + +#ifndef _MACHINE_ATOMIC_H_ +#define _MACHINE_ATOMIC_H_ + +#define __membar(_f) do {__asm volatile(_f ::: "memory"); } while (0) + +#define membar_enter() __membar("dbar 7") +#define membar_exit() __membar("dbar 6") +#define membar_producer() __membar("dbar 5") +#define membar_consumer() __membar("dbar 4") +#define membar_sync() __membar("dbar 0") + +#if defined(_KERNEL) + +/* virtio needs MP membars even on SP kernels */ +#define virtio_membar_producer() __membar("dbar 5") +#define virtio_membar_consumer() __membar("dbar 4") +#define virtio_membar_sync() __membar("dbar 0") + +/* + * Set bits + * *p = *p | v + */ +static inline void +atomic_setbits_int(volatile unsigned int *p, unsigned int v) +{ + __asm volatile("amor.w $zero, %1, %0" + : + : "r" (p), "r" (v) + : "memory"); +} + +/* + * Clear bits + * *p = *p & (~v) + */ +static inline void +atomic_clearbits_int(volatile unsigned int *p, unsigned int v) +{ + __asm volatile("amand.w $zero, %1, %0" + : + : "r" (p), "r" (~v) + : "memory"); +} + +#endif /* defined(_KERNEL) */ +#endif /* _MACHINE_ATOMIC_H_ */ diff --git sys/arch/loongarch64/include/bootconfig.h sys/arch/loongarch64/include/bootconfig.h new file mode 100644 index 00000000000..994f1954a96 --- /dev/null +++ sys/arch/loongarch64/include/bootconfig.h @@ -0,0 +1,47 @@ +/* $OpenBSD: bootconfig.h,v 1.5 2024/04/06 18:33:54 kettenis Exp $ */ + +/*- + * Copyright (c) 2015-2017 Ruslan Bukin + * All rights reserved. + * + * Portions of this software were developed by SRI International and the + * University of Cambridge Computer Laboratory under DARPA/AFRL contract + * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. + * + * Portions of this software were developed by the University of Cambridge + * Computer Laboratory as part of the CTSRD Project, with support from the + * UK Higher Education Innovation Fund (HEIF). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MACHINE_BOOTCONFIG_H_ +#define _MACHINE_BOOTCONFIG_H_ + +struct loongarch_bootparams { + vaddr_t kern_l1pt; /* L1 page table for the kernel */ + paddr_t kern_phys; + vaddr_t kern_stack; + paddr_t dtbp_phys; /* Device tree blob physical addr */ +}; + +#endif /* _MACHINE_BOOTCONFIG_H_ */ diff --git sys/arch/loongarch64/include/bus.h sys/arch/loongarch64/include/bus.h new file mode 100644 index 00000000000..9e9d08405f6 --- /dev/null +++ sys/arch/loongarch64/include/bus.h @@ -0,0 +1,558 @@ +/* $OpenBSD: bus.h,v 1.10 2026/06/22 21:12:12 kettenis Exp $ */ + +/* + * Copyright (c) 2003-2004 Opsycon AB Sweden. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MACHINE_BUS_H_ +#define _MACHINE_BUS_H_ + +#ifdef __STDC__ +#define CAT(a,b) a##b +#define CAT3(a,b,c) a##b##c +#else +#define CAT(a,b) a/**/b +#define CAT3(a,b,c) a/**/b/**/c +#endif + +/* + * Bus access types. + */ +struct bus_space; +typedef u_long bus_addr_t; +typedef u_long bus_size_t; +typedef u_long bus_space_handle_t; +typedef struct bus_space *bus_space_tag_t; +typedef struct bus_space bus_space_t; + +struct bus_space { + bus_addr_t bus_base; + void *bus_private; + u_int8_t (*_space_read_1)(bus_space_tag_t , bus_space_handle_t, + bus_size_t); + void (*_space_write_1)(bus_space_tag_t , bus_space_handle_t, + bus_size_t, u_int8_t); + u_int16_t (*_space_read_2)(bus_space_tag_t , bus_space_handle_t, + bus_size_t); + void (*_space_write_2)(bus_space_tag_t , bus_space_handle_t, + bus_size_t, u_int16_t); + u_int32_t (*_space_read_4)(bus_space_tag_t , bus_space_handle_t, + bus_size_t); + void (*_space_write_4)(bus_space_tag_t , bus_space_handle_t, + bus_size_t, u_int32_t); + u_int64_t (*_space_read_8)(bus_space_tag_t , bus_space_handle_t, + bus_size_t); + void (*_space_write_8)(bus_space_tag_t , bus_space_handle_t, + bus_size_t, u_int64_t); + void (*_space_read_raw_2)(bus_space_tag_t, bus_space_handle_t, + bus_addr_t, u_int8_t *, bus_size_t); + void (*_space_write_raw_2)(bus_space_tag_t, bus_space_handle_t, + bus_addr_t, const u_int8_t *, bus_size_t); + void (*_space_read_raw_4)(bus_space_tag_t, bus_space_handle_t, + bus_addr_t, u_int8_t *, bus_size_t); + void (*_space_write_raw_4)(bus_space_tag_t, bus_space_handle_t, + bus_addr_t, const u_int8_t *, bus_size_t); + void (*_space_read_raw_8)(bus_space_tag_t, bus_space_handle_t, + bus_addr_t, u_int8_t *, bus_size_t); + void (*_space_write_raw_8)(bus_space_tag_t, bus_space_handle_t, + bus_addr_t, const u_int8_t *, bus_size_t); + int (*_space_map)(bus_space_tag_t , bus_addr_t, + bus_size_t, int, bus_space_handle_t *); + void (*_space_unmap)(bus_space_tag_t, bus_space_handle_t, + bus_size_t); + int (*_space_subregion)(bus_space_tag_t, bus_space_handle_t, + bus_size_t, bus_size_t, bus_space_handle_t *); + void * (*_space_vaddr)(bus_space_tag_t, bus_space_handle_t); + paddr_t (*_space_mmap)(bus_space_tag_t, bus_addr_t, off_t, + int, int); +}; + +#define bus_space_read_1(t, h, o) (*(t)->_space_read_1)((t), (h), (o)) +#define bus_space_read_2(t, h, o) (*(t)->_space_read_2)((t), (h), (o)) +#define bus_space_read_4(t, h, o) (*(t)->_space_read_4)((t), (h), (o)) +#define bus_space_read_8(t, h, o) (*(t)->_space_read_8)((t), (h), (o)) + +#define bus_space_write_1(t, h, o, v) (*(t)->_space_write_1)((t), (h), (o), (v)) +#define bus_space_write_2(t, h, o, v) (*(t)->_space_write_2)((t), (h), (o), (v)) +#define bus_space_write_4(t, h, o, v) (*(t)->_space_write_4)((t), (h), (o), (v)) +#define bus_space_write_8(t, h, o, v) (*(t)->_space_write_8)((t), (h), (o), (v)) + +#define bus_space_read_raw_2(t, h, o) \ + (*(t)->_space_read_2)((t), (h), (o)) +#define bus_space_read_raw_4(t, h, o) \ + (*(t)->_space_read_4)((t), (h), (o)) +#define bus_space_read_raw_8(t, h, o) \ + (*(t)->_space_read_8)((t), (h), (o)) + +#define bus_space_write_raw_2(t, h, o, v) \ + (*(t)->_space_write_2)((t), (h), (o), (v)) +#define bus_space_write_raw_4(t, h, o, v) \ + (*(t)->_space_write_4)((t), (h), (o), (v)) +#define bus_space_write_raw_8(t, h, o, v) \ + (*(t)->_space_write_8)((t), (h), (o), (v)) + +#define bus_space_read_raw_multi_2(t, h, a, b, l) \ + (*(t)->_space_read_raw_2)((t), (h), (a), (b), (l)) +#define bus_space_read_raw_multi_4(t, h, a, b, l) \ + (*(t)->_space_read_raw_4)((t), (h), (a), (b), (l)) +#define bus_space_read_raw_multi_8(t, h, a, b, l) \ + (*(t)->_space_read_raw_8)((t), (h), (a), (b), (l)) + +#define bus_space_write_raw_multi_2(t, h, a, b, l) \ + (*(t)->_space_write_raw_2)((t), (h), (a), (b), (l)) +#define bus_space_write_raw_multi_4(t, h, a, b, l) \ + (*(t)->_space_write_raw_4)((t), (h), (a), (b), (l)) +#define bus_space_write_raw_multi_8(t, h, a, b, l) \ + (*(t)->_space_write_raw_8)((t), (h), (a), (b), (l)) + +#define bus_space_map(t, o, s, c, p) (*(t)->_space_map)((t), (o), (s), (c), (p)) +#define bus_space_unmap(t, h, s) (*(t)->_space_unmap)((t), (h), (s)) +#define bus_space_subregion(t, h, o, s, p) \ + (*(t)->_space_subregion)((t), (h), (o), (s), (p)) + +#define BUS_SPACE_MAP_CACHEABLE 0x01 +#define BUS_SPACE_MAP_LINEAR 0x02 +#define BUS_SPACE_MAP_PREFETCHABLE 0x04 + +extern bus_space_t loongarch64_bs_tag; + +#define bus_space_vaddr(t, h) (*(t)->_space_vaddr)((t), (h)) +#define bus_space_mmap(t, a, o, p, f) \ + (*(t)->_space_mmap)((t), (a), (o), (p), (f)) + +/*----------------------------------------------------------------------------*/ +#define bus_space_read_multi(n,m) \ +static __inline void \ +CAT(bus_space_read_multi_,n)(bus_space_tag_t bst, bus_space_handle_t bsh, \ + bus_size_t o, CAT3(u_int,m,_t) *x, size_t cnt) \ +{ \ + while (cnt--) \ + *x++ = CAT(bus_space_read_,n)(bst, bsh, o); \ +} + +bus_space_read_multi(1,8) +bus_space_read_multi(2,16) +bus_space_read_multi(4,32) +bus_space_read_multi(8,64) + +/*----------------------------------------------------------------------------*/ +#define bus_space_read_region(n,m) \ +static __inline void \ +CAT(bus_space_read_region_,n)(bus_space_tag_t bst, bus_space_handle_t bsh, \ + bus_addr_t ba, CAT3(u_int,m,_t) *x, size_t cnt) \ +{ \ + while (cnt--) { \ + *x++ = CAT(bus_space_read_,n)(bst, bsh, ba); \ + ba += (n); \ + } \ +} + +bus_space_read_region(1,8) +bus_space_read_region(2,16) +bus_space_read_region(4,32) +bus_space_read_region(8,64) + +/*----------------------------------------------------------------------------*/ +#define bus_space_read_raw_region(n,m) \ +static __inline void \ +CAT(bus_space_read_raw_region_,n)(bus_space_tag_t bst, \ + bus_space_handle_t bsh, \ + bus_addr_t ba, u_int8_t *x, size_t cnt) \ +{ \ + cnt >>= ((n) >> 1); \ + while (cnt--) { \ + CAT(bus_space_read_raw_multi_,n)(bst, bsh, ba, x, (n)); \ + ba += (n); \ + x += (n); \ + } \ +} + +bus_space_read_raw_region(2,16) +bus_space_read_raw_region(4,32) +bus_space_read_raw_region(8,64) + +/*----------------------------------------------------------------------------*/ +#define bus_space_write_multi(n,m) \ +static __inline void \ +CAT(bus_space_write_multi_,n)(bus_space_tag_t bst, bus_space_handle_t bsh, \ + bus_size_t o, const CAT3(u_int,m,_t) *x, size_t cnt) \ +{ \ + while (cnt--) \ + CAT(bus_space_write_,n)(bst, bsh, o, *x++); \ +} + +bus_space_write_multi(1,8) +bus_space_write_multi(2,16) +bus_space_write_multi(4,32) +bus_space_write_multi(8,64) + +/*----------------------------------------------------------------------------*/ +#define bus_space_write_region(n,m) \ +static __inline void \ +CAT(bus_space_write_region_,n)(bus_space_tag_t bst, bus_space_handle_t bsh, \ + bus_addr_t ba, const CAT3(u_int,m,_t) *x, size_t cnt) \ +{ \ + while (cnt--) { \ + CAT(bus_space_write_,n)(bst, bsh, ba, *x++); \ + ba += (n); \ + } \ +} + +bus_space_write_region(1,8) +bus_space_write_region(2,16) +bus_space_write_region(4,32) +bus_space_write_region(8,64) + +/*----------------------------------------------------------------------------*/ +#define bus_space_write_raw_region(n,m) \ +static __inline void \ +CAT(bus_space_write_raw_region_,n)(bus_space_tag_t bst, \ + bus_space_handle_t bsh, \ + bus_addr_t ba, const u_int8_t *x, size_t cnt) \ +{ \ + cnt >>= ((n) >> 1); \ + while (cnt--) { \ + CAT(bus_space_write_raw_multi_,n)(bst, bsh, ba, x, (n)); \ + ba += (n); \ + x += (n); \ + } \ +} + +bus_space_write_raw_region(2,16) +bus_space_write_raw_region(4,32) +bus_space_write_raw_region(8,64) + +/*----------------------------------------------------------------------------*/ +#define bus_space_set_region(n,m) \ +static __inline void \ +CAT(bus_space_set_region_,n)(bus_space_tag_t bst, bus_space_handle_t bsh, \ + bus_addr_t ba, CAT3(u_int,m,_t) x, size_t cnt) \ +{ \ + while (cnt--) { \ + CAT(bus_space_write_,n)(bst, bsh, ba, x); \ + ba += (n); \ + } \ +} + +bus_space_set_region(1,8) +bus_space_set_region(2,16) +bus_space_set_region(4,32) +bus_space_set_region(8,64) + +/*----------------------------------------------------------------------------*/ +static __inline void +bus_space_copy_1(void *v, bus_space_handle_t h1, bus_size_t o1, + bus_space_handle_t h2, bus_size_t o2, bus_size_t c) +{ + char *s = (char *)(h1 + o1); + char *d = (char *)(h2 + o2); + + __asm volatile ("dbar 7" ::: "memory"); + while (c--) + *d++ = *s++; + __asm volatile ("ibar 7" ::: "memory"); +} + + +static __inline void +bus_space_copy_2(void *v, bus_space_handle_t h1, bus_size_t o1, + bus_space_handle_t h2, bus_size_t o2, bus_size_t c) +{ + short *s = (short *)(h1 + o1); + short *d = (short *)(h2 + o2); + + __asm volatile ("dbar 7" ::: "memory"); + while (c--) + *d++ = *s++; + __asm volatile ("ibar 7" ::: "memory"); +} + +static __inline void +bus_space_copy_4(void *v, bus_space_handle_t h1, bus_size_t o1, + bus_space_handle_t h2, bus_size_t o2, bus_size_t c) +{ + int *s = (int *)(h1 + o1); + int *d = (int *)(h2 + o2); + + __asm volatile ("dbar 7" ::: "memory"); + while (c--) + *d++ = *s++; + __asm volatile ("ibar 7" ::: "memory"); +} + +static __inline void +bus_space_copy_8(void *v, bus_space_handle_t h1, bus_size_t o1, + bus_space_handle_t h2, bus_size_t o2, bus_size_t c) +{ + int64_t *s = (int64_t *)(h1 + o1); + int64_t *d = (int64_t *)(h2 + o2); + + __asm volatile ("dbar 7" ::: "memory"); + while (c--) + *d++ = *s++; + __asm volatile ("ibar 7" ::: "memory"); +} + +/*----------------------------------------------------------------------------*/ +/* + * Bus read/write barrier methods. + * + * void bus_space_barrier(bus_space_tag_t tag, + * bus_space_handle_t bsh, bus_size_t offset, + * bus_size_t len, int flags); + * + */ +static inline void +bus_space_barrier(bus_space_tag_t t, bus_space_handle_t h, bus_size_t offset, + bus_size_t length, int flags) +{ + __asm__ volatile ("ibar 0" ::: "memory"); +} +#define BUS_SPACE_BARRIER_READ 0x01 /* force read barrier */ +#define BUS_SPACE_BARRIER_WRITE 0x02 /* force write barrier */ + +#define BUS_DMA_WAITOK 0x0000 +#define BUS_DMA_NOWAIT 0x0001 +#define BUS_DMA_ALLOCNOW 0x0002 +#define BUS_DMA_COHERENT 0x0008 +#define BUS_DMA_BUS1 0x0010 /* placeholders for bus functions... */ +#define BUS_DMA_BUS2 0x0020 +#define BUS_DMA_BUS3 0x0040 +#define BUS_DMA_BUS4 0x0080 +#define BUS_DMA_READ 0x0100 /* mapping is device -> memory only */ +#define BUS_DMA_WRITE 0x0200 /* mapping is memory -> device only */ +#define BUS_DMA_STREAMING 0x0400 /* hint: sequential, unidirectional */ +#define BUS_DMA_ZERO 0x0800 /* zero memory in dmamem_alloc */ +#define BUS_DMA_NOCACHE 0x1000 +#define BUS_DMA_64BIT 0x2000 /* device handles 64bit dva */ + +/* Forwards needed by prototypes below. */ +struct mbuf; +struct proc; +struct uio; + +#define BUS_DMASYNC_POSTREAD 0x0001 +#define BUS_DMASYNC_POSTWRITE 0x0002 +#define BUS_DMASYNC_PREREAD 0x0004 +#define BUS_DMASYNC_PREWRITE 0x0008 + +typedef struct machine_bus_dma_tag *bus_dma_tag_t; +typedef struct machine_bus_dmamap *bus_dmamap_t; + +/* + * bus_dma_segment_t + * + * Describes a single contiguous DMA transaction. Values + * are suitable for programming into DMA registers. + */ +struct machine_bus_dma_segment { + bus_addr_t ds_addr; /* DMA address */ + bus_size_t ds_len; /* length of transfer */ + + paddr_t _ds_paddr; /* CPU address */ + vaddr_t _ds_vaddr; /* CPU address */ + vaddr_t _ds_bounce_va; /* mapped bounced data */ + int _ds_coherent; /* Coherently mapped */ +}; +typedef struct machine_bus_dma_segment bus_dma_segment_t; + +/* + * bus_dma_tag_t + * + * A machine-dependent opaque type describing the implementation of + * DMA for a given bus. + */ + +struct machine_bus_dma_tag { + void *_cookie; /* cookie used in the guts */ + int _flags; /* misc. flags */ + paddr_t _low; /* lowest DMA-reachable address */ + paddr_t _high; /* highest DMA-reachable address */ + + /* + * DMA mapping methods. + */ + int (*_dmamap_create)(bus_dma_tag_t , bus_size_t, int, + bus_size_t, bus_size_t, int, bus_dmamap_t *); + void (*_dmamap_destroy)(bus_dma_tag_t , bus_dmamap_t); + int (*_dmamap_load)(bus_dma_tag_t , bus_dmamap_t, void *, + bus_size_t, struct proc *, int); + int (*_dmamap_load_mbuf)(bus_dma_tag_t , bus_dmamap_t, + struct mbuf *, int); + int (*_dmamap_load_uio)(bus_dma_tag_t , bus_dmamap_t, + struct uio *, int); + int (*_dmamap_load_raw)(bus_dma_tag_t , bus_dmamap_t, + bus_dma_segment_t *, int, bus_size_t, int); + int (*_dmamap_load_buffer)(bus_dma_tag_t, bus_dmamap_t, void *, + bus_size_t, struct proc *, int, paddr_t *, int *, + int *, int *, int); + void (*_dmamap_unload)(bus_dma_tag_t , bus_dmamap_t); + void (*_dmamap_sync)(bus_dma_tag_t , bus_dmamap_t, + bus_addr_t, bus_size_t, int); + + /* + * DMA memory utility functions. + */ + int (*_dmamem_alloc)(bus_dma_tag_t, bus_size_t, bus_size_t, + bus_size_t, bus_dma_segment_t *, int, int *, int); + int (*_dmamem_alloc_range)(bus_dma_tag_t, bus_size_t, bus_size_t, + bus_size_t, bus_dma_segment_t *, int, int *, int, + paddr_t, paddr_t); + void (*_dmamem_free)(bus_dma_tag_t, bus_dma_segment_t *, int); + int (*_dmamem_map)(bus_dma_tag_t, bus_dma_segment_t *, + int, size_t, caddr_t *, int); + void (*_dmamem_unmap)(bus_dma_tag_t, caddr_t, size_t); + paddr_t (*_dmamem_mmap)(bus_dma_tag_t, bus_dma_segment_t *, + int, off_t, int, int); + + /* + * internal memory address translation information. + */ + bus_addr_t _dma_mask; +}; + +#define bus_dmamap_create(t, s, n, m, b, f, p) \ + (*(t)->_dmamap_create)((t), (s), (n), (m), (b), (f), (p)) +#define bus_dmamap_destroy(t, p) \ + (*(t)->_dmamap_destroy)((t), (p)) +#define bus_dmamap_load(t, m, b, s, p, f) \ + (*(t)->_dmamap_load)((t), (m), (b), (s), (p), (f)) +#define bus_dmamap_load_mbuf(t, m, b, f) \ + (*(t)->_dmamap_load_mbuf)((t), (m), (b), (f)) +#define bus_dmamap_load_uio(t, m, u, f) \ + (*(t)->_dmamap_load_uio)((t), (m), (u), (f)) +#define bus_dmamap_load_raw(t, m, sg, n, s, f) \ + (*(t)->_dmamap_load_raw)((t), (m), (sg), (n), (s), (f)) +#define bus_dmamap_unload(t, p) \ + (*(t)->_dmamap_unload)((t), (p)) +#define bus_dmamap_sync(t, p, a, l, o) \ + (void)((t)->_dmamap_sync ? \ + (*(t)->_dmamap_sync)((t), (p), (a), (l), (o)) : (void)0) + +#define bus_dmamem_alloc(t, s, a, b, sg, n, r, f) \ + (*(t)->_dmamem_alloc)((t), (s), (a), (b), (sg), (n), (r), (f)) +#define bus_dmamem_alloc_range(t, s, a, b, sg, n, r, f, l, h) \ + (*(t)->_dmamem_alloc_range)((t), (s), (a), (b), (sg), \ + (n), (r), (f), (l), (h)) +#define bus_dmamem_free(t, sg, n) \ + (*(t)->_dmamem_free)((t), (sg), (n)) +#define bus_dmamem_map(t, sg, n, s, k, f) \ + (*(t)->_dmamem_map)((t), (sg), (n), (s), (k), (f)) +#define bus_dmamem_unmap(t, k, s) \ + (*(t)->_dmamem_unmap)((t), (k), (s)) +#define bus_dmamem_mmap(t, sg, n, o, p, f) \ + (*(t)->_dmamem_mmap)((t), (sg), (n), (o), (p), (f)) + +void bus_dma_init(void); + +int _dmamap_create(bus_dma_tag_t, bus_size_t, int, + bus_size_t, bus_size_t, int, bus_dmamap_t *); +void _dmamap_destroy(bus_dma_tag_t, bus_dmamap_t); +int _dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *, + bus_size_t, struct proc *, int); +int _dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t, struct mbuf *, int); +int _dmamap_load_uio(bus_dma_tag_t, bus_dmamap_t, struct uio *, int); +int _dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t, + bus_dma_segment_t *, int, bus_size_t, int); +int _dmamap_load_buffer(bus_dma_tag_t, bus_dmamap_t, void *, + bus_size_t, struct proc *, int, paddr_t *, int *, int *, + int *, int); +void _dmamap_unload(bus_dma_tag_t, bus_dmamap_t); +void _dmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_addr_t, + bus_size_t, int); + +int _dmamem_alloc(bus_dma_tag_t, bus_size_t, bus_size_t, + bus_size_t, bus_dma_segment_t *, int, int *, int); +void _dmamem_free(bus_dma_tag_t, bus_dma_segment_t *, int); +int _dmamem_map(bus_dma_tag_t, bus_dma_segment_t *, + int, size_t, caddr_t *, int); +void _dmamem_unmap(bus_dma_tag_t, caddr_t, size_t); +paddr_t _dmamem_mmap(bus_dma_tag_t, bus_dma_segment_t *, int, off_t, int, int); +int _dmamem_alloc_range(bus_dma_tag_t, bus_size_t, bus_size_t, bus_size_t, + bus_dma_segment_t *, int, int *, int, paddr_t, paddr_t); + +/* + * bus_dmamap_t + * + * Describes a DMA mapping. + */ +struct machine_bus_dmamap { + /* + * PRIVATE MEMBERS: not for use by machine-independent code. + */ + bus_size_t _dm_size; /* largest DMA transfer mappable */ + int _dm_segcnt; /* number of segs this map can map */ + bus_size_t _dm_maxsegsz; /* largest possible segment */ + bus_size_t _dm_boundary; /* don't cross this */ + int _dm_flags; /* misc. flags */ + + void *_dm_cookie; /* cookie for bus-specific functions */ + + struct vm_page **_dm_pages; /* replacement pages */ + vaddr_t _dm_pgva; /* those above -- mapped */ + int _dm_npages; /* number of pages allocated */ + int _dm_nused; /* number of pages replaced */ + paddr_t _dm_low; /* lowest DMA-reachable address */ + paddr_t _dm_high; /* highest DMA-reachable address */ + + /* + * PUBLIC MEMBERS: these are used by machine-independent code. + */ + bus_size_t dm_mapsize; /* size of the mapping */ + int dm_nsegs; /* # valid segments in mapping */ + bus_dma_segment_t dm_segs[1]; /* segments; variable length */ +}; + +int generic_space_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, + bus_space_handle_t *); +void generic_space_unmap(bus_space_tag_t, bus_space_handle_t, bus_size_t); +int generic_space_region(bus_space_tag_t, bus_space_handle_t, bus_size_t, + bus_size_t, bus_space_handle_t *); +void *generic_space_vaddr(bus_space_tag_t, bus_space_handle_t); +paddr_t generic_space_mmap(bus_space_tag_t, bus_addr_t, off_t, int, int); +uint8_t generic_space_read_1(bus_space_tag_t, bus_space_handle_t, bus_size_t); +uint16_t generic_space_read_2(bus_space_tag_t, bus_space_handle_t, bus_size_t); +uint32_t generic_space_read_4(bus_space_tag_t, bus_space_handle_t, bus_size_t); +uint64_t generic_space_read_8(bus_space_tag_t, bus_space_handle_t, bus_size_t); +void generic_space_read_raw_2(bus_space_tag_t, bus_space_handle_t, + bus_addr_t, uint8_t *, bus_size_t); +void generic_space_write_1(bus_space_tag_t, bus_space_handle_t, bus_size_t, + uint8_t); +void generic_space_write_2(bus_space_tag_t, bus_space_handle_t, bus_size_t, + uint16_t); +void generic_space_write_4(bus_space_tag_t, bus_space_handle_t, bus_size_t, + uint32_t); +void generic_space_write_8(bus_space_tag_t, bus_space_handle_t, bus_size_t, + uint64_t); +void generic_space_write_raw_2(bus_space_tag_t, bus_space_handle_t, + bus_addr_t, const uint8_t *, bus_size_t); +void generic_space_read_raw_4(bus_space_tag_t, bus_space_handle_t, + bus_addr_t, uint8_t *, bus_size_t); +void generic_space_write_raw_4(bus_space_tag_t, bus_space_handle_t, + bus_addr_t, const uint8_t *, bus_size_t); +void generic_space_read_raw_8(bus_space_tag_t, bus_space_handle_t, + bus_addr_t, uint8_t *, bus_size_t); +void generic_space_write_raw_8(bus_space_tag_t, bus_space_handle_t, + bus_addr_t, const uint8_t *, bus_size_t); + +#endif /* _MACHINE_BUS_H_ */ diff --git sys/arch/loongarch64/include/cdefs.h sys/arch/loongarch64/include/cdefs.h new file mode 100644 index 00000000000..e266edfe691 --- /dev/null +++ sys/arch/loongarch64/include/cdefs.h @@ -0,0 +1,16 @@ +/* $OpenBSD: cdefs.h,v 1.1 2021/04/23 02:42:16 drahn Exp $ */ + +#ifndef _MACHINE_CDEFS_H_ +#define _MACHINE_CDEFS_H_ + +#define __strong_alias(alias,sym) \ + __asm__(".global " __STRING(alias) " ; " __STRING(alias) \ + " = " __STRING(sym)) +#define __weak_alias(alias,sym) \ + __asm__(".weak " __STRING(alias) " ; " __STRING(alias) \ + " = " __STRING(sym)) +#define __warn_references(sym,msg) \ + __asm__(".section .gnu.warning." __STRING(sym) \ + " ; .ascii \"" msg "\" ; .text") + +#endif /* !_MACHINE_CDEFS_H_ */ diff --git sys/arch/loongarch64/include/conf.h sys/arch/loongarch64/include/conf.h new file mode 100644 index 00000000000..4e4cee002c2 --- /dev/null +++ sys/arch/loongarch64/include/conf.h @@ -0,0 +1,50 @@ +/* $OpenBSD: conf.h,v 1.4 2022/06/28 14:43:50 visa Exp $ */ + +/* + * Copyright (c) 1996 Christos Zoulas. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christos Zoulas. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _MACHINE_CONF_H_ +#define _MACHINE_CONF_H_ + +#include + +#define mmread mmrw +#define mmwrite mmrw +cdev_decl(mm); + +/* open, close, ioctl */ +#define cdev_openprom_init(c,n) { \ + dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \ + (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \ + (dev_type_stop((*))) nullop, 0, \ + (dev_type_mmap((*))) enodev } + +cdev_decl(openprom); + +#endif /* _MACHINE_CONF_H_ */ diff --git sys/arch/loongarch64/include/cpu.h sys/arch/loongarch64/include/cpu.h new file mode 100644 index 00000000000..ba6b13ea7da --- /dev/null +++ sys/arch/loongarch64/include/cpu.h @@ -0,0 +1,327 @@ +/* $OpenBSD: cpu.h,v 1.28 2026/07/07 12:12:44 kettenis Exp $ */ + +/* + * Copyright (c) 2019 Mike Larkin + * Copyright (c) 2016 Dale Rahn + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _MACHINE_CPU_H_ +#define _MACHINE_CPU_H_ + +/* + * User-visible definitions + */ + +/* CTL_MACHDEP definitions. */ +#define CPU_COMPATIBLE 1 /* compatible property */ +#define CPU_LED_BLINK 2 /* int: blink leds? */ +#define CPU_MAXID 3 /* number of valid machdep ids */ + +#define CTL_MACHDEP_NAMES { \ + { 0, 0 }, \ + { "compatible", CTLTYPE_STRING }, \ + { "led_blink", CTLTYPE_INT }, \ +} + +#ifdef _KERNEL + +/* + * Kernel-only definitions + */ +#include +#include +#include + +void cpu_identify_cleanup(void); + +/* All the CLKF_* macros take a struct clockframe * as an argument. */ + +#define clockframe trapframe +/* + * CLKF_USERMODE: Return TRUE/FALSE (1/0) depending on whether the + * frame came from USR mode or not. + */ +#define CLKF_USERMODE(frame) ((frame->tf_sstatus & SSTATUS_SPP) == 0) + +/* + * CLKF_INTR: True if we took the interrupt from inside another + * interrupt handler. + */ +#define CLKF_INTR(frame) (curcpu()->ci_idepth > 1) + +/* + * CLKF_PC: Extract the program counter from a clockframe + */ +#define CLKF_PC(frame) (frame->tf_sepc) + +/* + * PROC_PC: Find out the program counter for the given process. + */ +#define PROC_PC(p) ((p)->p_addr->u_pcb.pcb_tf->tf_sepc) +#define PROC_STACK(p) ((p)->p_addr->u_pcb.pcb_tf->tf_sp) + +#include +#include +#include +#include +#include + +struct cpu_info { + struct device *ci_dev; /* Device corresponding to this CPU */ + struct cpu_info *ci_next; + struct schedstate_percpu ci_schedstate; /* scheduler state */ + + u_int32_t ci_cpuid; + uint64_t ci_hartid; + u_int ci_acpi_proc_id; + int ci_node; + struct cpu_info *ci_self; + + struct proc *ci_curproc; + struct pmap *ci_curpm; + u_int32_t ci_randseed; + + struct pcb *ci_curpcb; + struct pcb *ci_idle_pcb; + + struct clockqueue ci_queue; + volatile int ci_timer_deferred; + + uint32_t ci_cpl; + uint32_t ci_ipending; + uint32_t ci_idepth; +#ifdef DIAGNOSTIC + int ci_mutex_level; +#endif + int ci_want_resched; + + struct opp_table *ci_opp_table; + volatile int ci_opp_idx; + volatile int ci_opp_max; + uint32_t ci_cpu_supply; + +#ifdef MULTIPROCESSOR + struct srp_hazard ci_srp_hazards[SRP_HAZARD_NUM]; +#define __HAVE_UVM_PERCPU + struct uvm_pmr_cache ci_uvm; + volatile int ci_flags; + uint64_t ci_satp; + vaddr_t ci_initstack_end; + int ci_ipi_reason; + + volatile int ci_ddb_paused; +#define CI_DDB_RUNNING 0 +#define CI_DDB_SHOULDSTOP 1 +#define CI_DDB_STOPPED 2 +#define CI_DDB_ENTERDDB 3 +#define CI_DDB_INDDB 4 + +#endif + +#ifdef GPROF + struct gmonparam *ci_gmon; + struct clockintr ci_gmonclock; +#endif + + char ci_panicbuf[512]; +}; + +#define CPUF_PRIMARY (1<<0) +#define CPUF_AP (1<<1) +#define CPUF_IDENTIFY (1<<2) +#define CPUF_IDENTIFIED (1<<3) +#define CPUF_PRESENT (1<<4) +#define CPUF_GO (1<<5) +#define CPUF_RUNNING (1<<6) + +register struct cpu_info *__curcpu asm ("$tp"); + +#define curcpu() (__curcpu) + +extern uint32_t boot_hart; /* The hart we booted on. */ +extern struct cpu_info cpu_info_primary; +extern struct cpu_info *cpu_info_list; + +#ifndef MULTIPROCESSOR + +#define cpu_number() 0 +#define CPU_IS_PRIMARY(ci) 1 +#define CPU_IS_RUNNING(ci) 1 +#define CPU_INFO_ITERATOR int +#define CPU_INFO_FOREACH(cii, ci) \ + for (cii = 0, ci = curcpu(); ci != NULL; ci = NULL) +#define CPU_INFO_UNIT(ci) 0 +#define MAXCPUS 1 +#define cpu_unidle(ci) + +#else + +#define cpu_number() (curcpu()->ci_cpuid) +#define CPU_IS_PRIMARY(ci) ((ci) == &cpu_info_primary) +#define CPU_IS_RUNNING(ci) ((ci)->ci_flags & CPUF_RUNNING) +#define CPU_INFO_ITERATOR int +#define CPU_INFO_FOREACH(cii, ci) for (cii = 0, ci = cpu_info_list; \ + ci != NULL; ci = ci->ci_next) +#define CPU_INFO_UNIT(ci) ((ci)->ci_dev ? (ci)->ci_dev->dv_unit : 0) +#define MAXCPUS 32 + +extern struct cpu_info *cpu_info[MAXCPUS]; + +void cpu_boot_secondary_processors(void); + +#endif /* !MULTIPROCESSOR */ + +/* Zihintpause ratified extension */ +#define CPU_BUSY_CYCLE() __asm volatile(".long 0x0100000f" ::: "memory") + +#define curpcb curcpu()->ci_curpcb + +static inline unsigned int +cpu_rnd_messybits(void) +{ + // Should do bit reversal ^ with csr_read(LOONGARCH_CSR_STIME); + return csr_read(LOONGARCH_CSR_STIME); +} + +/* + * Scheduling glue + */ +#define aston(p) ((p)->p_md.md_astpending = 1) +#define setsoftast() aston(curcpu()->ci_curproc) + +/* + * Notify the current process (p) that it has a signal pending, + * process as soon as possible. + */ + +#ifdef MULTIPROCESSOR +void cpu_unidle(struct cpu_info *ci); +#define signotify(p) (aston(p), cpu_unidle((p)->p_cpu)) +void cpu_kick(struct cpu_info *); +#else +#define cpu_kick(ci) +#define cpu_unidle(ci) +#define signotify(p) setsoftast() +#endif + +/* + * Preempt the current process if in interrupt from user mode, + * or after the current trap/syscall if in system mode. + */ +void need_resched(struct cpu_info *); +#define clear_resched(ci) ((ci)->ci_want_resched = 0) + +/* + * Give a profiling tick to the current process when the user profiling + * buffer pages are invalid. On the i386, request an ast to send us + * through trap(), marking the proc as needing a profiling tick. + */ +#define need_proftick(p) aston(p) + +// asm code to start new kernel contexts. +void proc_trampoline(void); + +/* + * Random cruft + */ +void dumpconf(void); + +static inline void +intr_enable(void) +{ + unsigned long val = CRMD_IE; + __asm volatile("csrxchg %0, %1, %2" : "+r" (val): "r" (CRMD_IE), "i" (LOONGARCH_CSR_CRMD) : "memory"); +} + +static inline u_long +intr_disable(void) +{ + + unsigned long old = 0; + unsigned long mask = CRMD_IE; + + /* + * csrxchg rd, rj, csr: + * rd = old CSR value + * CSR[mask] = rd_old[mask] + * + * Since old starts at zero, this clears CRMD.IE while + * returning the previous CRMD value. + */ + __asm__ volatile( + "csrxchg %0, %1, %2" + : "+&r"(old) + : "r"(mask), "i"(LOONGARCH_CSR_CRMD) + : "memory" + ); + + return old & mask; + +} + +static inline void +intr_restore(u_long s) +{ + + unsigned long mask = CRMD_IE; + + /* + * Replace only CRMD.IE with the saved state. + * state is expected to be either 0 or LOONGARCH_CRMD_IE. + */ + __asm__ volatile( + "csrxchg %0, %1, %2" + : "+&r"(s) + : "r"(mask), "i"(LOONGARCH_CSR_CRMD) + : "memory" + ); + +} + +void delay (unsigned); +#define DELAY(x) delay(x) + +extern void (*cpu_startclock_fcn)(void); + +extern unsigned long loongarch_hwcap; +extern size_t loongarch_vlenb; + +void fpu_save(struct proc *, struct trapframe *); +void fpu_load(struct proc *); + +int vector_instruction(register_t stval); +void vector_save(struct proc *, struct trapframe *); +void vector_load(struct proc *); + +extern int cpu_errata_sifive_cip_1200; + +#define cpu_idle_enter() do { /* nothing */ } while (0) +#define cpu_idle_leave() do { /* nothing */ } while (0) + +struct blink_led { + void (*bl_func)(void *, int); + void *bl_arg; + SLIST_ENTRY(blink_led) bl_next; +}; + +void blink_led_register(struct blink_led *); + +#endif /* _KERNEL */ + +#ifdef MULTIPROCESSOR +#include +#endif /* MULTIPROCESSOR */ + +#endif /* !_MACHINE_CPU_H_ */ diff --git sys/arch/loongarch64/include/cpufunc.h sys/arch/loongarch64/include/cpufunc.h new file mode 100644 index 00000000000..32557f8de38 --- /dev/null +++ sys/arch/loongarch64/include/cpufunc.h @@ -0,0 +1,103 @@ +/* $OpenBSD: cpufunc.h,v 1.7 2026/04/05 11:48:17 kettenis Exp $ */ + +/*- + * Copyright (c) 2014 Andrew Turner + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: head/sys/cpu/include/cpufunc.h 299683 2016-05-13 16:03:50Z andrew $ + */ + +#ifndef _MACHINE_CPUFUNC_H_ +#define _MACHINE_CPUFUNC_H_ + +static __inline void +breakpoint(void) +{ + __asm("ebreak"); +} + +#ifdef _KERNEL + +#include + +#define rdcycle() csr_read(cycle) +#define rdtime() csr_read(LOONGARCH_CSR_STIME) +#define rdinstret() csr_read(instret) +#define rdhpmcounter(n) csr_read(hpmcounter##n) + +static __inline void +fence_i(void) +{ + __asm volatile("ibar 0" ::: "memory"); +} + +static __inline void +sfence_vma(void) +{ + __asm volatile("invtlb 0, $zero, $zero" ::: "memory"); +} + +static __inline void +sfence_vma_page(uintptr_t addr) +{ + __asm volatile("invtlb 0, $zero, $zero" + : + : "r" (addr) + : "memory"); +} + +// XXX ASIDs in loongarch64 are only 16 bits. +static __inline void +sfence_vma_asid(uint64_t asid) +{ + __asm volatile("invtlb 0, $zero, $zero" + : + : "r" (asid) + : "memory"); +} + +static __inline void +sfence_vma_page_asid(uintptr_t addr, uint64_t asid) +{ + __asm volatile("invtlb 0, $zero, $zero" + : + : "r" (addr), "r" (asid) + : "memory"); +} + +extern int64_t dcache_line_size; +extern int64_t icache_line_size; + +extern void (*cpu_dcache_wbinv_range)(vaddr_t, vsize_t); +extern void (*cpu_dcache_inv_range)(vaddr_t, vsize_t); +extern void (*cpu_dcache_wb_range)(vaddr_t, vsize_t); + +static __inline void +load_satp(uint64_t val) +{ + __asm volatile("csrwr %0, 0x19" :: "r"(val)); +} + +#endif /* _KERNEL */ +#endif /* _MACHINE_CPUFUNC_H_ */ diff --git sys/arch/loongarch64/include/db_machdep.h sys/arch/loongarch64/include/db_machdep.h new file mode 100644 index 00000000000..c86fb1aef6c --- /dev/null +++ sys/arch/loongarch64/include/db_machdep.h @@ -0,0 +1,93 @@ +/* $OpenBSD: db_machdep.h,v 1.5 2021/08/30 08:11:12 jasper Exp $ */ + +/* + * Copyright (c) 2019 Brian Bamsch + * Copyright (c) 2015-2016 Ruslan Bukin + * All rights reserved. + * + * Portions of this software were developed by SRI International and the + * University of Cambridge Computer Laboratory under DARPA/AFRL contract + * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. + * + * Portions of this software were developed by the University of Cambridge + * Computer Laboratory as part of the CTSRD Project, with support from the + * UK Higher Education Innovation Fund (HEIF). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _MACHINE_DB_MACHDEP_H_ +#define _MACHINE_DB_MACHDEP_H_ + +#include +#include +#include +#include +#include + +#define T_BREAKPOINT (EXCP_BRK) +#define T_WATCHPOINT (0) + +typedef long db_expr_t; + +typedef trapframe_t db_regs_t; + +extern db_regs_t ddb_regs; +#define DDB_REGS (&ddb_regs) + +#define PC_REGS(regs) ((vaddr_t)(regs)->tf_ra) +#define SET_PC_REGS(regs, value) (regs)->tf_ra = (register_t)(value) + +#define BKPT_INST (KERNEL_BREAKPOINT) +#define BKPT_SIZE (INSN_SIZE) +#define BKPT_SET(inst) (BKPT_INST) + +#define IS_BREAKPOINT_TRAP(type, code) ((type) == T_BREAKPOINT) +#define IS_WATCHPOINT_TRAP(type, code) ((type) == T_WATCHPOINT) + +#define inst_trap_return(ins) (ins == 0x10000073) /* eret */ +#define inst_return(ins) (ins == 0x00008067) /* ret */ +#define inst_call(ins) (((ins) & 0x7f) == 0x6f || \ + ((ins) & 0x7f) == 0x67) /* jal, jalr */ +#define inst_branch(ins) (((ins) & 0x7f) == 0x63) /* branch */ + +#define next_instr_address(pc, bd) ((bd) ? (pc) : ((pc) + INSN_SIZE)) + +#define DB_MACHINE_COMMANDS + +#define SOFTWARE_SSTEP + +int db_trapper(vaddr_t, u_int, trapframe_t *, int); +void db_machine_init (void); +vaddr_t db_branch_taken(u_int inst, vaddr_t pc, db_regs_t *regs); + +#define branch_taken(ins, pc, fun, regs) \ + db_branch_taken((ins), (pc), (regs)) + +/* For ddb_state */ +#define DDB_STATE_NOT_RUNNING 0 +#define DDB_STATE_RUNNING 1 +#define DDB_STATE_EXITING 2 + +#endif /* !_MACHINE_DB_MACHDEP_H_ */ diff --git sys/arch/loongarch64/include/disklabel.h sys/arch/loongarch64/include/disklabel.h new file mode 100644 index 00000000000..be82dc5463c --- /dev/null +++ sys/arch/loongarch64/include/disklabel.h @@ -0,0 +1,26 @@ +/* $OpenBSD: disklabel.h,v 1.2 2021/05/12 01:20:52 jsg Exp $ */ + +/* + * Copyright (c) 2014 Patrick Wildt + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _MACHINE_DISKLABEL_H_ +#define _MACHINE_DISKLABEL_H_ + +#define LABELSECTOR 1 /* sector containing label */ +#define LABELOFFSET 0 /* offset of label in sector */ +#define MAXPARTITIONS 16 /* number of partitions */ + +#endif /* _MACHINE_DISKLABEL_H_ */ diff --git sys/arch/loongarch64/include/efivar.h sys/arch/loongarch64/include/efivar.h new file mode 100644 index 00000000000..3bc3a8644a3 --- /dev/null +++ sys/arch/loongarch64/include/efivar.h @@ -0,0 +1,46 @@ +/* $OpenBSD: efivar.h,v 1.2 2024/07/10 10:53:55 kettenis Exp $ */ +/* + * Copyright (c) 2022 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _MACHINE_EFIVAR_H_ +#define _MACHINE_EFIVAR_H_ + +#include + +struct efi_softc { + struct device sc_dev; + struct pmap *sc_pm; + EFI_RUNTIME_SERVICES *sc_rs; + EFI_SYSTEM_RESOURCE_TABLE *sc_esrt; + u_long sc_psw; + + struct todr_chip_handle sc_todr; +}; + + +extern EFI_GET_VARIABLE efi_get_variable; +extern EFI_SET_VARIABLE efi_set_variable; +extern EFI_GET_NEXT_VARIABLE_NAME efi_get_next_variable_name; + +void efi_enter(struct efi_softc *); +void efi_leave(struct efi_softc *); + +extern label_t efi_jmpbuf; + +#define efi_enter_check(sc) (setjmp(&efi_jmpbuf) ? \ + (efi_leave(sc), EFAULT) : (efi_enter(sc), 0)) + +#endif /* _MACHINE_EFIVAR_H_ */ diff --git sys/arch/loongarch64/include/elf.h sys/arch/loongarch64/include/elf.h new file mode 100644 index 00000000000..4c92504c7e5 --- /dev/null +++ sys/arch/loongarch64/include/elf.h @@ -0,0 +1,96 @@ +/* $OpenBSD: elf.h,v 1.4 2026/05/02 14:09:17 jsing Exp $ */ + +/*- + * Copyright (c) 1996-1997 John D. Polstra. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MACHINE_ELF_H_ +#define _MACHINE_ELF_H_ + +/* + * ELF definitions for the RISC-V architecture. + */ + +#ifdef _KERNEL +# define __HAVE_CPU_HWCAP +# define __HAVE_CPU_HWCAP2 +extern unsigned long hwcap; +extern unsigned long hwcap2; +#endif /* _KERNEL */ + +/* Flags passed in AT_HWCAP */ +#define HWCAP_ISA_BIT(c) (1 << ((c) - 'a')) +#define HWCAP_ISA_I HWCAP_ISA_BIT('i') +#define HWCAP_ISA_M HWCAP_ISA_BIT('m') +#define HWCAP_ISA_A HWCAP_ISA_BIT('a') +#define HWCAP_ISA_F HWCAP_ISA_BIT('f') +#define HWCAP_ISA_D HWCAP_ISA_BIT('d') +#define HWCAP_ISA_G \ + (HWCAP_ISA_I | HWCAP_ISA_M | HWCAP_ISA_A | HWCAP_ISA_F | HWCAP_ISA_D) +#define HWCAP_ISA_B HWCAP_ISA_BIT('b') +#define HWCAP_ISA_C HWCAP_ISA_BIT('c') +#define HWCAP_ISA_H HWCAP_ISA_BIT('h') +#define HWCAP_ISA_V HWCAP_ISA_BIT('v') + +#ifdef _KERNEL +/* Kernel Used Extensions */ +#define HWCAP_ISA_K_OFFSET 32 +#define HWCAP_ISA_K_BIT(n) (1UL << (HWCAP_ISA_K_OFFSET + (n))) +#define HWCAP_ISA_K_MASK (0xffffUL << HWCAP_ISA_K_OFFSET) +#define HWCAP_ISA_ZICBOM HWCAP_ISA_K_BIT(0) /* Cache Block Management */ +#define HWCAP_ISA_ZICBOP HWCAP_ISA_K_BIT(1) /* Cache Block Prefetch */ +#define HWCAP_ISA_ZICBOZ HWCAP_ISA_K_BIT(2) /* Cache Block Zero */ + +/* Supervisor Extensions */ +#define HWCAP_ISA_S_OFFSET 48 +#define HWCAP_ISA_S_BIT(n) (1UL << (HWCAP_ISA_S_OFFSET + (n))) +#define HWCAP_ISA_S_MASK (0xffffUL << HWCAP_ISA_S_OFFSET) +#define HWCAP_ISA_SVNAPOT HWCAP_ISA_S_BIT(0) /* NAPOT Translation */ +#define HWCAP_ISA_SVPBMT HWCAP_ISA_S_BIT(1) /* Page-Based Memory Types */ +#define HWCAP_ISA_SVINVAL HWCAP_ISA_S_BIT(2) /* Cache Invalidation */ +#define HWCAP_ISA_SSTC HWCAP_ISA_S_BIT(3) /* Timer Interrupts */ +#define HWCAP_ISA_SCOFPMF HWCAP_ISA_S_BIT(4) /* Count Overflow */ +#define HWCAP_ISA_SSNPM HWCAP_ISA_S_BIT(5) /* Pointer Masking */ +#endif /* _KERNEL */ + +/* Flags passed in AT_HWCAP2 */ +#define HWCAP2_ISA_ZBA (1UL << 0) /* Address Generation */ +#define HWCAP2_ISA_ZBB (1UL << 1) /* Basic Bit Manipulation */ +#define HWCAP2_ISA_ZBC (1UL << 2) /* Carry-Less Multiplication */ +#define HWCAP2_ISA_ZBS (1UL << 3) /* Single-Bit */ +#define HWCAP2_ISA_ZFH (1UL << 4) /* Scalar Half Precision FP */ +#define HWCAP2_ISA_ZKT (1UL << 5) /* Data-Independent Execution */ +#define HWCAP2_ISA_ZVBB (1UL << 6) /* Vector Basic Bit Manipulation */ +#define HWCAP2_ISA_ZVBC (1UL << 7) /* Vector Carry-less Multiplication */ +#define HWCAP2_ISA_ZVFH (1UL << 8) /* Vector Half Precision FP */ +#define HWCAP2_ISA_ZVKG (1UL << 9) /* Vector GCM/GMAC */ +#define HWCAP2_ISA_ZVKNED (1UL << 10) /* Vector AES Block Cipher */ +#define HWCAP2_ISA_ZVKNHA (1UL << 11) /* Vector SHA-256 */ +#define HWCAP2_ISA_ZVKNHB (1UL << 12) /* Vector SHA-512 */ +#define HWCAP2_ISA_ZVKSED (1UL << 13) /* Vector ShangMi SM4 */ +#define HWCAP2_ISA_ZVKSH (1UL << 14) /* Vector ShangMi SM3 */ +#define HWCAP2_ISA_ZVKT (1UL << 15) /* Vector Data-Independent Execution */ + +#endif /* !_MACHINE_ELF_H_ */ diff --git sys/arch/loongarch64/include/endian.h sys/arch/loongarch64/include/endian.h new file mode 100644 index 00000000000..13a31ffbf62 --- /dev/null +++ sys/arch/loongarch64/include/endian.h @@ -0,0 +1,29 @@ +/* $OpenBSD: endian.h,v 1.3 2022/03/22 06:46:45 miod Exp $ */ + +/* + * Copyright (c) 2015 David Gwynne + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _MACHINE_ENDIAN_H_ +#define _MACHINE_ENDIAN_H_ + +#define _BYTE_ORDER _LITTLE_ENDIAN +#define __STRICT_ALIGNMENT + +#ifndef __FROM_SYS__ENDIAN +#include +#endif + +#endif /* _MACHINE_ENDIAN_H_ */ diff --git sys/arch/loongarch64/include/exec.h sys/arch/loongarch64/include/exec.h new file mode 100644 index 00000000000..1d2bf6c3dce --- /dev/null +++ sys/arch/loongarch64/include/exec.h @@ -0,0 +1,30 @@ +/* $OpenBSD: exec.h,v 1.2 2021/05/12 01:20:52 jsg Exp $ */ + +/* + * Copyright (c) 2014 Patrick Wildt + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _MACHINE_EXEC_H_ +#define _MACHINE_EXEC_H_ + +#define __LDPGSZ 4096 + +#define ARCH_ELFSIZE 64 + +#define ELF_TARG_CLASS ELFCLASS64 +#define ELF_TARG_DATA ELFDATA2LSB +#define ELF_TARG_MACH EM_LOONGARCH + +#endif diff --git sys/arch/loongarch64/include/fdt.h sys/arch/loongarch64/include/fdt.h new file mode 100644 index 00000000000..c747f5f19c7 --- /dev/null +++ sys/arch/loongarch64/include/fdt.h @@ -0,0 +1,59 @@ +/* $OpenBSD: fdt.h,v 1.4 2022/05/30 17:39:09 kettenis Exp $ */ + +/* + * Copyright (c) 2016 Patrick Wildt + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __LOONGARCH_FDT_H__ +#define __LOONGARCH_FDT_H__ + +#define _LOONGARCH64_BUS_DMA_PRIVATE +#include + +struct fdt_attach_args { + const char *fa_name; + int fa_node; + bus_space_tag_t fa_iot; + bus_dma_tag_t fa_dmat; + struct fdt_reg *fa_reg; + int fa_nreg; + uint32_t *fa_intr; + int fa_nintr; + int fa_acells; + int fa_scells; +}; + +extern int stdout_node; +extern int stdout_speed; +extern bus_space_tag_t fdt_cons_bs_tag; + +void *fdt_find_cons(const char *); + +#define fdt_intr_enable loongarch_intr_enable +#define fdt_intr_establish loongarch_intr_establish_fdt +#define fdt_intr_establish_idx loongarch_intr_establish_fdt_idx +#define fdt_intr_establish_idx_cpu loongarch_intr_establish_fdt_idx_cpu +#define fdt_intr_establish_imap loongarch_intr_establish_fdt_imap +#define fdt_intr_establish_imap_cpu loongarch_intr_establish_fdt_imap_cpu +#define fdt_intr_establish_msi loongarch_intr_establish_fdt_msi +#define fdt_intr_establish_msi_cpu loongarch_intr_establish_fdt_msi_cpu +#define fdt_intr_disable loongarch_intr_disable +#define fdt_intr_disestablish loongarch_intr_disestablish_fdt +#define fdt_intr_get_parent loongarch_intr_get_parent +#define fdt_intr_parent_establish loongarch_intr_parent_establish_fdt +#define fdt_intr_parent_disestablish loongarch_intr_parent_disestablish_fdt +#define fdt_intr_register loongarch_intr_register_fdt + +#endif /* __LOONGARCH_FDT_H__ */ diff --git sys/arch/loongarch64/include/fenv.h sys/arch/loongarch64/include/fenv.h new file mode 100644 index 00000000000..72f7be50cee --- /dev/null +++ sys/arch/loongarch64/include/fenv.h @@ -0,0 +1,95 @@ +/* $OpenBSD: fenv.h,v 1.2 2021/05/12 02:28:25 jsg Exp $ */ + +/* + * Copyright (c) 2011 Martynas Venckus + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _MACHINE_FENV_H_ +#define _MACHINE_FENV_H_ + +/* + * Each symbol representing a floating point exception expands to an integer + * constant expression with values, such that bitwise-inclusive ORs of _all + * combinations_ of the constants result in distinct values. + * + * We use such values that allow direct bitwise operations on FPU registers. + */ +#define FE_INVALID 0x10 +#define FE_DIVBYZERO 0x08 +#define FE_OVERFLOW 0x04 +#define FE_UNDERFLOW 0x02 +#define FE_INEXACT 0x01 + +/* + * The following symbol is simply the bitwise-inclusive OR of all floating-point + * exception constants defined above. + */ +#define FE_ALL_EXCEPT (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | \ + FE_UNDERFLOW | FE_INEXACT ) + +/* + * Each symbol representing the rounding direction, expands to an integer + * constant expression whose value is distinct non-negative value. + * + * We use such values that allow direct bitwise operations on FPU registers. + */ +#define FE_TONEAREST 0x0 +#define FE_TOWARDZERO 0x1 +#define FE_DOWNWARD 0x2 +#define FE_UPWARD 0x3 +#define FE_TONEARESTFROMZERO 0x4 + +/* + * The following symbol is simply the bitwise-inclusive OR of all floating-point + * rounding direction constants defined above. + */ +#define _ROUND_MASK (FE_TONEAREST | FE_TOWARDZERO | FE_DOWNWARD | \ + FE_UPWARD | FE_TONEARESTFROMZERO) +#define _ROUND_SHIFT 5 + +/* + * fenv_t represents the entire floating-point environment. + */ +typedef unsigned int fenv_t; + +/* + * The following constant represents the default floating-point environment + * (that is, the one installed at program startup) and has type pointer to + * const-qualified fenv_t. + * + * It can be used as an argument to the functions within the header + * that manage the floating-point environment, namely fesetenv() and + * feupdateenv(). + */ +__BEGIN_DECLS +extern fenv_t __fe_dfl_env; +__END_DECLS +#define FE_DFL_ENV ((const fenv_t *)&__fe_dfl_env) + +/* + * fexcept_t represents the floating-point status flags collectively, including + * any status the implementation associates with the flags. + * + * A floating-point status flag is a system variable whose value is set (but + * never cleared) when a floating-point exception is raised, which occurs as a + * side effect of exceptional floating-point arithmetic to provide auxiliary + * information. + * + * A floating-point control mode is a system variable whose value may be set by + * the user to affect the subsequent behavior of floating-point arithmetic. + */ +typedef unsigned int fexcept_t; + +#endif /* !_MACHINE_FENV_H_ */ diff --git sys/arch/loongarch64/include/frame.h sys/arch/loongarch64/include/frame.h new file mode 100644 index 00000000000..bfce36b52ae --- /dev/null +++ sys/arch/loongarch64/include/frame.h @@ -0,0 +1,99 @@ +/* $OpenBSD: frame.h,v 1.3 2022/02/24 14:19:10 visa Exp $ */ + +/* + * Copyright (c) 2019 Brian Bamsch + * Copyright (c) 2016 Dale Rahn + * Copyright (c) 2015 Ruslan Bukin + * All rights reserved. + * + * Portions of this software were developed by SRI International and the + * University of Cambridge Computer Laboratory under DARPA/AFRL contract + * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. + * + * Portions of this software were developed by the University of Cambridge + * Computer Laboratory as part of the CTSRD Project, with support from the + * UK Higher Education Innovation Fund (HEIF). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MACHINE_FRAME_H_ +#define _MACHINE_FRAME_H_ + +#ifndef _LOCORE + +#include + +/* + * Exception/Trap Stack Frame + */ +#define clockframe trapframe +typedef struct trapframe { + /* Standard Registers */ + register_t tf_ra; + register_t tf_sp; + register_t tf_gp; + register_t tf_tp; + register_t tf_t[7]; + register_t tf_s[12]; + register_t tf_a[8]; + /* Supervisor Trap CSRs */ + register_t tf_sepc; + register_t tf_sstatus; + register_t tf_stval; + register_t tf_scause; + register_t tf_pad; +} trapframe_t; + +/* + * pushed on stack for signal delivery + */ +struct sigframe { + int sf_signum; + struct sigcontext sf_sc; + siginfo_t sf_si; +}; + +/* + * System stack frames. + */ + +/* + * Stack frame inside cpu_switch() + */ +struct switchframe { + register_t sf_s[12]; + register_t sf_ra; + register_t sf_pad; +}; + +struct callframe { + struct callframe *f_frame; + register_t f_ra; +}; + +#endif /* !_LOCORE */ + +#endif /* !_MACHINE_FRAME_H_ */ diff --git sys/arch/loongarch64/include/ieee.h sys/arch/loongarch64/include/ieee.h new file mode 100644 index 00000000000..da4ad3fa74a --- /dev/null +++ sys/arch/loongarch64/include/ieee.h @@ -0,0 +1,148 @@ +/* $OpenBSD: ieee.h,v 1.3 2021/05/12 01:20:52 jsg Exp $ */ +/* $NetBSD: ieee.h,v 1.1 1996/09/30 16:34:25 ws Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ieee.h 8.1 (Berkeley) 6/11/93 + */ + +/* + * ieee.h defines the machine-dependent layout of the machine's IEEE + * floating point. It does *not* define (yet?) any of the rounding + * mode bits, exceptions, and so forth. + */ + +/* + * Define the number of bits in each fraction and exponent. + * + * k k+1 + * Note that 1.0 x 2 == 0.1 x 2 and that denorms are represented + * + * (-exp_bias+1) + * as fractions that look like 0.fffff x 2 . This means that + * + * -126 + * the number 0.10000 x 2 , for instance, is the same as the normalized + * + * -127 -128 + * float 1.0 x 2 . Thus, to represent 2 , we need one leading zero + * + * -129 + * in the fraction; to represent 2 , we need two, and so on. This + * + * (-exp_bias-fracbits+1) + * implies that the smallest denormalized number is 2 + * + * for whichever format we are talking about: for single precision, for + * + * -126 -149 + * instance, we get .00000000000000000000001 x 2 , or 1.0 x 2 , and + * + * -149 == -127 - 23 + 1. + */ +#define SNG_EXPBITS 8 +#define SNG_FRACBITS 23 + +#define DBL_EXPBITS 11 +#define DBL_FRACHBITS 20 +#define DBL_FRACLBITS 32 +#define DBL_FRACBITS 52 + +#define EXT_EXPBITS 15 +#define EXT_FRACHBITS 16 +#define EXT_FRACHMBITS 32 +#define EXT_FRACLMBITS 32 +#define EXT_FRACLBITS 32 +#define EXT_FRACBITS 112 + +#define EXT_IMPLICIT_NBIT + +#define EXT_TO_ARRAY32(p, a) do { \ + (a)[0] = (uint32_t)(p)->ext_fracl; \ + (a)[1] = (uint32_t)(p)->ext_fraclm; \ + (a)[2] = (uint32_t)(p)->ext_frachm; \ + (a)[3] = (uint32_t)(p)->ext_frach; \ +} while (0) + +struct ieee_single { + u_int sng_frac:23; + u_int sng_exp:8; + u_int sng_sign:1; +}; + +struct ieee_double { + u_int dbl_fracl; + u_int dbl_frach:20; + u_int dbl_exp:11; + u_int dbl_sign:1; +}; + +struct ieee_ext { + u_int ext_fracl; + u_int ext_fraclm; + u_int ext_frachm; + u_int ext_frach:16; + u_int ext_exp:15; + u_int ext_sign:1; +}; + +/* + * Floats whose exponent is in [1..INFNAN) (of whatever type) are + * `normal'. Floats whose exponent is INFNAN are either Inf or NaN. + * Floats whose exponent is zero are either zero (iff all fraction + * bits are zero) or subnormal values. + * + * A NaN is a `signalling NaN' if its QUIETNAN bit is clear in its + * high fraction; if the bit is set, it is a `quiet NaN'. + */ +#define SNG_EXP_INFNAN 255 +#define DBL_EXP_INFNAN 2047 +#define EXT_EXP_INFNAN 32767 + +#if 0 +#define SNG_QUIETNAN (1 << 22) +#define DBL_QUIETNAN (1 << 19) +#define EXT_QUIETNAN (1 << 15) +#endif + +/* + * Exponent biases. + */ +#define SNG_EXP_BIAS 127 +#define DBL_EXP_BIAS 1023 +#define EXT_EXP_BIAS 16383 diff --git sys/arch/loongarch64/include/ieeefp.h sys/arch/loongarch64/include/ieeefp.h new file mode 100644 index 00000000000..241803a8d2a --- /dev/null +++ sys/arch/loongarch64/include/ieeefp.h @@ -0,0 +1,25 @@ +/* $OpenBSD: ieeefp.h,v 1.3 2021/04/30 00:25:52 drahn Exp $ */ + +/* + * Based on ieeefp.h written by J.T. Conklin, Apr 28, 1995 + * Public domain. + */ + +#ifndef _MACHINE_IEEEFP_H_ +#define _MACHINE_IEEEFP_H_ + +typedef int fp_except; +#define FP_X_INV 0x10 /* invalid operation exception */ +#define FP_X_DZ 0x08 /* divide-by-zero exception */ +#define FP_X_OFL 0x04 /* overflow exception */ +#define FP_X_UFL 0x02 /* underflow exception */ +#define FP_X_IMP 0x01 /* imprecise (loss of precision) */ + +typedef enum { + FP_RN=0, /* round to nearest representable number */ + FP_RZ=1, /* round to zero (truncate) */ + FP_RM=2, /* round toward negative infinity */ + FP_RP=3 /* round toward positive infinity */ +} fp_rnd; + +#endif /* _MACHINE_IEEEFP_H_ */ diff --git sys/arch/loongarch64/include/intr.h sys/arch/loongarch64/include/intr.h new file mode 100644 index 00000000000..fa46a63a3e8 --- /dev/null +++ sys/arch/loongarch64/include/intr.h @@ -0,0 +1,229 @@ +/* $OpenBSD: intr.h,v 1.10 2025/05/19 02:13:15 jsg Exp $ */ + +/* + * Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se / www.opsycon.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef _MACHINE_INTR_H_ +#define _MACHINE_INTR_H_ + +/* + * The interrupt level ipl is a logical level; per-platform interrupt + * code will turn it into the appropriate hardware interrupt masks + * values. + * + * Interrupt sources on the CPU are kept enabled regardless of the + * current ipl value; individual hardware sources interrupting while + * logically masked are masked on the fly, remembered as pending, and + * unmasked at the first splx() opportunity. + */ +#ifdef _KERNEL + +/* Interrupt priority `levels'; not mutually exclusive. */ +#define IPL_NONE 0 /* nothing */ +#define IPL_SOFTCLOCK 2 /* soft clock interrupts */ +#define IPL_SOFTNET 3 /* soft network interrupts */ +#define IPL_SOFTTTY 4 /* soft terminal interrupts */ +#define IPL_BIO 5 /* block I/O */ +#define IPL_NET 6 /* network */ +#define IPL_TTY 7 /* terminal */ +#define IPL_VM 8 /* memory allocation */ +#define IPL_AUDIO 9 /* audio */ +#define IPL_CLOCK 10 /* clock */ +#define IPL_SCHED IPL_CLOCK +#define IPL_STATCLOCK IPL_CLOCK +#define IPL_HIGH 11 /* everything */ +#define IPL_IPI 12 /* interprocessor interrupt */ +#define NIPL 13 /* number of levels */ + +#define IPL_MPFLOOR IPL_TTY +/* Interrupt priority 'flags'. */ +#define IPL_IRQMASK 0xf /* priority only */ +#define IPL_FLAGMASK 0xf00 /* flags only*/ +#define IPL_MPSAFE 0x100 /* 'mpsafe' interrupt, no kernel lock */ +#define IPL_WAKEUP 0x200 + +/* Interrupt sharing types. */ +#define IST_NONE 0 /* none */ +#define IST_PULSE 1 /* pulsed */ +#define IST_EDGE 2 /* edge-triggered */ +#define IST_LEVEL 3 /* level-triggered */ + +#define IST_LEVEL_LOW IST_LEVEL +#define IST_LEVEL_HIGH 4 +#define IST_EDGE_FALLING IST_EDGE +#define IST_EDGE_RISING 5 +#define IST_EDGE_BOTH 6 + +enum { + IRQ_SOFTWARE_USER, + IRQ_SOFTWARE_SUPERVISOR, + IRQ_SOFTWARE_HYPERVISOR, + IRQ_SOFTWARE_MACHINE, + IRQ_TIMER_USER, + IRQ_TIMER_SUPERVISOR, + IRQ_TIMER_HYPERVISOR, + IRQ_TIMER_MACHINE, + IRQ_EXTERNAL_USER, + IRQ_EXTERNAL_SUPERVISOR, + IRQ_EXTERNAL_HYPERVISOR, + IRQ_EXTERNAL_MACHINE, + INTC_NIRQS +}; + +#define __USE_MI_SOFTINTR + +#include + +#ifndef _LOCORE +#include + +void softintr(int); + +int splraise(int); +int spllower(int); +void splx(int); + +void loongarch_cpu_intr(void *); +void loongarch_do_pending_intr(int); +void loongarch_set_intr_func(int (*raise)(int), int (*lower)(int), + void (*x)(int), void (*setipl)(int)); +void loongarch_set_intr_handler(void (*intr_handle)(void *)); + +struct machine_intr_handle { + struct interrupt_controller *ih_ic; + void *ih_ih; +}; + +struct loongarch_intr_func { + int (*raise)(int); + int (*lower)(int); + void (*x)(int); + void (*setipl)(int); +}; + +extern struct loongarch_intr_func loongarch_intr_func; + +#define splraise(cpl) (loongarch_intr_func.raise(cpl)) +#define _splraise(cpl) (loongarch_intr_func.raise(cpl)) +#define spllower(cpl) (loongarch_intr_func.lower(cpl)) +#define splx(cpl) (loongarch_intr_func.x(cpl)) + +#define splsoftclock() splraise(IPL_SOFTCLOCK) +#define splsoftnet() splraise(IPL_SOFTNET) +#define splsofttty() splraise(IPL_SOFTTTY) +#define splbio() splraise(IPL_BIO) +#define splnet() splraise(IPL_NET) +#define spltty() splraise(IPL_TTY) +#define splvm() splraise(IPL_VM) +#define splaudio() splraise(IPL_AUDIO) +#define splclock() splraise(IPL_CLOCK) +#define splsched() splraise(IPL_SCHED) +#define splstatclock() splraise(IPL_STATCLOCK) +#define splhigh() splraise(IPL_HIGH) + +#define spl0() spllower(IPL_NONE) + +void intr_barrier(void *); + +void loongarch_init_smask(void); /* XXX */ +extern uint32_t loongarch_smask[NIPL]; + +void loongarch_clock_register(void (*)(void), void (*)(u_int), void (*)(int), + void (*)(void)); + +/* + **** interrupt controller structure and routines **** + */ +struct cpu_info; +struct interrupt_controller { + int ic_node; + void *ic_cookie; + void *(*ic_establish)(void *, int *, int, struct cpu_info *, + int (*)(void *), void *, char *); + void *(*ic_establish_msi)(void *, uint64_t *, uint64_t *, int, + struct cpu_info *, int (*)(void *), void *, char *); + void (*ic_disestablish)(void *); + void (*ic_enable)(void *); + void (*ic_disable)(void *); + void (*ic_route)(void *, int, struct cpu_info *); + void (*ic_cpu_enable)(void); + void (*ic_barrier)(void *); + + LIST_ENTRY(interrupt_controller) ic_list; + uint32_t ic_phandle; + uint32_t ic_cells; +}; + +void loongarch_intr_init_fdt(void); +void loongarch_intr_register_fdt(struct interrupt_controller *); +void *loongarch_intr_establish_fdt(int, int, int (*)(void *), + void *, char *); +void *loongarch_intr_establish_fdt_idx(int, int, int, int (*)(void *), + void *, char *); +void *loongarch_intr_establish_fdt_idx_cpu(int, int, int, struct cpu_info *, + int (*)(void *), void *, char *); +void *loongarch_intr_establish_fdt_imap_cpu(int, int *, int, int, + struct cpu_info *, int (*)(void *), void *, char *); +void *loongarch_intr_establish_fdt_msi(int, uint64_t *, uint64_t *, int, + int (*)(void *), void *, char *); +void *loongarch_intr_establish_fdt_msi_cpu(int, uint64_t *, uint64_t *, int, + struct cpu_info *, int (*)(void *), void *, char *); +void loongarch_intr_disestablish_fdt(void *); +void loongarch_intr_enable(void *); +void loongarch_intr_disable(void *); +void loongarch_intr_route(void *, int, struct cpu_info *); +void loongarch_intr_cpu_enable(void); + +#define IPI_NOP 0 +#define IPI_DDB (1 << 0) + +void intr_send_ipi(struct cpu_info *, int); + +#ifdef DIAGNOSTIC +/* + * Although this function is implemented in MI code, it must be in this MD + * header because we don't want this header to include MI includes. + */ +void splassert_fail(int, int, const char *); +extern int splassert_ctl; +void loongarch_splassert_check(int, const char *); +#define splassert(__wantipl) do { \ + if (splassert_ctl > 0) { \ + loongarch_splassert_check(__wantipl, __func__); \ + } \ +} while (0) +#define splsoftassert(wantipl) splassert(wantipl) +#else +#define splassert(wantipl) do { /* nothing */ } while (0) +#define splsoftassert(wantipl) do { /* nothing */ } while (0) +#endif + +#endif /* ! _LOCORE */ + +#endif /* _KERNEL */ + +#endif /* _MACHINE_INTR_H_ */ + diff --git sys/arch/loongarch64/include/kcore.h sys/arch/loongarch64/include/kcore.h new file mode 100644 index 00000000000..ada7476aeda --- /dev/null +++ sys/arch/loongarch64/include/kcore.h @@ -0,0 +1,16 @@ +/* $OpenBSD: kcore.h,v 1.2 2021/05/12 01:20:52 jsg Exp $ */ + +/* public domain */ + +/* Make sure this is larger than DRAM_BLOCKS on all arm-based platforms */ +#define NPHYS_RAM_SEGS 8 + +typedef struct cpu_kcore_hdr { + u_int64_t kernelbase; /* value of KERNEL_BASE */ + u_int64_t kerneloffs; /* offset of kernel in RAM */ + u_int64_t staticsize; /* size of contiguous mapping */ + u_int64_t pmap_kernel_l1; /* pmap_kernel()->pm_l1 */ + u_int64_t pmap_kernel_l2; /* pmap_kernel()->pm_l2 */ + u_int64_t reserved[11]; + phys_ram_seg_t ram_segs[NPHYS_RAM_SEGS]; +} cpu_kcore_hdr_t; diff --git sys/arch/loongarch64/include/limits.h sys/arch/loongarch64/include/limits.h new file mode 100644 index 00000000000..e6e61d9cbdc --- /dev/null +++ sys/arch/loongarch64/include/limits.h @@ -0,0 +1,56 @@ +/* $OpenBSD: limits.h,v 1.2 2021/06/25 19:22:51 matthieu Exp $ */ +/* $NetBSD: limits.h,v 1.4 2003/04/28 23:16:18 bjh21 Exp $ */ + +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)limits.h 7.2 (Berkeley) 6/28/90 + */ + +#ifndef _MACHINE_LIMITS_H_ +#define _MACHINE_LIMITS_H_ + +#include + +#if __POSIX_VISIBLE || __XPG_VISIBLE +#ifndef SIZE_MAX +#define SIZE_MAX ULONG_MAX /* max value for a size_t */ +#endif +#define SSIZE_MAX LONG_MAX /* max value for a ssize_t */ +#endif + +#if __BSD_VISIBLE +#define SIZE_T_MAX ULONG_MAX /* max value for a size_t (historic) */ + +#define UQUAD_MAX (ULONG_MAX) /* max unsigned quad */ +#define QUAD_MAX (LONG_MAX) /* max signed quad */ +#define QUAD_MIN (LONG_MIN) /* min signed quad */ + +#endif /* __BSD_VISIBLE */ + +#endif /* _MACHINE_LIMITS_H_ */ diff --git sys/arch/loongarch64/include/loadfile_machdep.h sys/arch/loongarch64/include/loadfile_machdep.h new file mode 100644 index 00000000000..f2af8d4090c --- /dev/null +++ sys/arch/loongarch64/include/loadfile_machdep.h @@ -0,0 +1,53 @@ +/* $OpenBSD: loadfile_machdep.h,v 1.2 2021/04/23 15:31:12 drahn Exp $ */ +/* $NetBSD: loadfile_machdep.h,v 1.1 1999/04/29 03:17:12 tsubai Exp $ */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define BOOT_ELF +#define ELFSIZE 64 + +#define LOAD_KERNEL (LOAD_ALL & ~LOAD_TEXTA) +#define COUNT_KERNEL (COUNT_ALL & ~COUNT_TEXTA) + +extern u_long efi_loadaddr; +#define LOADADDR(a) (((((u_long)(a)) + offset)&0x3fffffffff) + \ + efi_loadaddr) +#define ALIGNENTRY(a) ((u_long)(a)) +#define READ(f, b, c) read((f), (void *)LOADADDR(b), (c)) +#define BCOPY(s, d, c) memcpy((void *)LOADADDR(d), (void *)(s), (c)) +#define BZERO(d, c) memset((void *)LOADADDR(d), 0, (c)) +#define WARN(a) (void)(printf a, \ + printf((errno ? ": %s\n" : "\n"), \ + strerror(errno))) +#define PROGRESS(a) (void) printf a +#define ALLOC(a) alloc(a) +#define FREE(a, b) free(a, b) + +void run_loadfile(uint64_t *, int); diff --git sys/arch/loongarch64/include/loongarchreg..diy sys/arch/loongarch64/include/loongarchreg..diy new file mode 100644 index 00000000000..689faab2cf3 --- /dev/null +++ sys/arch/loongarch64/include/loongarchreg..diy @@ -0,0 +1,255 @@ +/* $OpenBSD: loongarchreg.h,v 1.8 2026/07/24 10:51:00 kettenis Exp $ */ + +/*- + * Copyright (c) 2019 Brian Bamsch + * Copyright (c) 2015-2017 Ruslan Bukin + * All rights reserved. + * + * Portions of this software were developed by SRI International and the + * University of Cambridge Computer Laboratory under DARPA/AFRL contract + * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. + * + * Portions of this software were developed by the University of Cambridge + * Computer Laboratory as part of the CTSRD Project, with support from the + * UK Higher Education Innovation Fund (HEIF). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MACHINE_LOONGARCHREG_H_ +#define _MACHINE_LOONGARCHREG_H_ + +#define EXCP_SHIFT 0 +#define EXCP_MASK (0xf << EXCP_SHIFT) +#define EXCP_MISALIGNED_FETCH 0 +#define EXCP_FAULT_FETCH 1 +#define EXCP_ILLEGAL_INSTRUCTION 2 +#define EXCP_BREAKPOINT 3 +#define EXCP_MISALIGNED_LOAD 4 +#define EXCP_FAULT_LOAD 5 +#define EXCP_MISALIGNED_STORE 6 +#define EXCP_FAULT_STORE 7 +#define EXCP_USER_ECALL 8 +#define EXCP_SUPERVISOR_ECALL 9 +#define EXCP_HYPERVISOR_ECALL 10 +#define EXCP_MACHINE_ECALL 11 +#define EXCP_INST_PAGE_FAULT 12 +#define EXCP_LOAD_PAGE_FAULT 13 +#define EXCP_STORE_PAGE_FAULT 15 +#define EXCP_INTR (1ULL << 63) + +#define MSTATUS_UIE (1 << 0) +#define MSTATUS_SIE (1 << 1) +#define MSTATUS_MIE (1 << 3) +#define MSTATUS_UPIE (1 << 4) +#define MSTATUS_SPIE (1 << 5) +#define MSTATUS_MPIE (1 << 7) +#define MSTATUS_SPP (1 << 8) +#define MSTATUS_VS_SHIFT 9 +#define MSTATUS_VS_MASK (0x3 << MSTATUS_VS_SHIFT) +#define MSTATUS_MPP_SHIFT 11 +#define MSTATUS_MPP_MASK (0x3 << MSTATUS_MPP_SHIFT) +#define MSTATUS_FS_SHIFT 13 +#define MSTATUS_FS_MASK (0x3 << MSTATUS_FS_SHIFT) +#define MSTATUS_XS_SHIFT 15 +#define MSTATUS_XS_MASK (0x3 << MSTATUS_XS_SHIFT) +#define MSTATUS_MPRV (1 << 17) +#define MSTATUS_SUM (1 << 18) +#define MSTATUS_MXR (1 << 19) +#define MSTATUS_TVM (1 << 20) +#define MSTATUS_TW (1 << 21) +#define MSTATUS_TSR (1 << 22) +#define MSTATUS_UXL_SHIFT 32 +#define MSTATUS_UXL_MASK (0x3ULL << MSTATUS_UXL_SHIFT) +#define MSTATUS_SXL_SHIFT 34 +#define MSTATUS_SXL_MASK (0x3ULL << MSTATUS_SXL_SHIFT) +#define MSTATUS_SD (1ULL << (MXLEN - 1)) + +#define SSTATUS_UIE (1 << 0) +#define SSTATUS_SIE (1 << 1) +#define SSTATUS_UPIE (1 << 4) +#define SSTATUS_SPIE (1 << 5) +#define SSTATUS_SPP (1 << 8) +#define SSTATUS_VS_SHIFT 9 +#define SSTATUS_VS_MASK (0x3 << SSTATUS_VS_SHIFT) +#define SSTATUS_VS_OFF (0x0 << SSTATUS_VS_SHIFT) +#define SSTATUS_VS_INITIAL (0x1 << SSTATUS_VS_SHIFT) +#define SSTATUS_VS_CLEAN (0x2 << SSTATUS_VS_SHIFT) +#define SSTATUS_VS_DIRTY (0x3 << SSTATUS_VS_SHIFT) +#define SSTATUS_FS_SHIFT 13 +#define SSTATUS_FS_MASK (0x3 << SSTATUS_FS_SHIFT) +#define SSTATUS_FS_OFF (0x0 << SSTATUS_FS_SHIFT) +#define SSTATUS_FS_INITIAL (0x1 << SSTATUS_FS_SHIFT) +#define SSTATUS_FS_CLEAN (0x2 << SSTATUS_FS_SHIFT) +#define SSTATUS_FS_DIRTY (0x3 << SSTATUS_FS_SHIFT) +#define SSTATUS_XS_SHIFT 15 +#define SSTATUS_XS_MASK (0x3 << SSTATUS_XS_SHIFT) +#define SSTATUS_SUM (1 << 18) +#define SSTATUS_MXR (1 << 19) +#define SSTATUS_UXL_SHIFT 32 +#define SSTATUS_UXL_MASK (0x3ULL << SSTATUS_UXL_SHIFT) +#define SSTATUS_SD (1ULL << (SXLEN - 1)) + +#define USTATUS_UIE (1 << 0) +#define USTATUS_UPIE (1 << 4) + +#define MSTATUS_PRV_U 0 /* user */ +#define MSTATUS_PRV_S 1 /* supervisor */ +#define MSTATUS_PRV_H 2 /* hypervisor */ +#define MSTATUS_PRV_M 3 /* machine */ + +#define MIE_USIE (1 << 0) +#define MIE_SSIE (1 << 1) +#define MIE_MSIE (1 << 3) +#define MIE_UTIE (1 << 4) +#define MIE_STIE (1 << 5) +#define MIE_MTIE (1 << 7) +#define MIE_UEIE (1 << 8) +#define MIE_SEIE (1 << 9) +#define MIE_MEIE (1 << 11) + +#define MIP_USIP (1 << 0) +#define MIP_SSIP (1 << 1) +#define MIP_MSIP (1 << 3) +#define MIP_UTIP (1 << 4) +#define MIP_STIP (1 << 5) +#define MIP_MTIP (1 << 7) +#define MIP_UEIP (1 << 8) +#define MIP_SEIP (1 << 9) +#define MIP_MEIP (1 << 11) + +#define SIE_USIE (1 << 0) +#define SIE_SSIE (1 << 1) +#define SIE_UTIE (1 << 4) +#define SIE_STIE (1 << 5) +#define SIE_UEIE (1 << 8) +#define SIE_SEIE (1 << 9) + +#define SIP_USIP (1 << 0) +#define SIP_SSIP (1 << 1) +#define SIP_UTIP (1 << 4) +#define SIP_STIP (1 << 5) +#define SIP_UEIP (1 << 8) +#define SIP_SEIP (1 << 9) + +#define UIE_USIE (1 << 0) +#define UIE_UTIE (1 << 4) +#define UIE_UEIE (1 << 8) + +#define UIP_USIP (1 << 0) +#define UIP_UTIP (1 << 4) +#define UIP_UEIP (1 << 8) + +#define STOPEI_ID_MASK (0x7ff << STOPEI_ID_SHIFT) +#define STOPEI_ID_SHIFT 16 + +#define PPN(pa) ((pa) >> PAGE_SHIFT) +#define SATP_PPN_SHIFT 0 +#define SATP_PPN_MASK (0xfffffffffffULL << SATP_PPN_SHIFT) +#define SATP_PPN(satp) (((satp) & SATP_PPN_MASK) >> SATP_PPN_SHIFT) +#define SATP_FORMAT_PPN(ppn) (((uint64_t)(ppn) << SATP_PPN_SHIFT) & SATP_PPN_MASK) +#define SATP_ASID_SHIFT 44 +#define SATP_ASID_MASK (0xffffULL << SATP_ASID_SHIFT) +#define SATP_ASID(satp) (((satp) & SATP_ASID_MASK) >> SATP_ASID_SHIFT) +#define SATP_FORMAT_ASID(asid) (((uint64_t)(asid) << SATP_ASID_SHIFT) & SATP_ASID_MASK) +#define SATP_MODE_SHIFT 60 +#define SATP_MODE_MASK (0xfULL << SATP_MODE_SHIFT) +#define SATP_MODE(mode) (((satp) & SATP_MODE_MASK) >> SATP_MODE_SHIFT) + +#define SATP_MODE_SV39 (8ULL << SATP_MODE_SHIFT) +#define SATP_MODE_SV48 (9ULL << SATP_MODE_SHIFT) +#define SATP_MODE_SV57 (10ULL << SATP_MODE_SHIFT) +#define SATP_MODE_SV64 (11ULL << SATP_MODE_SHIFT) + +/** + * As of RISC-V Machine ISA v1.11, the XLEN can vary between + * Machine, Supervisor, and User modes. The Machine XLEN (MXLEN) + * is resolved from the MXL field of the 'misa' CSR. The + * Supervisor XLEN (SXLEN) and User XLEN (UXLEN) are resolved + * from the SXL and UXL fields of the 'mstatus' CSR, respectively. + * + * The Machine XLEN is reset to the widest supported ISA variant + * at machine reset. For now, assume that all modes will always + * use the same, static XLEN of 64 bits. + */ +#define XLEN 64 +#define XLEN_BYTES (XLEN / 8) +#define MXLEN XLEN +#define SXLEN XLEN +#define UXLEN XLEN +#define INSN_SIZE 4 +#define INSN_C_SIZE 2 + +/* + * The maximum vector register length in bits (VLEN) is 65,536, as + * documented in section 31.2 of the The RISC-V Instruction Set Manual, + * Volume I: Unprivileged Architecture (Version 20260120). + */ +#define VLEN_MAX 65536 +#define VLEN_BYTES_MAX (VLEN_MAX / 8) + +// Check if val can fit in the CSR immediate form +#define CSR_ZIMM(val) \ + (__builtin_constant_p(val) && ((u_long)(val) < 32)) + +#define csr_swap(csr, val) \ +({ u_long ret; \ + if (CSR_ZIMM(val)) \ + __asm volatile("csrrwi %0, " #csr ", %1" \ + : "=r" (ret) : "i" (val)); \ + else \ + __asm volatile("csrrw %0, " #csr ", %1" \ + : "=r" (ret) : "r" (val)); \ + ret; \ +}) + +#define csr_write(csr, val) \ +({ if (CSR_ZIMM(val)) \ + __asm volatile("csrwi " #csr ", %0" :: "i" (val)); \ + else \ + __asm volatile("csrw " #csr ", %0" :: "r" (val)); \ +}) + +#define csr_set(csr, val) \ +({ if (CSR_ZIMM(val)) \ + __asm volatile("csrsi " #csr ", %0" :: "i" (val)); \ + else \ + __asm volatile("csrs " #csr ", %0" :: "r" (val)); \ +}) + +#define csr_clear(csr, val) \ +({ if (CSR_ZIMM(val)) \ + __asm volatile("csrci " #csr ", %0" :: "i" (val)); \ + else \ + __asm volatile("csrc " #csr ", %0" :: "r" (val)); \ +}) + +#define csr_read(csr) \ +({ u_long val; \ + __asm volatile("csrrd %0, " #csr : "=r" (val) : "i" (csr)); \ + val; \ +}) + +#endif /* !_MACHINE_LOONGARCHREG_H_ */ diff --git sys/arch/loongarch64/include/loongarchreg.h sys/arch/loongarch64/include/loongarchreg.h new file mode 100644 index 00000000000..589cd9d592e --- /dev/null +++ sys/arch/loongarch64/include/loongarchreg.h @@ -0,0 +1,150 @@ +/* $OpenBSD: loongarchreg.h,v 1.8 2026/07/24 10:51:00 kettenis Exp $ */ + +/*- + * Copyright (c) 2026 Your Name / OpenBSD Port + * Copyright (c) 2019 Brian Bamsch + * Copyright (c) 2015-2017 Ruslan Bukin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. + */ + +#ifndef _MACHINE_LOONGARCHREG_H_ +#define _MACHINE_LOONGARCHREG_H_ + +#define LOONGARCH_CSR_TCFG 0x41 +#define LOONGARCH_CSR_TVAL 0x42 +#define LOONGARCH_CSR_TICLR 0x44 + +#define LOONGARCH_TCFG_EN (1UL << 0) +#define LOONGARCH_TCFG_PERIODIC (1UL << 1) + + +/* + * LoongArch Exception Codes (ECFG / ESTAT) + */ +#define EXCP_INT 0 /* Interrupt */ +#define EXCP_PIL 1 /* Page Invalid Exception for Load */ +#define EXCP_PIS 2 /* Page Invalid Exception for Store */ +#define EXCP_PIF 3 /* Page Invalid Exception for Fetch */ +#define EXCP_PME 4 /* Page Modified Exception */ +#define EXCP_PNR 5 /* Page Not Readable Exception */ +#define EXCP_PNX 6 /* Page Not Executable Exception */ +#define EXCP_PPI 7 /* Page Privilege Illegal Exception */ +#define EXCP_ADE 8 /* Address Error Exception */ +#define EXCP_ALE 9 /* Address Alignment Fault */ +#define EXCP_SYS 11 /* System Call (Syscall) */ +#define EXCP_BRK 12 /* Breakpoint Exception */ +#define EXCP_INE 13 /* Instruction Non-existent (Illegal) */ +#define EXCP_IPE 14 /* Instruction Privilege Illegal */ +#define EXCP_FPD 15 /* Floating-Point Disabled */ +#define EXCP_FPE 18 /* Floating-Point Exception */ + +#define EXCP_MASK 0x3f + +/* + * CSR CRMD (Current Mode Register) Layout + */ +#define LOONGARCH_CSR_CRMD 0x0 +#define CRMD_PLV_SHIFT 0 +#define CRMD_PLV_MASK (0x3 << CRMD_PLV_SHIFT) +#define CRMD_PLV_KERNEL (0x0 << CRMD_PLV_SHIFT) +#define CRMD_PLV_USER (0x3 << CRMD_PLV_SHIFT) +#define CRMD_IE (1 << 2) /* Interrupt Enable */ +#define CRMD_DA (1 << 3) /* Direct Address Translation */ +#define CRMD_PG (1 << 4) /* Paged Address Translation */ + +/* SSTATUS_SIE compatibility definition mapping for machine/cpu.h */ +#define SSTATUS_SIE CRMD_IE +#define SIE_STIE (1 << 11) + +/* + * CSR PRMD (Pre-status Mode Register) Layout + */ +#define LOONGARCH_CSR_PRMD 0x1 +#define PRMD_PPLV_SHIFT 0 +#define PRMD_PPLV_MASK (0x3 << PRMD_PPLV_SHIFT) +#define PRMD_PIE (1 << 2) /* Pre-Interrupt Enable */ + +#define SSTATUS_SPP PRMD_PPLV_MASK /* Used to verify user mode */ + +/* + * CSR ECFG / ESTAT (Interrupt Masking & Status flags) + */ +#define LOONGARCH_CSR_ECFG 0x4 +#define LOONGARCH_CSR_ESTAT 0x5 + +/* + * CSR PGDL / PGDH (Page Global Directory Pointers) + */ +#define LOONGARCH_CSR_PGDL 0x1c /* Kernel/Lower base mapping */ +#define LOONGARCH_CSR_PGDH 0x1d /* User/Higher base mapping */ +#define LOONGARCH_CSR_PGD 0x1e + +/* + * CSR STIME (Stable Timer Counter) + */ +#define LOONGARCH_CSR_STIME 0x40 + +/* Architectural basic sizes */ +#define XLEN 64 +#define XLEN_BYTES (XLEN / 8) +#define INSN_SIZE 4 + +/* + * LoongArch64 Inline Assembly CSR Access Mechanisms + * + * LoongArch utilizes: + * - csrrd : Read from a CSR + * - csrwr : Write to a CSR and return the old value (Atomic Swap) + * - csrxchg : Atomically alter bits matching a specific mask value + */ + +/* Reads a control register */ +#define csr_read(csr) \ +({ \ + unsigned long val; \ + __asm volatile("csrrd %0, %1" : "=r" (val) : "i" (csr)); \ + val; \ +}) + +/* Writes to a control register */ +#define csr_write(csr, val) \ +({ \ + __asm volatile("csrwr %0, %1" : "+r" (val) : "i" (csr)); \ +}) + +/* Exchanges/swaps a control register, returning the old contents */ +#define csr_swap(csr, val) \ +({ \ + __asm volatile("csrwr %0, " #csr : "+r" (val)); \ + val; \ +}) + +/* Sets explicit bits within a CSR using a bit mask */ +#define csr_set(csr, mask) \ +({ \ + __asm volatile("csrxchg $zero, %0, %1" : : "r" (mask), "i" (mask) : "memory"); \ +}) + +/* Clears explicit bits within a CSR using a bit mask */ +#define csr_clear(csr, mask) \ +({ \ + unsigned long val; \ + __asm volatile("csrxchg %0, %1, " #csr \ + : "+r" (val) : "r" (mask)); \ +}) + +#endif /* !_MACHINE_LOONGARCHREG_H_ */ diff --git sys/arch/loongarch64/include/mplock.h sys/arch/loongarch64/include/mplock.h new file mode 100644 index 00000000000..565e4fe7bbf --- /dev/null +++ sys/arch/loongarch64/include/mplock.h @@ -0,0 +1,10 @@ +/* $OpenBSD: mplock.h,v 1.1 2021/06/27 20:36:57 kettenis Exp $ */ + +/* public domain */ + +#ifndef _MACHINE_MPLOCK_H_ +#define _MACHINE_MPLOCK_H_ + +#define __USE_MI_MPLOCK + +#endif /* !_MACHINE_MPLOCK_H */ diff --git sys/arch/loongarch64/include/mutex.h sys/arch/loongarch64/include/mutex.h new file mode 100644 index 00000000000..8b2c0cefe5b --- /dev/null +++ sys/arch/loongarch64/include/mutex.h @@ -0,0 +1,3 @@ +/* $OpenBSD: mutex.h,v 1.1 2021/04/23 02:42:16 drahn Exp $ */ + +#define __USE_MI_MUTEX diff --git sys/arch/loongarch64/include/openpromio.h sys/arch/loongarch64/include/openpromio.h new file mode 100644 index 00000000000..c3f33087240 --- /dev/null +++ sys/arch/loongarch64/include/openpromio.h @@ -0,0 +1,57 @@ +/* $OpenBSD: openpromio.h,v 1.1 2021/04/23 12:01:03 jsg Exp $ */ +/* $NetBSD: openpromio.h,v 1.1.1.1 1998/06/20 04:58:52 eeh Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)openpromio.h 8.1 (Berkeley) 6/11/93 + */ + +struct opiocdesc { + int op_nodeid; /* passed or returned node id */ + int op_namelen; /* length of op_name */ + char *op_name; /* pointer to field name */ + int op_buflen; /* length of op_buf (value-result) */ + char *op_buf; /* pointer to field value */ +}; + +#define OPIOCGET _IOWR('O', 1, struct opiocdesc) /* get openprom field */ +#define OPIOCSET _IOW('O', 2, struct opiocdesc) /* set openprom field */ +#define OPIOCNEXTPROP _IOWR('O', 3, struct opiocdesc) /* get next property */ +#define OPIOCGETOPTNODE _IOR('O', 4, int) /* get openprom field */ +#define OPIOCGETNEXT _IOWR('O', 5, int) /* get next node of node */ +#define OPIOCGETCHILD _IOWR('O', 6, int) /* get first child of node */ diff --git sys/arch/loongarch64/include/param.h sys/arch/loongarch64/include/param.h new file mode 100644 index 00000000000..1047fc0f037 --- /dev/null +++ sys/arch/loongarch64/include/param.h @@ -0,0 +1,78 @@ +/* $OpenBSD: param.h,v 1.7 2025/07/07 18:33:37 kettenis Exp $ */ + +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MACHINE_PARAM_H_ +#define _MACHINE_PARAM_H_ + +#ifdef _KERNEL +#ifndef _LOCORE +#include +#endif +#endif + +#define _MACHINE loongarch64 +#define MACHINE "loongarch64" +#define _MACHINE_ARCH loongarch64 +#define MACHINE_ARCH "loongarch64" +#define MID_MACHINE MID_LOONGARCH64 + +#define PAGE_SHIFT 12 +#define PAGE_SIZE (1 << PAGE_SHIFT) +#define PAGE_MASK (PAGE_SIZE - 1) + +#ifdef _KERNEL + +#define NBPG PAGE_SIZE /* bytes/page */ +#define PGSHIFT PAGE_SHIFT /* LOG2(PAGE_SIZE) */ +#define PGOFSET PAGE_MASK /* byte offset into page */ + +#define UPAGES 6 /* pages of u-area */ +#define USPACE (UPAGES * PAGE_SIZE) /* total size of u-area */ +#define USPACE_ALIGN 0 /* u-area alignment 0-none */ +#define __HAVE_USPACE_GUARD + +#define NMBCLUSTERS (64 * 1024) /* max cluster allocation */ + +#ifndef MSGBUFSIZE +#define MSGBUFSIZE (16 * PAGE_SIZE) /* default message buffer size */ +#endif + +#define STACKALIGNBYTES (16 - 1) +#define STACKALIGN(p) ((u_long)(p) &~ STACKALIGNBYTES) + +#define __HAVE_FDT + +#endif /* _KERNEL */ + +#endif /* _MACHINE_PARAM_H_ */ diff --git sys/arch/loongarch64/include/pcb.h sys/arch/loongarch64/include/pcb.h new file mode 100644 index 00000000000..f1d4fca53ef --- /dev/null +++ sys/arch/loongarch64/include/pcb.h @@ -0,0 +1,43 @@ +/* $OpenBSD: pcb.h,v 1.5 2026/05/09 17:38:50 jsing Exp $ */ + +/* + * Copyright (c) 2016 Dale Rahn + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef _MACHINE_PCB_H_ +#define _MACHINE_PCB_H_ + +#include +#include + +struct trapframe; + +/* + * Warning certain fields must be within 256 bytes of the beginning + * of this structure. + */ +struct pcb { + u_int pcb_flags; +#define PCB_FPU 0x00000001 /* Process had FPU initialized */ +#define PCB_SINGLESTEP 0x00000002 /* Single step process */ +#define PCB_VECTOR 0x00000004 /* Process had vector initialized */ + struct trapframe *pcb_tf; + + register_t pcb_sp; /* stack pointer of switchframe */ + + caddr_t pcb_onfault; /* On fault handler */ + struct fpreg pcb_fpstate; /* Floating Point state */ + struct vreg *pcb_vstate; /* Vector state */ +}; +#endif /* _MACHINE_PCB_H_ */ diff --git sys/arch/loongarch64/include/pci_machdep.h sys/arch/loongarch64/include/pci_machdep.h new file mode 100644 index 00000000000..2e9d1b55225 --- /dev/null +++ sys/arch/loongarch64/include/pci_machdep.h @@ -0,0 +1,145 @@ +/* $OpenBSD: pci_machdep.h,v 1.13 2025/01/23 11:24:34 kettenis Exp $ */ + +/* + * Copyright (c) 2003-2004 Opsycon AB (www.opsycon.se / www.opsycon.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +typedef struct machine_pci_chipset *pci_chipset_tag_t; +typedef uint64_t pcitag_t; + +#define PCITAG_NODE(x) ((x) >> 32) +#define PCITAG_OFFSET(x) ((x) & 0xffffffff) + +/* Supported interrupt types. */ +#define PCI_NONE 0 +#define PCI_INTX 1 +#define PCI_MSI 2 +#define PCI_MSIX 3 + +typedef struct { + pci_chipset_tag_t ih_pc; + pcitag_t ih_tag; + int ih_intrpin; + int ih_type; + bus_dma_tag_t ih_dmat; +} pci_intr_handle_t; + +struct pci_attach_args; + +/* + * Machine-specific PCI structure and type definitions. + * NOT TO BE USED DIRECTLY BY MACHINE INDEPENDENT CODE. + */ +struct machine_pci_chipset { + void *pc_conf_v; + void (*pc_attach_hook)(struct device *, + struct device *, struct pcibus_attach_args *); + int (*pc_bus_maxdevs)(void *, int); + pcitag_t (*pc_make_tag)(void *, int, int, int); + void (*pc_decompose_tag)(void *, pcitag_t, int *, + int *, int *); + int (*pc_conf_size)(void *, pcitag_t); + pcireg_t (*pc_conf_read)(void *, pcitag_t, int); + void (*pc_conf_write)(void *, pcitag_t, int, pcireg_t); + int (*pc_probe_device_hook)(void *, struct pci_attach_args *); + + void *pc_intr_v; + int (*pc_intr_map)(struct pci_attach_args *, + pci_intr_handle_t *); + int (*pc_intr_map_msi)(struct pci_attach_args *, + pci_intr_handle_t *); + int (*pc_intr_map_msivec)(struct pci_attach_args *, + int, pci_intr_handle_t *); + int (*pc_intr_map_msix)(struct pci_attach_args *, + int, pci_intr_handle_t *); + const char *(*pc_intr_string)(void *, pci_intr_handle_t); + void *(*pc_intr_establish)(void *, pci_intr_handle_t, + int, struct cpu_info *, int (*)(void *), void *, + char *); + void (*pc_intr_disestablish)(void *, void *); +}; + +/* + * Functions provided to machine-independent PCI code. + */ +#define pci_attach_hook(p, s, pba) \ + (*(pba)->pba_pc->pc_attach_hook)((p), (s), (pba)) +#define pci_bus_maxdevs(c, b) \ + (*(c)->pc_bus_maxdevs)((c)->pc_conf_v, (b)) +#define pci_make_tag(c, b, d, f) \ + (*(c)->pc_make_tag)((c)->pc_conf_v, (b), (d), (f)) +#define pci_decompose_tag(c, t, bp, dp, fp) \ + (*(c)->pc_decompose_tag)((c)->pc_conf_v, (t), (bp), (dp), (fp)) +#define pci_conf_size(c, t) \ + (*(c)->pc_conf_size)((c)->pc_conf_v, (t)) +#define pci_conf_read(c, t, r) \ + (*(c)->pc_conf_read)((c)->pc_conf_v, (t), (r)) +#define pci_conf_write(c, t, r, v) \ + (*(c)->pc_conf_write)((c)->pc_conf_v, (t), (r), (v)) +#define pci_probe_device_hook(c, a) \ + (*(c)->pc_probe_device_hook)((c)->pc_conf_v, (a)) +#define pci_intr_map(c, ihp) \ + (*(c)->pa_pc->pc_intr_map)((c), (ihp)) +#define pci_intr_map_msi(c, ihp) \ + (*(c)->pa_pc->pc_intr_map_msi)((c), (ihp)) +#define pci_intr_map_msivec(c, vec, ihp) \ + (*(c)->pa_pc->pc_intr_map_msivec)((c), (vec), (ihp)) +#define pci_intr_map_msix(c, vec, ihp) \ + (*(c)->pa_pc->pc_intr_map_msix)((c), (vec), (ihp)) +#define pci_intr_string(c, ih) \ + (*(c)->pc_intr_string)((c)->pc_intr_v, (ih)) +#define pci_intr_establish(c, ih, l, h, a, nm) \ + (*(c)->pc_intr_establish)((c)->pc_intr_v, (ih), (l), NULL, (h), (a),\ + (nm)) +#define pci_intr_establish_cpu(c, ih, l, ci, h, a, nm) \ + (*(c)->pc_intr_establish)((c)->pc_intr_v, (ih), (l), (ci), (h), (a),\ + (nm)) +#define pci_intr_disestablish(c, iv) \ + (*(c)->pc_intr_disestablish)((c)->pc_intr_v, (iv)) + +#define pci_min_powerstate(c, t) (PCI_PMCSR_STATE_D3) +#define pci_set_powerstate_md(c, t, s, p) + +#define pci_dev_postattach(a, b) + +void pci_mcfg_init(bus_space_tag_t, bus_addr_t, int, int, int); +pci_chipset_tag_t pci_lookup_segment(int, int); + +int pci_intr_enable_msivec(struct pci_attach_args *, int); + +void pci_msi_enable(pci_chipset_tag_t, pcitag_t, bus_addr_t, uint32_t); +void pci_msix_enable(pci_chipset_tag_t, pcitag_t, bus_space_tag_t, + int, bus_addr_t, uint32_t); +int _pci_intr_map_msi(struct pci_attach_args *, pci_intr_handle_t *); +int _pci_intr_map_msivec(struct pci_attach_args *, int, + pci_intr_handle_t *); +int _pci_intr_map_msix(struct pci_attach_args *, int, pci_intr_handle_t *); + +#define __HAVE_PCI_MSIX + +int pci_msix_table_map(pci_chipset_tag_t, pcitag_t, + bus_space_tag_t, bus_space_handle_t *); +void pci_msix_table_unmap(pci_chipset_tag_t, pcitag_t, + bus_space_tag_t, bus_space_handle_t); diff --git sys/arch/loongarch64/include/pmap.h sys/arch/loongarch64/include/pmap.h new file mode 100644 index 00000000000..cdc3ff7c0e6 --- /dev/null +++ sys/arch/loongarch64/include/pmap.h @@ -0,0 +1,136 @@ +/* $OpenBSD: pmap.h,v 1.15 2026/04/05 11:48:17 kettenis Exp $ */ + +/* + * Copyright (c) 2019-2020 Brian Bamsch + * Copyright (c) 2008,2009,2014 Dale Rahn + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef _MACHINE_PMAP_H_ +#define _MACHINE_PMAP_H_ + +#ifndef _LOCORE +#include +#include +#include +#endif + + +/* V->P mapping data */ +// XXX Only targeting compatibility with SV39 +#define VP_IDX0_CNT 512 +#define VP_IDX0_MASK (VP_IDX0_CNT-1) +#define VP_IDX0_POS 39 +#define VP_IDX1_CNT 512 +#define VP_IDX1_MASK (VP_IDX1_CNT-1) +#define VP_IDX1_POS 30 +#define VP_IDX2_CNT 512 +#define VP_IDX2_MASK (VP_IDX2_CNT-1) +#define VP_IDX2_POS 21 +#define VP_IDX3_CNT 512 +#define VP_IDX3_MASK (VP_IDX3_CNT-1) +#define VP_IDX3_POS 12 + +/* cache flags */ +// XXX These are duplicated from arm64 and may need some reworking +#define PMAP_CACHE_CI (PMAP_MD0) /* cache inhibit */ +#define PMAP_CACHE_WB (PMAP_MD1) /* writeback */ +#define PMAP_CACHE_DEV (PMAP_MD2) /* device mapping */ +#define PMAP_CACHE_BITS (PMAP_MD0|PMAP_MD1|PMAP_MD2) + +#define PTED_VA_MANAGED_M (PMAP_MD3) +#define PTED_VA_WIRED_M (PMAP_MD3 << 1) + +#if defined(_KERNEL) && !defined(_LOCORE) +/* + * Pmap stuff + */ + +typedef struct pmap *pmap_t; + +struct pmap { + struct mutex pm_mtx; + union { + // XXX Sv48 not yet supported + // XXX Consider inverting Lx + struct pmapvp1 *l1; /* virtual to physical table 3 lvl */ + } pm_vp; + uint64_t pm_satp; + int pm_privileged; + int pm_refs; /* ref count */ + struct pmap_statistics pm_stats; /* pmap statistics */ +}; + +#define PMAP_PA_MASK ~((paddr_t)PAGE_MASK) /* to remove the flags */ +#define PMAP_NOCACHE 0x1 /* non-cacheable memory */ +#define PMAP_DEVICE 0x2 /* device memory */ + +extern uint64_t pmap_pma; +extern uint64_t pmap_nc; +extern uint64_t pmap_io; + +#define PG_PMAP_MOD PG_PMAP0 +#define PG_PMAP_REF PG_PMAP1 +#define PG_PMAP_EXE PG_PMAP2 + +// [NCPUS] +extern paddr_t zero_page; +extern paddr_t copy_src_page; +extern paddr_t copy_dst_page; + +void pagezero(vaddr_t); + +extern struct pmap kernel_pmap_; +#define pmap_kernel() (&kernel_pmap_) +#define pmap_resident_count(pmap) ((pmap)->pm_stats.resident_count) +#define pmap_wired_count(pmap) ((pmap)->pm_stats.wired_count) + +vaddr_t pmap_bootstrap(long kvo, paddr_t lpt1, + vaddr_t kernelstart, vaddr_t kernelend, + paddr_t memstart, paddr_t memend); +void pmap_kenter_cache(vaddr_t va, paddr_t pa, vm_prot_t prot, int cacheable); +void pmap_page_ro(pmap_t pm, vaddr_t va, vm_prot_t prot); + +paddr_t pmap_steal_avail(size_t size, int align, void **kva); +void pmap_avail_fixup(void); +void pmap_physload_avail(void); + +#define PMAP_GROWKERNEL + +#define PHYS_TO_DMAP(pa) ((pa) - dmap_phys_base + DMAP_MIN_ADDRESS) + +struct pv_entry; + +/* investigate */ +#define pmap_unuse_final(p) do { /* nothing */ } while (0) +int pmap_fault_fixup(pmap_t, vaddr_t, vm_prot_t); +void pmap_postinit(void); +void pmap_init_percpu(void); + +#define __HAVE_PMAP_POPULATE + +#endif /* _KERNEL && !_LOCORE */ + +#ifndef _LOCORE +struct vm_page_md { + struct mutex pv_mtx; + LIST_HEAD(,pte_desc) pv_list; +}; + +#define VM_MDPAGE_INIT(pg) do { \ + mtx_init(&(pg)->mdpage.pv_mtx, IPL_VM); \ + LIST_INIT(&((pg)->mdpage.pv_list)); \ +} while (0) +#endif /* _LOCORE */ + +#endif /* _MACHINE_PMAP_H_ */ diff --git sys/arch/loongarch64/include/proc.h sys/arch/loongarch64/include/proc.h new file mode 100644 index 00000000000..14f6b2de9d9 --- /dev/null +++ sys/arch/loongarch64/include/proc.h @@ -0,0 +1,45 @@ +/* $OpenBSD: proc.h,v 1.2 2021/05/12 01:20:52 jsg Exp $ */ +/* $NetBSD: proc.h,v 1.1 2003/04/26 18:39:46 fvdl Exp $ */ + +/* + * Copyright (c) 1991 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)proc.h 7.1 (Berkeley) 5/15/91 + */ + +#ifndef _MACHINE_PROC_H_ +#define _MACHINE_PROC_H_ + +/* + * Machine-dependent part of the proc structure for loongarch64. + */ +struct mdproc { + volatile int md_astpending; +}; + +#endif /* _MACHINE_PROC_H_ */ diff --git sys/arch/loongarch64/include/profile.h sys/arch/loongarch64/include/profile.h new file mode 100644 index 00000000000..8e8117829d2 --- /dev/null +++ sys/arch/loongarch64/include/profile.h @@ -0,0 +1,100 @@ +/* $OpenBSD: profile.h,v 1.4 2021/05/21 16:49:57 deraadt Exp $ */ + +/* + * Copyright (c) 2015 Dale Rahn + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define _MCOUNT_DECL void _mcount + +#define MCOUNT_ASM_NAME "__mcount" + +#ifdef __PIC__ +#define PLTSYM "" /* XXX -aarch64 defaults to PLT? */ +#else +#define PLTSYM "" +#endif + +#define MCOUNT \ +__asm__ (".text \n;" \ + ".align 3 \n;" \ + ".globl " MCOUNT_ASM_NAME " \n;" \ + ".type " MCOUNT_ASM_NAME ",@function \n;" \ + MCOUNT_ASM_NAME ": \n;" \ + " addi.d $sp, $sp, -176 \n" \ + " st.d $fp, $sp, 0 \n" \ + " st.d $ra, $sp, 8 \n" \ + " st.d $s0, $sp, 24 \n" \ + " st.d $a0, $sp, 32 \n" \ + " st.d $a1, $sp, 40 \n" \ + " st.d $a2, $sp, 48 \n" \ + " st.d $a3, $sp, 56 \n" \ + " st.d $a4, $sp, 64 \n" \ + " st.d $a5, $sp, 72 \n" \ + " st.d $a6, $sp, 80 \n" \ + " st.d $a7, $sp, 88 \n" \ + " st.d $s1, $sp, 96 \n" \ + " st.d $s2, $sp, 104 \n" \ + " st.d $s3, $sp, 112 \n" \ + " st.d $s4, $sp, 120 \n" \ + " st.d $s5, $sp, 128 \n" \ + " st.d $s6, $sp, 136 \n" \ + " st.d $s7, $sp, 144 \n" \ + " st.d $s8, $sp, 152 \n" \ + " ld.d $a0, $fp, 8 \n" \ + " move $a1, $r1 \n" \ + " bl " __STRING(_mcount) PLTSYM " \n" \ + /* restore argument registers */ \ + " ld.d $fp, $sp, 0 \n" \ + " ld.d $ra, $sp, 8 \n" \ + " ld.d $s0, $sp, 24 \n" \ + " ld.d $a0, $sp, 32 \n" \ + " ld.d $a1, $sp, 40 \n" \ + " ld.d $a2, $sp, 48 \n" \ + " ld.d $a3, $sp, 56 \n" \ + " ld.d $a4, $sp, 64 \n" \ + " ld.d $a5, $sp, 72 \n" \ + " ld.d $a6, $sp, 80 \n" \ + " ld.d $a7, $sp, 88 \n" \ + " ld.d $s1, $sp, 96 \n" \ + " ld.d $s2, $sp, 104 \n" \ + " ld.d $s3, $sp, 112 \n" \ + " ld.d $s4, $sp, 120 \n" \ + " ld.d $s5, $sp, 128 \n" \ + " ld.d $s6, $sp, 136 \n" \ + " ld.d $s7, $sp, 144 \n" \ + " ld.d $s8, $sp, 152 \n" \ + " addi.d $sp, $sp, 176 \n" \ + " jirl $zero, $ra, 0 \n"); + +#ifdef _KERNEL +// Change this to dair read/set, then restore. +#define MCOUNT_ENTER \ +__asm__ __volatile__( \ + "csrrd %0, $crmd\n\t" /* read CRMD into s */ \ + "li.d $t0, 4\n\t" /* bit 2 = 4 */ \ + "csrxchg $zero, $t0, $crmd\n\t"/* clear IE bit (bit 2) */ \ + : "=r" (s) /* s holds original value */\ + : \ + : "$t0", "memory" \ + ); + +#define MCOUNT_EXIT \ +__asm__ __volatile__( \ +"csrwr %0, $crmd\n\t" /* restore CRMD from s */ \ + : \ + : "r" (s) \ + : "memory" \ + ); +#endif diff --git sys/arch/loongarch64/include/pte.h sys/arch/loongarch64/include/pte.h new file mode 100644 index 00000000000..1346aec04c5 --- /dev/null +++ sys/arch/loongarch64/include/pte.h @@ -0,0 +1,93 @@ +/* $OpenBSD: pte.h,v 1.5 2026/04/05 11:48:17 kettenis Exp $ */ + +/* + * Copyright (c) 2019 Brian Bamsch + * Copyright (c) 2014 Dale Rahn + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef _LOONGARCH64_PTE_H_ +#define _LOONGARCH64_PTE_H_ + +#define Lx_TABLE_ALIGN (4096) + +/* Block and Page attributes */ +/* Bits 9:8 are reserved for software */ +#define PTE_ATTR_MASK (0x3ffUL) +#define PTE_SW_MANAGED (1 << 9) +#define PTE_SW_WIRED (1 << 8) +#define PTE_D (1 << 7) /* Dirty */ +#define PTE_A (1 << 6) /* Accessed */ +#define PTE_G (1 << 5) /* Global */ +#define PTE_U (1 << 4) /* User */ +#define PTE_X (1 << 3) /* Execute */ +#define PTE_W (1 << 2) /* Write */ +#define PTE_R (1 << 1) /* Read */ +#define PTE_V (1 << 0) /* Valid */ +#define PTE_RWX (PTE_R | PTE_W | PTE_X) +#define PTE_RX (PTE_R | PTE_X) +#define PTE_KERN (PTE_V | PTE_R | PTE_W | PTE_A | PTE_D) + +/* Svpmbt extension */ +#define PTE_PMA (0ULL << 61) +#define PTE_NC (1ULL << 61) +#define PTE_IO (2ULL << 61) + +/* Svnapot extension */ +#define PTE_N (1ULL << 63) + +/* T-Head extended page attributes */ +#define PTE_THEAD_SO (1ULL << 63) +#define PTE_THEAD_C (1ULL << 62) +#define PTE_THEAD_B (1ULL << 61) +#define PTE_THEAD_SH (1ULL << 60) + +/* Level 0 table, 512GiB per entry */ +#define L0_SHIFT 39 + +/* Level 1 table, 1GiB per entry */ +#define L1_SHIFT 30 +#define L1_SIZE (1UL << L1_SHIFT) +#define L1_OFFSET (L1_SIZE - 1) + +/* Level 2 table, 2MiB per entry */ +#define L2_SHIFT 21 +#define L2_SIZE (1UL << L2_SHIFT) +#define L2_OFFSET (L2_SIZE - 1) + +/* Level 3 table, 4KiB per entry */ +#define L3_SHIFT 12 +#define L3_SIZE (1UL << L3_SHIFT) +#define L3_OFFSET (L3_SIZE - 1) + +/* page mapping */ +#define Ln_ENTRIES_SHIFT 9 +#define Ln_ENTRIES (1 << Ln_ENTRIES_SHIFT) +#define Ln_ADDR_MASK (Ln_ENTRIES - 1) +#define Ln_TABLE_MASK ((1 << 12) - 1) + +/* physical page number mask */ +#define PTE_RPGN (((1ULL << 56) - 1) & ~PAGE_MASK) + +#define PTE_PPN0_S 10 +#define PTE_PPN1_S 19 +#define PTE_PPN2_S 28 +#define PTE_PPN3_S 37 +#define PTE_SIZE 8 + +#ifndef _LOCORE +typedef uint64_t pt_entry_t; /* page table entry */ +typedef uint64_t pn_t; /* page number */ +#endif /* !_LOCORE */ + +#endif /* _LOONGARCH64_PTE_H_ */ diff --git sys/arch/loongarch64/include/ptrace.h sys/arch/loongarch64/include/ptrace.h new file mode 100644 index 00000000000..8d20cf3cf43 --- /dev/null +++ sys/arch/loongarch64/include/ptrace.h @@ -0,0 +1,25 @@ +/* $OpenBSD: ptrace.h,v 1.4 2021/09/03 14:13:06 jca Exp $ */ + +/* + * Copyright (c) 2014 Patrick Wildt + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#if 0 +#define PT_STEP (PT_FIRSTMACH + 0) +#endif +#define PT_GETREGS (PT_FIRSTMACH + 1) +#define PT_SETREGS (PT_FIRSTMACH + 2) +#define PT_GETFPREGS (PT_FIRSTMACH + 3) +#define PT_SETFPREGS (PT_FIRSTMACH + 4) diff --git sys/arch/loongarch64/include/reg.h sys/arch/loongarch64/include/reg.h new file mode 100644 index 00000000000..e5f714d9f3d --- /dev/null +++ sys/arch/loongarch64/include/reg.h @@ -0,0 +1,68 @@ +/* $OpenBSD: reg.h,v 1.3 2026/05/09 17:38:50 jsing Exp $ */ + +/*- + * Copyright (c) 2019 Brian Bamsch + * Copyright (c) 2015-2016 Ruslan Bukin + * All rights reserved. + * + * Portions of this software were developed by SRI International and the + * University of Cambridge Computer Laboratory under DARPA/AFRL contract + * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. + * + * Portions of this software were developed by the University of Cambridge + * Computer Laboratory as part of the CTSRD Project, with support from the + * UK Higher Education Innovation Fund (HEIF). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _MACHINE_REG_H_ +#define _MACHINE_REG_H_ + +struct reg { + uint64_t r_ra; /* return address */ + uint64_t r_sp; /* stack pointer */ + uint64_t r_gp; /* global pointer */ + uint64_t r_tp; /* thread pointer */ + uint64_t r_t[7]; /* temporary registers */ + uint64_t r_s[12]; /* saved registers */ + uint64_t r_a[8]; /* argument registers */ + uint64_t r_sepc; /* exception program counter */ + uint64_t r_sstatus; /* status register */ +}; + +struct fpreg { + uint64_t fp_f[32]; /* floating-point registers */ + uint64_t fp_fcsr; /* floating-point control register */ +}; + +struct vreg { + uint64_t v_vtype; /* vector type control register */ + uint64_t v_vl; /* vector length control register */ + uint64_t v_vstart; /* vector start control register */ + uint64_t v_vcsr; /* vector control and status register */ + uint8_t v_vdata[]; /* vector register data (sized based on vlenb) */ +}; + +#endif /* !_MACHINE_REG_H_ */ diff --git sys/arch/loongarch64/include/reloc.h sys/arch/loongarch64/include/reloc.h new file mode 100644 index 00000000000..9cca19bc073 --- /dev/null +++ sys/arch/loongarch64/include/reloc.h @@ -0,0 +1,16 @@ +/* $OpenBSD: reloc.h,v 1.2 2021/05/12 01:20:52 jsg Exp $ */ + +/* + * loongarch64 static relocation types. + */ + +/* Relocation types used by the dynamic linker. */ +#define R_LARCH_NONE 0 +#define R_LARCH_32 1 +#define R_LARCH_64 2 +#define R_LARCH_RELATIVE 3 +#define R_LARCH_COPY 4 +#define R_LARCH_JUMP_SLOT 5 +#define R_LARCH_TLS_DTPMOD64 6 +#define R_LARCH_TLS_DTPREL64 7 +#define R_LARCH_TLS_TPREL64 8 diff --git sys/arch/loongarch64/include/sbi.h sys/arch/loongarch64/include/sbi.h new file mode 100644 index 00000000000..761d99919a9 --- /dev/null +++ sys/arch/loongarch64/include/sbi.h @@ -0,0 +1,262 @@ +/* $OpenBSD: sbi.h,v 1.6 2024/03/29 22:11:34 kettenis Exp $ */ + +/*- + * Copyright (c) 2016-2017 Ruslan Bukin + * All rights reserved. + * Copyright (c) 2019 Mitchell Horne + * + * Portions of this software were developed by SRI International and the + * University of Cambridge Computer Laboratory under DARPA/AFRL contract + * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. + * + * Portions of this software were developed by the University of Cambridge + * Computer Laboratory as part of the CTSRD Project, with support from the + * UK Higher Education Innovation Fund (HEIF). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MACHINE_SBI_H_ +#define _MACHINE_SBI_H_ + +/* SBI Specification Version */ +#define SBI_SPEC_VERS_MAJOR_OFFSET 24 +#define SBI_SPEC_VERS_MAJOR_MASK (0x7F << SBI_SPEC_VERS_MAJOR_OFFSET) +#define SBI_SPEC_VERS_MINOR_OFFSET 0 +#define SBI_SPEC_VERS_MINOR_MASK (0xFFFFFF << SBI_SPEC_VERS_MINOR_OFFSET) + +/* SBI Implementation IDs */ +#define SBI_IMPL_ID_BBL 0 +#define SBI_IMPL_ID_OPENSBI 1 + +/* SBI Error Codes */ +#define SBI_SUCCESS 0 +#define SBI_ERR_FAILURE -1 +#define SBI_ERR_NOT_SUPPORTED -2 +#define SBI_ERR_INVALID_PARAM -3 +#define SBI_ERR_DENIED -4 +#define SBI_ERR_INVALID_ADDRESS -5 + +/* SBI Base Extension */ +#define SBI_EXT_ID_BASE 0x10 +#define SBI_BASE_GET_SPEC_VERSION 0 +#define SBI_BASE_GET_IMPL_ID 1 +#define SBI_BASE_GET_IMPL_VERSION 2 +#define SBI_BASE_PROBE_EXTENSION 3 +#define SBI_BASE_GET_MVENDORID 4 +#define SBI_BASE_GET_MARCHID 5 +#define SBI_BASE_GET_MIMPID 6 + +/* Hart State Management (HSM) Extension */ +#define SBI_EXT_ID_HSM 0x48534D +#define SBI_HSM_HART_START 0 +#define SBI_HSM_HART_STOP 1 +#define SBI_HSM_HART_STATUS 2 +#define SBI_HSM_STATUS_STARTED 0 +#define SBI_HSM_STATUS_STOPPED 1 +#define SBI_HSM_STATUS_START_PENDING 2 +#define SBI_HSM_STATUS_STOP_PENDING 3 + +/* System Reset Extension */ +#define SBI_EXT_ID_SRST 0x53525354 +#define SBI_SRST_RESET 0 +#define SBI_SRST_RESET_SHUTDOWN 0 +#define SBI_SRST_RESET_COLD_REBOOT 1 +#define SBI_SRST_RESET_WARM_REBOOT 2 + +/* Legacy Extensions */ +#define SBI_SET_TIMER 0 +#define SBI_CONSOLE_PUTCHAR 1 +#define SBI_CONSOLE_GETCHAR 2 +#define SBI_CLEAR_IPI 3 +#define SBI_SEND_IPI 4 +#define SBI_REMOTE_FENCE_I 5 +#define SBI_REMOTE_SFENCE_VMA 6 +#define SBI_REMOTE_SFENCE_VMA_ASID 7 +#define SBI_SHUTDOWN 8 + +#define SBI_CALL0(e, f) SBI_CALL4(e, f, 0, 0, 0, 0) +#define SBI_CALL1(e, f, p1) SBI_CALL4(e, f, p1, 0, 0, 0) +#define SBI_CALL2(e, f, p1, p2) SBI_CALL4(e, f, p1, p2, 0, 0) +#define SBI_CALL3(e, f, p1, p2, p3) SBI_CALL4(e, f, p1, p2, p3, 0) +#define SBI_CALL4(e, f, p1, p2, p3, p4) sbi_call(e, f, p1, p2, p3, p4) + +struct sbi_ret { + long error; + long value; +}; + +static __inline struct sbi_ret +sbi_call(uint64_t arg7, uint64_t arg6, uint64_t arg0, uint64_t arg1, + uint64_t arg2, uint64_t arg3) +{ + struct sbi_ret ret; + + register uintptr_t a0 __asm ("$a0") = (uintptr_t)(arg0); + register uintptr_t a1 __asm ("$a1") = (uintptr_t)(arg1); + register uintptr_t a2 __asm ("$a2") = (uintptr_t)(arg2); + register uintptr_t a3 __asm ("$a3") = (uintptr_t)(arg3); + register uintptr_t a6 __asm ("$a6") = (uintptr_t)(arg6); + register uintptr_t a7 __asm ("$a7") = (uintptr_t)(arg7); + + __asm volatile( \ + "syscall 0" \ + :"+r"(a0), "+r"(a1) \ + :"r"(a2), "r"(a3), "r"(a6), "r"(a7) \ + :"memory"); + + ret.error = a0; + ret.value = a1; + return (ret); +} + +/* Base extension functions and variables. */ +extern u_long sbi_spec_version; +extern u_long sbi_impl_id; +extern u_long sbi_impl_version; + +static __inline u_int +sbi_get_mvendorid(void) +{ + return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_MVENDORID).value); +} + + +static __inline u_long +sbi_get_marchid(void) +{ + return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_MARCHID).value); +} + +static __inline u_long +sbi_get_mimpid(void) +{ + return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_MIMPID).value); +} + +static __inline long +sbi_probe_extension(long id) +{ + return (SBI_CALL1(SBI_EXT_ID_BASE, SBI_BASE_PROBE_EXTENSION, id).value); +} + +/* Hart State Management extension functions. */ + +/* + * Start execution on the specified hart at physical address start_addr. The + * register a0 will contain the hart's ID, and a1 will contain the value of + * priv. + */ +int sbi_hsm_hart_start(u_long hart, u_long start_addr, u_long priv); + +/* + * Stop execution on the current hart. Interrupts should be disabled, or this + * function may return. + */ +void sbi_hsm_hart_stop(void); + +/* + * Get the execution status of the specified hart. The status will be one of: + * - SBI_HSM_STATUS_STARTED + * - SBI_HSM_STATUS_STOPPED + * - SBI_HSM_STATUS_START_PENDING + * - SBI_HSM_STATUS_STOP_PENDING + */ +int sbi_hsm_hart_status(u_long hart); + +/* Legacy extension functions. */ +static __inline void +sbi_console_putchar(int ch) +{ + + (void)SBI_CALL1(SBI_CONSOLE_PUTCHAR, 0, ch); +} + +static __inline int +sbi_console_getchar(void) +{ + + /* + * XXX: The "error" is returned here because legacy SBI functions + * continue to return their value in a0. + */ + return (SBI_CALL0(SBI_CONSOLE_GETCHAR, 0).error); +} + +static __inline void +sbi_set_timer(uint64_t val) +{ + + (void)SBI_CALL1(SBI_SET_TIMER, 0, val); +} + +static __inline void +sbi_shutdown(void) +{ + + (void)SBI_CALL0(SBI_SHUTDOWN, 0); +} + +static __inline void +sbi_clear_ipi(void) +{ + + (void)SBI_CALL0(SBI_CLEAR_IPI, 0); +} + +static __inline void +sbi_send_ipi(const unsigned long *hart_mask) +{ + + (void)SBI_CALL1(SBI_SEND_IPI, 0, (uint64_t)hart_mask); +} + +static __inline void +sbi_remote_fence_i(const unsigned long *hart_mask) +{ + + (void)SBI_CALL1(SBI_REMOTE_FENCE_I, 0, (uint64_t)hart_mask); +} + +static __inline void +sbi_remote_sfence_vma(const unsigned long *hart_mask, + unsigned long start, unsigned long size) +{ + + (void)SBI_CALL3(SBI_REMOTE_SFENCE_VMA, 0, (uint64_t)hart_mask, start, + size); +} + +static __inline void +sbi_remote_sfence_vma_asid(const unsigned long *hart_mask, + unsigned long start, unsigned long size, + unsigned long asid) +{ + + (void)SBI_CALL4(SBI_REMOTE_SFENCE_VMA_ASID, 0, (uint64_t)hart_mask, + start, size, asid); +} + +void sbi_print_version(void); +void sbi_init(void); + +#endif /* !_MACHINE_SBI_H_ */ diff --git sys/arch/loongarch64/include/setjmp.h sys/arch/loongarch64/include/setjmp.h new file mode 100644 index 00000000000..15c39636b4b --- /dev/null +++ sys/arch/loongarch64/include/setjmp.h @@ -0,0 +1,8 @@ +/* $OpenBSD: setjmp.h,v 1.4 2021/06/17 16:09:08 kettenis Exp $ */ + +/* + * machine/setjmp.h: machine dependent setjmp-related information. + */ + +#define _JBLEN 32 /* sp, ra, [f]s0-11, fscr, magic val, sigmask */ +#define _JB_SIGMASK 28 diff --git sys/arch/loongarch64/include/signal.h sys/arch/loongarch64/include/signal.h new file mode 100644 index 00000000000..b2638e54b8d --- /dev/null +++ sys/arch/loongarch64/include/signal.h @@ -0,0 +1,70 @@ +/* $OpenBSD: signal.h,v 1.4 2021/05/20 15:14:30 drahn Exp $ */ + +/*- + * Copyright (c) 1986, 1989, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)signal.h 8.1 (Berkeley) 6/11/93 + * from: FreeBSD: src/sys/i386/include/signal.h,v 1.13 2000/11/09 + * from: FreeBSD: src/sys/sparc64/include/signal.h,v 1.6 2001/09/30 18:52:17 + * $FreeBSD: head/sys/riscv/include/signal.h 292407 2015-12-17 18:44:30Z br $ + */ + +#ifndef _MACHINE_SIGNAL_H_ +#define _MACHINE_SIGNAL_H_ + +#include + +typedef int sig_atomic_t; + +#if __BSD_VISIBLE || __XPG_VISIBLE >= 420 + +#include + +struct sigcontext { + int __sc_unused; + int sc_mask; + + __register_t sc_ra; + __register_t sc_sp; + __register_t sc_gp; + __register_t sc_tp; + __register_t sc_t[7]; + __register_t sc_s[12]; + __register_t sc_a[8]; + __register_t sc_sepc; + + /* 64 bit floats as well as integer registers */ + __register_t sc_f[32]; /* floating-point registers */ + __register_t sc_fcsr; /* floating-point control register */ + + long sc_cookie; +}; + +#endif /* __BSD_VISIBLE || __XPG_VISIBLE >= 420 */ + +#endif /* !_MACHINE_SIGNAL_H_ */ diff --git sys/arch/loongarch64/include/simplebusvar.h sys/arch/loongarch64/include/simplebusvar.h new file mode 100644 index 00000000000..ae49f6d721f --- /dev/null +++ sys/arch/loongarch64/include/simplebusvar.h @@ -0,0 +1,38 @@ +/* $OpenBSD: simplebusvar.h,v 1.1 2023/09/22 01:10:44 jsg Exp $ */ + +/* + * Copyright (c) 2016 Patrick Wildt + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +struct simplebus_softc { + struct device sc_dev; + int sc_node; + bus_space_tag_t sc_iot; + bus_dma_tag_t sc_dmat; + int sc_acells; + int sc_scells; + int sc_pacells; + int sc_pscells; + struct bus_space sc_bus; + struct machine_bus_dma_tag sc_dma; + int *sc_ranges; + int sc_rangeslen; + int *sc_dmaranges; + int sc_dmarangeslen; + int sc_early; + int sc_early_nodes[64]; +}; + +extern void simplebus_attach(struct device *, struct device *, void *); diff --git sys/arch/loongarch64/include/smbiosvar.h sys/arch/loongarch64/include/smbiosvar.h new file mode 100644 index 00000000000..0d106014a87 --- /dev/null +++ sys/arch/loongarch64/include/smbiosvar.h @@ -0,0 +1,278 @@ +/* $OpenBSD: smbiosvar.h,v 1.6 2025/07/15 01:09:32 jsg Exp $ */ +/* + * Copyright (c) 2006 Gordon Willem Klok + * Copyright (c) 2005 Jordan Hargrave + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MACHINE_SMBIOSVAR_ +#define _MACHINE_SMBIOSVAR_ + +#define SMBIOS_UUID_NPRESENT 0x1 +#define SMBIOS_UUID_NSET 0x2 + +/* + * Section 3.5 of "UUIDs and GUIDs" found at + * http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt + * specifies the string representation of a UUID. + */ +#define SMBIOS_UUID_REP "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" +#define SMBIOS_UUID_REPLEN 37 /* 16 zero padded values, 4 hyphens, 1 null */ + +struct smbios_entry { + uint8_t mjr; + uint8_t min; + uint8_t *addr; + uint16_t len; + uint16_t count; +}; + +struct smbhdr { + uint32_t sig; /* "_SM_" */ + uint8_t checksum; /* Entry point checksum */ + uint8_t len; /* Entry point structure length */ + uint8_t majrev; /* Specification major revision */ + uint8_t minrev; /* Specification minor revision */ + uint16_t mss; /* Maximum Structure Size */ + uint8_t epr; /* Entry Point Revision */ + uint8_t fa[5]; /* value determined by EPR */ + uint8_t sasig[5]; /* Secondary Anchor "_DMI_" */ + uint8_t sachecksum; /* Secondary Checksum */ + uint16_t size; /* Length of structure table in bytes */ + uint32_t addr; /* Structure table address */ + uint16_t count; /* Number of SMBIOS structures */ + uint8_t rev; /* BCD revision */ +} __packed; + +struct smb3hdr { + uint8_t sig[5]; /* "_SM3_" */ + uint8_t checksum; /* Entry point structure checksum */ + uint8_t len; /* Entry point length */ + uint8_t majrev; /* SMBIOS major version */ + uint8_t minrev; /* SMBIOS minor version */ + uint8_t docrev; /* SMBIOS docrev */ + uint8_t epr; /* Entry point revision */ + uint8_t reserved; /* Reserved */ + uint32_t size; /* Structure table maximum size */ + uint64_t addr; /* Structure table address */ +} __packed; + +struct smbtblhdr { + uint8_t type; + uint8_t size; + uint16_t handle; +} __packed; + +struct smbtable { + struct smbtblhdr *hdr; + void *tblhdr; + uint32_t cookie; +}; + +#define SMBIOS_TYPE_BIOS 0 +#define SMBIOS_TYPE_SYSTEM 1 +#define SMBIOS_TYPE_BASEBOARD 2 +#define SMBIOS_TYPE_ENCLOSURE 3 +#define SMBIOS_TYPE_PROCESSOR 4 +#define SMBIOS_TYPE_MEMCTRL 5 +#define SMBIOS_TYPE_MEMMOD 6 +#define SMBIOS_TYPE_CACHE 7 +#define SMBIOS_TYPE_PORT 8 +#define SMBIOS_TYPE_SLOTS 9 +#define SMBIOS_TYPE_OBD 10 +#define SMBIOS_TYPE_OEM 11 +#define SMBIOS_TYPE_SYSCONFOPT 12 +#define SMBIOS_TYPE_BIOSLANG 13 +#define SMBIOS_TYPE_GROUPASSOC 14 +#define SMBIOS_TYPE_SYSEVENTLOG 15 +#define SMBIOS_TYPE_PHYMEM 16 +#define SMBIOS_TYPE_MEMDEV 17 +#define SMBIOS_TYPE_ECCINFO32 18 +#define SMBIOS_TYPE_MEMMAPARRAYADDR 19 +#define SMBIOS_TYPE_MEMMAPDEVADDR 20 +#define SMBIOS_TYPE_INBUILTPOINT 21 +#define SMBIOS_TYPE_PORTBATT 22 +#define SMBIOS_TYPE_SYSRESET 23 +#define SMBIOS_TYPE_HWSECUIRTY 24 +#define SMBIOS_TYPE_PWRCTRL 25 +#define SMBIOS_TYPE_VOLTPROBE 26 +#define SMBIOS_TYPE_COOLING 27 +#define SMBIOS_TYPE_TEMPPROBE 28 +#define SMBIOS_TYPE_CURRENTPROBE 29 +#define SMBIOS_TYPE_OOB_REMOTEACCESS 30 +#define SMBIOS_TYPE_BIS 31 +#define SMBIOS_TYPE_SBI 32 +#define SMBIOS_TYPE_ECCINFO64 33 +#define SMBIOS_TYPE_MGMTDEV 34 +#define SMBIOS_TYPE_MGTDEVCOMP 35 +#define SMBIOS_TYPE_MGTDEVTHRESH 36 +#define SMBIOS_TYPE_MEMCHANNEL 37 +#define SMBIOS_TYPE_IPMIDEV 38 +#define SMBIOS_TYPE_SPS 39 +#define SMBIOS_TYPE_INACTIVE 126 +#define SMBIOS_TYPE_EOT 127 + +/* + * SMBIOS Structure Type 0 "BIOS Information" + * DMTF Specification DSP0134 Section: 3.3.1 p.g. 34 + */ +struct smbios_struct_bios { + uint8_t vendor; /* string */ + uint8_t version; /* string */ + uint16_t startaddr; + uint8_t release; /* string */ + uint8_t romsize; + uint64_t characteristics; + uint32_t charext; + uint8_t major_rel; + uint8_t minor_rel; + uint8_t ecf_mjr_rel; /* embedded controller firmware */ + uint8_t ecf_min_rel; /* embedded controller firmware */ +} __packed; + +/* + * SMBIOS Structure Type 1 "System Information" + * DMTF Specification DSP0134 Section 3.3.2 p.g. 35 + */ + +struct smbios_sys { +/* SMBIOS spec 2.0+ */ + uint8_t vendor; /* string */ + uint8_t product; /* string */ + uint8_t version; /* string */ + uint8_t serial; /* string */ +/* SMBIOS spec 2.1+ */ + uint8_t uuid[16]; + uint8_t wakeup; +/* SMBIOS spec 2.4+ */ + uint8_t sku; /* string */ + uint8_t family; /* string */ +} __packed; + +/* + * SMBIOS Structure Type 2 "Base Board (Module) Information" + * DMTF Specification DSP0134 Section 3.3.3 p.g. 37 + */ +struct smbios_board { + uint8_t vendor; /* string */ + uint8_t product; /* string */ + uint8_t version; /* string */ + uint8_t serial; /* string */ + uint8_t asset; /* string */ + uint8_t feature; /* feature flags */ + uint8_t location; /* location in chassis */ + uint16_t handle; /* chassis handle */ + uint8_t type; /* board type */ + uint8_t noc; /* number of contained objects */ +} __packed; + +/* + * SMBIOS Structure Type 3 "System Enclosure or Chassis" + * DMTF Specification DSP0134 + */ +struct smbios_enclosure { + /* SMBIOS spec 2.0+ */ + uint8_t vendor; /* string */ + uint8_t type; + uint8_t version; /* string */ + uint8_t serial; /* string */ + uint8_t asset_tag; /* string */ + /* SMBIOS spec 2.1+ */ + uint8_t boot_state; + uint8_t psu_state; + uint8_t thermal_state; + uint8_t security_status; + /* SMBIOS spec 2.3+ */ + uint16_t oem_defined; + uint8_t height; + uint8_t no_power_cords; + uint8_t no_contained_element; + uint8_t reclen_contained_element; + uint8_t contained_elements; + /* SMBIOS spec 2.7+ */ + uint8_t sku; /* string */ +} __packed; + +/* + * SMBIOS Structure Type 4 "processor Information" + * DMTF Specification DSP0134 v2.5 Section 3.3.5 p.g. 24 + */ +struct smbios_cpu { + uint8_t cpu_socket_designation; /* string */ + uint8_t cpu_type; + uint8_t cpu_family; + uint8_t cpu_mfg; /* string */ + uint32_t cpu_id_eax; + uint32_t cpu_id_edx; + uint8_t cpu_version; /* string */ + uint8_t cpu_voltage; + uint16_t cpu_clock; + uint16_t cpu_max_speed; + uint16_t cpu_current_speed; + uint8_t cpu_status; +#define SMBIOS_CPUST_POPULATED (1<<6) +#define SMBIOS_CPUST_STATUSMASK (0x07) + uint8_t cpu_upgrade; + uint16_t cpu_l1_handle; + uint16_t cpu_l2_handle; + uint16_t cpu_l3_handle; + uint8_t cpu_serial; /* string */ + uint8_t cpu_asset_tag; /* string */ + uint8_t cpu_part_nr; /* string */ + /* following fields were added in smbios 2.5 */ + uint8_t cpu_core_count; + uint8_t cpu_core_enabled; + uint8_t cpu_thread_count; + uint16_t cpu_characteristics; +} __packed; + +/* + * SMBIOS Structure Type 38 "IPMI Information" + * DMTF Specification DSP0134 Section 3.3.39 p.g. 91 + */ +struct smbios_ipmi { + uint8_t smipmi_if_type; /* IPMI Interface Type */ + uint8_t smipmi_if_rev; /* BCD IPMI Revision */ + uint8_t smipmi_i2c_address; /* I2C address of BMC */ + uint8_t smipmi_nvram_address; /* I2C address of NVRAM + * storage */ + uint64_t smipmi_base_address; /* Base address of BMC (BAR + * format */ + uint8_t smipmi_base_flags; /* Flags field: + * bit 7:6 : register spacing + * 00 = byte + * 01 = dword + * 02 = word + * bit 4 : Lower bit BAR + * bit 3 : IRQ valid + * bit 2 : N/A + * bit 1 : Interrupt polarity + * bit 0 : Interrupt trigger */ + uint8_t smipmi_irq; /* IRQ if applicable */ +} __packed; + +int smbios_find_table(uint8_t, struct smbtable *); +char *smbios_get_string(struct smbtable *, uint8_t, char *, size_t); + +#endif diff --git sys/arch/loongarch64/include/spinlock.h sys/arch/loongarch64/include/spinlock.h new file mode 100644 index 00000000000..a0836db1a41 --- /dev/null +++ sys/arch/loongarch64/include/spinlock.h @@ -0,0 +1,10 @@ +/* $OpenBSD: spinlock.h,v 1.2 2021/05/12 01:20:52 jsg Exp $ */ + +#ifndef _MACHINE_SPINLOCK_H_ +#define _MACHINE_SPINLOCK_H_ + +#define _ATOMIC_LOCK_UNLOCKED (0) +#define _ATOMIC_LOCK_LOCKED (1) +typedef int _atomic_lock_t; + +#endif diff --git sys/arch/loongarch64/include/sysarch.h sys/arch/loongarch64/include/sysarch.h new file mode 100644 index 00000000000..1c737a0a72d --- /dev/null +++ sys/arch/loongarch64/include/sysarch.h @@ -0,0 +1,43 @@ +/* $OpenBSD: sysarch.h,v 1.1 2021/09/14 12:03:49 jca Exp $ */ + +/* + * Copyright (c) 2021 Jeremie Courreges-Anglas + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _LOONGARCH64_SYSARCH_H_ +#define _LOONGARCH64_SYSARCH_H_ + +/* + * Architecture specific syscalls (loongarch64) + */ + +#define LOONGARCH_SYNC_ICACHE 0 + +struct loongarch_sync_icache_args { + u_int64_t addr; /* Virtual start address */ + size_t len; /* Region size */ +}; + +#ifndef _KERNEL + +#include + +__BEGIN_DECLS +int sysarch(int, void *); +__END_DECLS + +#endif /* _KERNEL */ + +#endif /* _LOONGARCH64_SYSARCH_H_ */ diff --git sys/arch/loongarch64/include/syscall.h sys/arch/loongarch64/include/syscall.h new file mode 100644 index 00000000000..b460a0793ad --- /dev/null +++ sys/arch/loongarch64/include/syscall.h @@ -0,0 +1,28 @@ +/* $OpenBSD: syscall.h,v 1.3 2021/05/21 16:49:35 deraadt Exp $ */ + +/* + * Copyright (c) 2020 Brian Bamsch + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _MACHINE_SYSCALL_H_ +#define _MACHINE_SYSCALL_H_ + +#ifdef _KERNEL + +void svc_handler (trapframe_t *); + +#endif + +#endif /* !_MACHINE_SYSCALL_H_ */ diff --git sys/arch/loongarch64/include/tcb.h sys/arch/loongarch64/include/tcb.h new file mode 100644 index 00000000000..b957e793563 --- /dev/null +++ sys/arch/loongarch64/include/tcb.h @@ -0,0 +1,52 @@ +/* $OpenBSD: tcb.h,v 1.3 2021/05/12 01:20:52 jsg Exp $ */ + +/* + * Copyright (c) 2019 Brian Bamsch + * Copyright (c) 2011 Philip Guenther + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _MACHINE_TCB_H_ +#define _MACHINE_TCB_H_ + +#ifdef _KERNEL + +#include + +#define TCB_GET(p) \ + ((void *)(((struct pcb *)(p)->p_addr)->pcb_tf->tf_tp)) + +#define TCB_SET(p, addr) \ + do { \ + ((struct pcb *)(p)->p_addr)->pcb_tf->tf_tp = (long)(addr); \ + } while (0) + +#else /* _KERNEL */ + +/* ELF TLS ABI calls for small TCB, with static TLS data after it */ +#define TLS_VARIANT 1 + +static inline void * +__loongarch64_read_tcb(void) +{ + void *tcb; + __asm volatile("move %0, $tp": "=r" (tcb)); + return tcb; +} + +#define TCB_GET() __loongarch64_read_tcb() + +#endif /* _KERNEL */ + +#endif /* _MACHINE_TCB_H_ */ diff --git sys/arch/loongarch64/include/timetc.h sys/arch/loongarch64/include/timetc.h new file mode 100644 index 00000000000..284749253cf --- /dev/null +++ sys/arch/loongarch64/include/timetc.h @@ -0,0 +1,24 @@ +/* $OpenBSD: timetc.h,v 1.3 2021/07/24 22:41:09 jca Exp $ */ + +/* + * Copyright (c) 2020 Paul Irofti + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _MACHINE_TIMETC_H_ +#define _MACHINE_TIMETC_H_ + +#define TC_TB 1 + +#endif /* _MACHINE_TIMETC_H_ */ diff --git sys/arch/loongarch64/include/trap.h sys/arch/loongarch64/include/trap.h new file mode 100644 index 00000000000..2d220c52bb8 --- /dev/null +++ sys/arch/loongarch64/include/trap.h @@ -0,0 +1,24 @@ +/* $OpenBSD: trap.h,v 1.2 2021/05/12 01:20:52 jsg Exp $ */ + +/* + * Copyright (c) 2019 Brian Bamsch + * Copyright (c) 2016 Dale Rahn + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define KERNEL_BREAKPOINT 0x00100073 /* EBREAK -- Used by DDB */ + +#define KBPT_ASM "ebreak" + +#define USER_BREAKPOINT 0x00100073 /* EBREAK */ diff --git sys/arch/loongarch64/include/vmparam.h sys/arch/loongarch64/include/vmparam.h new file mode 100644 index 00000000000..80cf4cd2dc7 --- /dev/null +++ sys/arch/loongarch64/include/vmparam.h @@ -0,0 +1,152 @@ +/* $OpenBSD: vmparam.h,v 1.9 2023/11/28 09:10:18 jsg Exp $ */ + +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)vmparam.h 5.9 (Berkeley) 5/12/91 + */ + +#ifndef _MACHINE_VMPARAM_H_ +#define _MACHINE_VMPARAM_H_ + +/* + * Machine dependent constants for loongarch64. + */ + +#define USRSTACK VM_MAXUSER_ADDRESS + +/* + * Virtual memory related constants, all in bytes + */ +#ifndef MAXTSIZ +#define MAXTSIZ ((paddr_t)1*1024*1024*1024) /* max text size */ +#endif +#ifndef DFLDSIZ +#define DFLDSIZ ((paddr_t)128*1024*1024) /* initial data size limit */ +#endif +#ifndef MAXDSIZ +#define MAXDSIZ ((paddr_t)16*1024*1024*1024) /* max data size */ +#endif +#ifndef BRKSIZ +#define BRKSIZ ((paddr_t)1*1024*1024*1024) /* heap gap size */ +#endif +#ifndef DFLSSIZ +#define DFLSSIZ ((paddr_t)128*1024*1024) /* initial stack size limit */ +#endif +#ifndef MAXSSIZ +#define MAXSSIZ ((paddr_t)1*1024*1024*1024) /* max stack size */ +#endif + +#define STACKGAP_RANDOM 256*1024 + +/* + * Size of shared memory map + */ +#ifndef SHMMAXPGS +#define SHMMAXPGS 1024 +#endif + +/* + * Size of User Raw I/O map + */ +#define USRIOSIZE 300 + +#define USER_SPACE_BITS 48 + +/** + * Address space layout. + * + * RISC-V implements multiple paging modes with different virtual address space + * sizes: SV32, SV39 and SV48. SV39 permits a virtual address space size of + * 512GB and uses a three-level page table. Since this is large enough for most + * purposes, we currently use SV39 for both userland and the kernel, avoiding + * the extra translation step required by SV48. + * + * The address space is split into two regions at each end of the 64-bit address + * space: + * + * 0x0000000000000000 - 0x0000003fffffffff 256GB user map + * 0x0000004000000000 - 0xffffffbfffffffff unmappable + * 0xffffffc000000000 - 0xffffffc7ffffffff 32GB kernel map + * 0xffffffc800000000 - 0xffffffcfffffffff 32GB unused + * 0xffffffd000000000 - 0xffffffefffffffff 128GB direct map + * 0xfffffff000000000 - 0xffffffffffffffff 64GB unused + * + * The kernel is loaded at the beginning of the kernel map. + * + * We define some interesting address constants: + * + * VM_MIN_ADDRESS and VM_MAX_ADDRESS define the start and end of the entire + * 64 bit address space, mostly just for convenience. + * + * VM_MIN_KERNEL_ADDRESS and VM_MAX_KERNEL_ADDRESS define the start and end of + * mappable kernel virtual address space. + * + * VM_MIN_ADDRESS and VM_MAXUSER_ADDRESS define the start and end of the + * user address space. + */ +#define VM_MIN_ADDRESS ((vaddr_t)PAGE_SIZE) +#define VM_MAX_ADDRESS (0xffffffffffffffffUL) + +#define VM_MIN_KERNEL_ADDRESS (0xffffffe000000000UL) +#define VM_MAX_KERNEL_ADDRESS (0xffffffffffffffffUL) + +/* Kernel L1 Page Table Range */ +#define L1_KERN_BASE (256) +#define L1_KERN_ENTRIES (320 - L1_KERN_BASE) + +#define DMAP_MIN_ADDRESS (0xffffffc000000000UL) +#define DMAP_MAX_ADDRESS (0xffffffdfffffffffUL) + +/* DMAP L1 Page Table Range */ +#define L1_DMAP_BASE (320) +#define L1_DMAP_ENTRIES (384 - L1_DMAP_BASE) + +#define VM_MAXUSER_ADDRESS (0x0000007fffffffffUL) /* 39 bits */ + +#ifdef _KERNEL +#define VM_MIN_STACK_ADDRESS (VM_MAXUSER_ADDRESS * 3 / 4) +#endif + +#define KERNBASE (VM_MIN_KERNEL_ADDRESS) + +#ifndef _LOCORE +extern paddr_t dmap_phys_base; +#endif + +/* virtual sizes (bytes) for various kernel submaps */ +#define VM_PHYS_SIZE (USRIOSIZE*PAGE_SIZE) + +#define VM_PHYSSEG_MAX 32 +#define VM_PHYSSEG_STRAT VM_PSTRAT_BSEARCH +#define VM_PHYSSEG_NOADD /* can't add RAM after vm_mem_init */ + +#endif /* _MACHINE_VMPARAM_H_ */ diff --git sys/arch/loongarch64/loongarch64/acpi_machdep.c sys/arch/loongarch64/loongarch64/acpi_machdep.c new file mode 100644 index 00000000000..93ecc9a2a93 --- /dev/null +++ sys/arch/loongarch64/loongarch64/acpi_machdep.c @@ -0,0 +1,200 @@ +/* $OpenBSD: acpi_machdep.c,v 1.22 2024/05/22 05:51:49 jsg Exp $ */ +/* + * Copyright (c) 2018 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include "apm.h" + +int pwr_action = 1; + +int acpi_fdt_match(struct device *, void *, void *); +void acpi_fdt_attach(struct device *, struct device *, void *); + +const struct cfattach acpi_fdt_ca = { + sizeof(struct acpi_softc), acpi_fdt_match, acpi_fdt_attach +}; + +int +acpi_fdt_match(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *faa = aux; + + return OF_is_compatible(faa->fa_node, "openbsd,acpi-5.0"); +} + +void +acpi_fdt_attach(struct device *parent, struct device *self, void *aux) +{ + struct acpi_softc *sc = (struct acpi_softc *)self; + struct fdt_attach_args *faa = aux; + bus_dma_tag_t dmat; + + sc->sc_memt = faa->fa_iot; + sc->sc_ci_dmat = faa->fa_dmat; + + /* Create coherent DMA tag. */ + dmat = malloc(sizeof(*sc->sc_cc_dmat), M_DEVBUF, M_WAITOK | M_ZERO); + memcpy(dmat, faa->fa_dmat, sizeof(*dmat)); + dmat->_flags |= BUS_DMA_COHERENT; + sc->sc_cc_dmat = dmat; + + acpi_attach_common(sc, faa->fa_reg[0].addr); +} + +int +acpi_map(paddr_t pa, size_t len, struct acpi_mem_map *handle) +{ + paddr_t pgpa = trunc_page(pa); + paddr_t endpa = round_page(pa + len); + vaddr_t va = (vaddr_t)km_alloc(endpa - pgpa, &kv_any, &kp_none, + &kd_nowait); + + if (va == 0) + return (ENOMEM); + + handle->baseva = va; + handle->va = (u_int8_t *)(va + (pa & PGOFSET)); + handle->vsize = endpa - pgpa; + handle->pa = pa; + + do { + pmap_kenter_pa(va, pgpa, PROT_READ | PROT_WRITE); + va += NBPG; + pgpa += NBPG; + } while (pgpa < endpa); + + return 0; +} + +void +acpi_unmap(struct acpi_mem_map *handle) +{ + pmap_kremove(handle->baseva, handle->vsize); + km_free((void *)handle->baseva, handle->vsize, &kv_any, &kp_none); +} + +int +acpi_bus_space_map(bus_space_tag_t t, bus_addr_t addr, bus_size_t size, + int flags, bus_space_handle_t *bshp) +{ + return bus_space_map(t, addr, size, flags, bshp); +} + +void +acpi_bus_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, + bus_size_t size) +{ + bus_space_unmap(t, bsh, size); +} + +int +acpi_acquire_glk(uint32_t *lock) +{ + /* No global lock. */ + return 1; +} + +int +acpi_release_glk(uint32_t *lock) +{ + /* No global lock. */ + return 0; +} + +void +acpi_attach_machdep(struct acpi_softc *sc) +{ +#if NAPM > 0 + apm_setinfohook(acpi_apminfo); +#endif +} + +void * +acpi_intr_establish(int irq, int flags, int level, + int (*func)(void *), void *arg, const char *name) +{ + struct interrupt_controller *ic; + struct machine_intr_handle *aih; + uint32_t interrupt[3]; + void *cookie; + + extern LIST_HEAD(, interrupt_controller) interrupt_controllers; + LIST_FOREACH(ic, &interrupt_controllers, ic_list) { + if (ic->ic_phandle == 1) + break; + } + if (ic == NULL) + return NULL; + + interrupt[0] = 0; + interrupt[1] = irq - 32; + if (flags & LR_EXTIRQ_MODE) { /* edge */ + if (flags & LR_EXTIRQ_POLARITY) + interrupt[2] = 0x2; /* falling */ + else + interrupt[2] = 0x1; /* rising */ + } else { /* level */ + if (flags & LR_EXTIRQ_POLARITY) + interrupt[2] = 0x8; /* low */ + else + interrupt[2] = 0x4; /* high */ + } + + cookie = ic->ic_establish(ic->ic_cookie, interrupt, level, NULL, + func, arg, (char *)name); + if (cookie == NULL) + return NULL; + + aih = malloc(sizeof(*aih), M_DEVBUF, M_WAITOK); + aih->ih_ic = ic; + aih->ih_ih = cookie; + + return aih; +} + +void +acpi_intr_disestablish(void *cookie) +{ + struct machine_intr_handle *aih = cookie; + struct interrupt_controller *ic = aih->ih_ic; + + ic->ic_disestablish(aih->ih_ih); + free(aih, M_DEVBUF, sizeof(*aih)); +} + +bus_dma_tag_t +acpi_iommu_device_map(struct aml_node *node, bus_dma_tag_t dmat) +{ + return acpiiort_device_map(node, dmat); +} diff --git sys/arch/loongarch64/loongarch64/acpiapm.c sys/arch/loongarch64/loongarch64/acpiapm.c new file mode 100644 index 00000000000..18bcfc6c46e --- /dev/null +++ sys/arch/loongarch64/loongarch64/acpiapm.c @@ -0,0 +1,58 @@ +/* $OpenBSD: acpiapm.c,v 1.2 2020/04/03 08:24:52 mpi Exp $ */ +/* + * Copyright (c) 2007 Ted Unangst + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + + +int (*acpiapm_open)(dev_t, int, int, struct proc *); +int (*acpiapm_close)(dev_t, int, int, struct proc *); +int (*acpiapm_ioctl)(dev_t, u_long, caddr_t, int, struct proc *); +int (*acpiapm_kqfilter)(dev_t, struct knote *); + +int +acpiapmopen(dev_t dev, int flag, int mode, struct proc *p) +{ + if (!acpiapm_open) + return ENODEV; + return acpiapm_open(dev, flag, mode, p); +} + +int +acpiapmclose(dev_t dev, int flag, int mode, struct proc *p) +{ + if (!acpiapm_close) + return ENODEV; + return acpiapm_close(dev, flag, mode, p); +} + +int +acpiapmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) +{ + if (!acpiapm_ioctl) + return ENODEV; + return acpiapm_ioctl(dev, cmd, data, flag, p); +} + +int +acpiapmkqfilter(dev_t dev, struct knote *kn) +{ + if (!acpiapm_kqfilter) + return EOPNOTSUPP; + return acpiapm_kqfilter(dev, kn); +} diff --git sys/arch/loongarch64/loongarch64/ast.c sys/arch/loongarch64/loongarch64/ast.c new file mode 100644 index 00000000000..a58ce10ad05 --- /dev/null +++ sys/arch/loongarch64/loongarch64/ast.c @@ -0,0 +1,46 @@ +/* $OpenBSD: ast.c,v 1.5 2026/03/08 17:07:31 deraadt Exp $ */ + +/* + * Copyright (c) 2015 Dale Rahn + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +/* + * Transform cpu ast to mi_ast + */ + +void +ast(struct trapframe *tf) +{ + struct proc *p = curcpu()->ci_curproc; + + p->p_addr->u_pcb.pcb_tf = tf; + + refreshcreds(p); + atomic_inc_int(&uvmexp.softs); + mi_ast(p, curcpu()->ci_want_resched); + userret(p); +} diff --git sys/arch/loongarch64/loongarch64/autoconf.c sys/arch/loongarch64/loongarch64/autoconf.c new file mode 100644 index 00000000000..40adc591e32 --- /dev/null +++ sys/arch/loongarch64/loongarch64/autoconf.c @@ -0,0 +1,113 @@ +/* $OpenBSD: autoconf.c,v 1.10 2026/05/02 14:09:17 jsing Exp $ */ + +/* + * Copyright (c) 2009 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#if defined(NFSCLIENT) +#include +#include +#include +#include +#endif + +extern void dumpconf(void); + +void +unmap_startup(void) +{ + extern void *_start, *endboot; + vaddr_t p = (vaddr_t)&_start; + + do { + pmap_kremove(p, PAGE_SIZE); + p += PAGE_SIZE; + } while (p < (vaddr_t)&endboot); +} + +void +cpu_configure(void) +{ + splhigh(); + + softintr_init(); + bus_dma_init(); + + config_rootfound("mainbus", NULL); + + unmap_startup(); + + cpu_identify_cleanup(); + + cold = 0; + spl0(); +} + +void +diskconf(void) +{ +#if defined(NFSCLIENT) + extern uint8_t *bootmac; + dev_t tmpdev = NODEV; +#endif + struct device *bootdv = NULL; + int part = 0; + +#if defined(NFSCLIENT) + if (bootmac) { + struct ifnet *ifp; + + TAILQ_FOREACH(ifp, &ifnetlist, if_list) { + if (ifp->if_type == IFT_ETHER && + memcmp(bootmac, ((struct arpcom *)ifp)->ac_enaddr, + ETHER_ADDR_LEN) == 0) + break; + } + if (ifp) + bootdv = parsedisk(ifp->if_xname, strlen(ifp->if_xname), + 0, &tmpdev); + } +#endif + + setroot(bootdv, part, RB_USERREQ); + dumpconf(); + +#ifdef HIBERNATE + hibernate_resume(); +#endif /* HIBERNATE */ +} + +void +device_register(struct device *dev, void *aux) +{ +} + +const struct nam2blk nam2blk[] = { + { "wd", 0 }, + { "sd", 4 }, + { "cd", 6 }, + { "rd", 8 }, + { "vnd", 14 }, + { NULL, -1 } +}; diff --git sys/arch/loongarch64/loongarch64/bus_dma.c sys/arch/loongarch64/loongarch64/bus_dma.c new file mode 100644 index 00000000000..150c5c9ea23 --- /dev/null +++ sys/arch/loongarch64/loongarch64/bus_dma.c @@ -0,0 +1,1007 @@ +/* $OpenBSD: bus_dma.c,v 1.12 2026/08/07 19:07:30 kettenis Exp $ */ + +/* + * Copyright (c) 2003-2004 Opsycon AB (www.opsycon.se / www.opsycon.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +/*- + * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "kstat.h" + +#include +#include +#include +#include +#include + +#if NKSTAT > 0 +#include +#endif + +#include + +#include +#include +#include + +u_long bus_dma_high_pages; +u_long bus_dma_bounce_pages; +u_long bus_dma_bounces; + +#if NKSTAT > 0 +struct bus_dma_kstat_data { + struct kstat_kv kd_bounce_pages; + struct kstat_kv kd_bounces; +}; + +static const struct bus_dma_kstat_data bus_dma_kstat_tpl = { + KSTAT_KV_INITIALIZER("bounce-pages", KSTAT_KV_T_COUNTER64), + KSTAT_KV_INITIALIZER("bounces", KSTAT_KV_T_COUNTER64), +}; + +int +bus_dma_kstat_copy(struct kstat *ks, void *dst) +{ + struct bus_dma_kstat_data *kd = dst; + + *kd = bus_dma_kstat_tpl; + kstat_kv_u64(&kd->kd_bounce_pages) = bus_dma_bounce_pages; + kstat_kv_u64(&kd->kd_bounces) = bus_dma_bounces; + + return 0; +} +#endif + +void +bus_dma_init(void) +{ + struct uvm_constraint_range high_constraint; +#if NKSTAT > 0 + struct kstat *ks; +#endif + + high_constraint.ucr_low = dma_constraint.ucr_high; + high_constraint.ucr_high = no_constraint.ucr_high; + if (high_constraint.ucr_low != high_constraint.ucr_high) + high_constraint.ucr_low++; + + bus_dma_high_pages = uvm_pagecount(&high_constraint); + +#if NKSTAT > 0 + ks = kstat_create("mainbus0", 0, "dma", 0, KSTAT_T_KV, 0); + if (ks == NULL) + return; + + ks->ks_datalen = sizeof(bus_dma_kstat_tpl); + ks->ks_copy = bus_dma_kstat_copy; + kstat_install(ks); +#endif +} + +/* + * Common function for DMA map creation. May be called by bus-specific + * DMA map creation functions. + */ +int +_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments, + bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamp) +{ + int use_bounce_buffer = 0; + struct machine_bus_dmamap *map; + struct pglist mlist; + paddr_t low = 0, high = (paddr_t)-1; + struct vm_page **pg, *pgnext; + size_t mapsize, sz, ssize; + vaddr_t va, sva; + void *mapstore; + int npages, error; + const struct kmem_dyn_mode *kd; + + if ((flags & BUS_DMA_64BIT) == 0 && bus_dma_high_pages > 0) { + use_bounce_buffer = 1; + low = dma_constraint.ucr_low; + high = dma_constraint.ucr_high; + } + + if (t->_low != 0) { + use_bounce_buffer = 1; + low = MAX(t->_low, low); + } + if (t->_high != (paddr_t)-1) { + use_bounce_buffer = 1; + high = MIN(t->_high, high); + } + + /* + * Allocate and initialize the DMA map. The end of the map + * is a variable-sized array of segments, so we allocate enough + * room for them in one shot. + * + * Note we don't preserve the WAITOK or NOWAIT flags. Preservation + * of ALLOCNOW notifies others that we've reserved these resources, + * and they are not to be freed. + * + * The bus_dmamap_t includes one bus_dma_segment_t, hence + * the (nsegments - 1). + */ + mapsize = sizeof(struct machine_bus_dmamap) + + (sizeof(bus_dma_segment_t) * (nsegments - 1)); + + if (use_bounce_buffer) { + /* this many pages plus one in case we get split */ + npages = round_page(size) / PAGE_SIZE + 1; + if (npages < nsegments) + npages = nsegments; + mapsize += sizeof(struct vm_page *) * npages; + atomic_add_long(&bus_dma_bounce_pages, npages); + } + + if ((mapstore = malloc(mapsize, M_DEVBUF, (flags & BUS_DMA_NOWAIT) ? + (M_NOWAIT | M_ZERO) : (M_WAITOK | M_ZERO))) == NULL) + return (ENOMEM); + + map = (struct machine_bus_dmamap *)mapstore; + map->_dm_size = size; + map->_dm_segcnt = nsegments; + map->_dm_maxsegsz = maxsegsz; + map->_dm_boundary = boundary; + map->_dm_low = low; + map->_dm_high = high; + if (use_bounce_buffer) { + map->_dm_pages = (void *)&map->dm_segs[nsegments]; + map->_dm_npages = npages; + } + map->_dm_flags = flags & ~(BUS_DMA_WAITOK|BUS_DMA_NOWAIT); + + if (!use_bounce_buffer) { + *dmamp = map; + return (0); + } + + sz = npages << PGSHIFT; + kd = flags & BUS_DMA_NOWAIT ? &kd_trylock : &kd_waitok; + va = (vaddr_t)km_alloc(sz, &kv_any, &kp_none, kd); + if (va == 0) { + map->_dm_npages = 0; + free(map, M_DEVBUF, mapsize); + return (ENOMEM); + } + + TAILQ_INIT(&mlist); + error = uvm_pglistalloc(sz, map->_dm_low, map->_dm_high, + PAGE_SIZE, 0, &mlist, nsegments, + (flags & BUS_DMA_NOWAIT) ? UVM_PLA_NOWAIT : UVM_PLA_WAITOK); + if (error) { + map->_dm_npages = 0; + km_free((void *)va, sz, &kv_any, &kp_none); + free(map, M_DEVBUF, mapsize); + return (ENOMEM); + } + + sva = va; + ssize = sz; + pgnext = TAILQ_FIRST(&mlist); + for (pg = map->_dm_pages; npages--; va += PAGE_SIZE, pg++) { + *pg = pgnext; + pmap_kenter_pa(va, VM_PAGE_TO_PHYS(*pg), + PROT_READ | PROT_WRITE); + pgnext = TAILQ_NEXT(*pg, pageq); + memset((void *)va, 0, PAGE_SIZE); + } + pmap_update(pmap_kernel()); + map->_dm_pgva = sva; + + *dmamp = map; + return (0); +} + +/* + * Common function for DMA map destruction. May be called by bus-specific + * DMA map destruction functions. + */ +void +_dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map) +{ + size_t mapsize; + struct vm_page **pg; + struct pglist mlist; + + if (map->_dm_pgva) { + km_free((void *)map->_dm_pgva, map->_dm_npages << PGSHIFT, + &kv_any, &kp_none); + } + + mapsize = sizeof(struct machine_bus_dmamap) + + (sizeof(bus_dma_segment_t) * (map->_dm_segcnt - 1)); + mapsize += sizeof(struct vm_page *) * map->_dm_npages; + + if (map->_dm_pages) { + TAILQ_INIT(&mlist); + for (pg = map->_dm_pages; map->_dm_npages--; pg++) { + TAILQ_INSERT_TAIL(&mlist, *pg, pageq); + } + uvm_pglistfree(&mlist); + } + + free(map, M_DEVBUF, mapsize); +} + +/* + * Common function for loading a DMA map with a linear buffer. May + * be called by bus-specific DMA map load functions. + */ +int +_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf, bus_size_t buflen, + struct proc *p, int flags) +{ + paddr_t lastaddr; + int seg, used, error; + int lastbounce; + + /* + * Make sure that on error condition we return "no valid mappings". + */ + map->dm_nsegs = 0; + map->dm_mapsize = 0; + + if (buflen > map->_dm_size) + return (EINVAL); + + seg = 0; + used = 0; + lastbounce = 0; + error = (*t->_dmamap_load_buffer)(t, map, buf, buflen, p, flags, + &lastaddr, &seg, &used, &lastbounce, 1); + if (error == 0) { + map->dm_nsegs = seg + 1; + map->dm_mapsize = buflen; + map->_dm_nused = used; + } + + return (error); +} + +/* + * Like _bus_dmamap_load(), but for mbufs. + */ +int +_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *m0, int flags) +{ + paddr_t lastaddr; + int seg, used, error, first; + int lastbounce; + struct mbuf *m; + + /* + * Make sure that on error condition we return "no valid mappings". + */ + map->dm_nsegs = 0; + map->dm_mapsize = 0; + +#ifdef DIAGNOSTIC + if ((m0->m_flags & M_PKTHDR) == 0) + panic("_dmamap_load_mbuf: no packet header"); +#endif + + if (m0->m_pkthdr.len > map->_dm_size) + return (EINVAL); + + first = 1; + seg = 0; + used = 0; + lastbounce = 0; + error = 0; + for (m = m0; m != NULL && error == 0; m = m->m_next) { + if (m->m_len == 0) + continue; + error = (*t->_dmamap_load_buffer)(t, map, m->m_data, m->m_len, + NULL, flags, &lastaddr, &seg, &used, &lastbounce, first); + first = 0; + } + if (error == 0) { + map->dm_mapsize = m0->m_pkthdr.len; + map->dm_nsegs = seg + 1; + map->_dm_nused = used; + } + + return (error); +} + +/* + * Like _dmamap_load(), but for uios. + */ +int +_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map, struct uio *uio, int flags) +{ + paddr_t lastaddr; + int seg, used, i, error, first; + int lastbounce; + bus_size_t minlen, resid; + struct proc *p = NULL; + struct iovec *iov; + void *addr; + + /* + * Make sure that on error condition we return "no valid mappings". + */ + map->dm_nsegs = 0; + map->dm_mapsize = 0; + + resid = uio->uio_resid; + iov = uio->uio_iov; + + if (uio->uio_segflg == UIO_USERSPACE) { + p = uio->uio_procp; +#ifdef DIAGNOSTIC + if (p == NULL) + panic("_dmamap_load_uio: USERSPACE but no proc"); +#endif + } + + first = 1; + seg = 0; + used = 0; + lastbounce = 0; + error = 0; + for (i = 0; i < uio->uio_iovcnt && resid != 0 && error == 0; i++) { + /* + * Now at the first iovec to load. Load each iovec + * until we have exhausted the residual count. + */ + minlen = resid < iov[i].iov_len ? resid : iov[i].iov_len; + addr = (void *)iov[i].iov_base; + + error = (*t->_dmamap_load_buffer)(t, map, addr, minlen, + p, flags, &lastaddr, &seg, &used, &lastbounce, first); + first = 0; + + resid -= minlen; + } + if (error == 0) { + map->dm_nsegs = seg + 1; + map->dm_mapsize = uio->uio_resid; + map->_dm_nused = used; + } + + return (error); +} + +/* + * Like _dmamap_load(), but for raw memory allocated with + * bus_dmamem_alloc(). + */ +int +_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map, bus_dma_segment_t *segs, + int nsegs, bus_size_t size, int flags) +{ + bus_addr_t paddr, baddr, bmask, lastaddr = 0; + bus_size_t plen, sgsize, mapsize; + int bounce, lastbounce = 0; + int first = 1; + int i, seg = 0; + int off, page = 0; + vaddr_t pgva, vaddr; + + /* + * Make sure that on error condition we return "no valid mappings". + */ + map->dm_mapsize = 0; + map->dm_nsegs = 0; + + if (nsegs > map->_dm_segcnt || size > map->_dm_size) + return (EINVAL); + + mapsize = size; + bmask = ~(map->_dm_boundary - 1); + + /* + * Assume the mapping is coherent until we run into a segment + * that isn't. + */ + map->_dm_flags |= BUS_DMA_COHERENT; + + for (i = 0; i < nsegs && size > 0; i++) { + paddr = segs[i].ds_addr; + vaddr = segs[i]._ds_vaddr; + plen = MIN(segs[i].ds_len, size); + + if (!segs[i]._ds_coherent) + map->_dm_flags &= ~BUS_DMA_COHERENT; + + bounce = 0; + if (paddr + plen - 1 > dma_constraint.ucr_high && + (map->_dm_flags & BUS_DMA_64BIT) == 0) + bounce = 1; + if (paddr < map->_dm_low || paddr + plen - 1 > map->_dm_high) + bounce = 1; + + while (plen > 0) { + if (bounce) { + if (page >= map->_dm_npages) + return (EFBIG); + + off = paddr & PAGE_MASK; + pgva = map->_dm_pgva + (page << PGSHIFT) + off; + page++; + } else { + pgva = -1; + } + + /* + * Compute the segment size, and adjust counts. + */ + sgsize = PAGE_SIZE - ((u_long)paddr & PGOFSET); + if (plen < sgsize) + sgsize = plen; + + /* + * Make sure we don't cross any boundaries. + */ + if (map->_dm_boundary > 0) { + baddr = (paddr + map->_dm_boundary) & bmask; + if (sgsize > (baddr - paddr)) + sgsize = (baddr - paddr); + } + + /* + * Insert chunk into a segment, coalescing with + * previous segment if possible. + */ + if (first) { + map->dm_segs[seg].ds_addr = paddr; + map->dm_segs[seg].ds_len = sgsize; + map->dm_segs[seg]._ds_paddr = paddr; + map->dm_segs[seg]._ds_vaddr = vaddr; + map->dm_segs[seg]._ds_bounce_va = pgva; + first = 0; + } else { + if (paddr == lastaddr && + bounce == lastbounce && + (map->dm_segs[seg].ds_len + sgsize) <= + map->_dm_maxsegsz && + (map->_dm_boundary == 0 || + (map->dm_segs[seg].ds_addr & bmask) == + (paddr & bmask)) && + ((t->_flags & BUS_DMA_COHERENT && !bounce) || + (map->dm_segs[seg]._ds_vaddr + + map->dm_segs[seg].ds_len == vaddr))) + map->dm_segs[seg].ds_len += sgsize; + else { + if (++seg >= map->_dm_segcnt) + return (EINVAL); + map->dm_segs[seg].ds_addr = paddr; + map->dm_segs[seg].ds_len = sgsize; + map->dm_segs[seg]._ds_paddr = paddr; + map->dm_segs[seg]._ds_vaddr = vaddr; + map->dm_segs[seg]._ds_bounce_va = pgva; + } + } + + paddr += sgsize; + vaddr += sgsize; + plen -= sgsize; + size -= sgsize; + + lastaddr = paddr; + lastbounce = bounce; + } + } + + map->dm_mapsize = mapsize; + map->dm_nsegs = seg + 1; + map->_dm_nused = page; + return (0); +} + +/* + * Common function for unloading a DMA map. May be called by + * bus-specific DMA map unload functions. + */ +void +_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map) +{ + /* + * No resources to free; just mark the mappings as + * invalid. + */ + map->dm_nsegs = 0; + map->dm_mapsize = 0; + map->_dm_nused = 0; +} + +static void +_dmamap_sync_segment(vaddr_t va, vsize_t len, int ops) +{ + switch (ops) { + case BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE: + case BUS_DMASYNC_PREREAD: + cpu_dcache_wbinv_range(va, len); + break; + + case BUS_DMASYNC_PREWRITE: + cpu_dcache_wb_range(va, len); + break; + + /* + * RISC-V CPUs can do speculative loads so we need to clean the cache + * after a DMA read to deal with any speculatively loaded cache lines. + * Since these can't be dirty, we can just invalidate them and don't + * have to worry about having to write back their contents. + */ + case BUS_DMASYNC_POSTREAD: + case BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE: + membar_sync(); + cpu_dcache_inv_range(va, len); + break; + } +} + +/* + * Common function for DMA map synchronization. May be called + * by bus-specific DMA map synchronization functions. + */ +void +_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t addr, + bus_size_t size, int op) +{ + int coherent = 0; + int bounce = 0; + int nsegs; + int curseg; + + if (t->_flags & BUS_DMA_COHERENT || + map->_dm_flags & BUS_DMA_COHERENT) + coherent = 1; + + if (map->_dm_nused > 0) + bounce = 1; + + /* + * If we're fully coherent, just make sure the write buffer is + * synced and return. + */ + if (coherent && !bounce) { + __asm volatile ("ibar 0" ::: "memory"); + return; + } + + nsegs = map->dm_nsegs; + curseg = 0; + + while (size && nsegs) { + vaddr_t bounce_va; + vaddr_t flush_va; + vaddr_t vaddr; + bus_size_t ssize; + + ssize = map->dm_segs[curseg].ds_len; + vaddr = map->dm_segs[curseg]._ds_vaddr; + bounce_va = map->dm_segs[curseg]._ds_bounce_va; + + if (addr != 0) { + if (addr >= ssize) { + addr -= ssize; + ssize = 0; + } else { + vaddr += addr; + if (bounce_va != -1) + bounce_va += addr; + ssize -= addr; + addr = 0; + } + } + if (ssize > size) + ssize = size; + + if (ssize != 0) { + if (bounce_va != -1) + flush_va = bounce_va; + else + flush_va = vaddr; + + if (bounce_va != -1 && (op & BUS_DMASYNC_PREWRITE)) { + memcpy((void *)bounce_va, (void *)vaddr, + ssize); + atomic_inc_long(&bus_dma_bounces); + } + + if ((t->_flags & BUS_DMA_COHERENT) == 0) + _dmamap_sync_segment(flush_va, ssize, op); + + if (bounce_va != -1 && (op & BUS_DMASYNC_POSTREAD)) { + memcpy((void *)vaddr, (void *)bounce_va, + ssize); + atomic_inc_long(&bus_dma_bounces); + } + + size -= ssize; + } + curseg++; + nsegs--; + } + + if (size != 0) { + panic("_dmamap_sync: ran off map!"); + } +} + +/* + * Common function for DMA-safe memory allocation. May be called + * by bus-specific DMA memory allocation functions. + */ +int +_dmamem_alloc(bus_dma_tag_t t, bus_size_t size, bus_size_t alignment, + bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs, + int flags) +{ + return _dmamem_alloc_range(t, size, alignment, boundary, + segs, nsegs, rsegs, flags, dma_constraint.ucr_low, + dma_constraint.ucr_high); +} + +/* + * Common function for freeing DMA-safe memory. May be called by + * bus-specific DMA memory free functions. + */ +void +_dmamem_free(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs) +{ + vm_page_t m; + bus_addr_t addr; + struct pglist mlist; + int curseg; + + /* + * Build a list of pages to free back to the VM system. + */ + TAILQ_INIT(&mlist); + for (curseg = 0; curseg < nsegs; curseg++) { + for (addr = segs[curseg].ds_addr; + addr < (segs[curseg].ds_addr + segs[curseg].ds_len); + addr += PAGE_SIZE) { + m = PHYS_TO_VM_PAGE(addr); + TAILQ_INSERT_TAIL(&mlist, m, pageq); + } + } + + uvm_pglistfree(&mlist); +} + +/* + * Common function for mapping DMA-safe memory. May be called by + * bus-specific DMA memory map functions. + */ +int +_dmamem_map(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs, size_t size, + caddr_t *kvap, int flags) +{ + vaddr_t va, sva; + size_t ssize; + bus_addr_t addr; + int curseg, pmap_flags, cache; + const struct kmem_dyn_mode *kd; + + size = round_page(size); + kd = flags & BUS_DMA_NOWAIT ? &kd_trylock : &kd_waitok; + va = (vaddr_t)km_alloc(size, &kv_any, &kp_none, kd); + if (va == 0) + return (ENOMEM); + + *kvap = (caddr_t)va; + + sva = va; + ssize = size; + pmap_flags = PMAP_WIRED | PMAP_CANFAIL; + cache = PMAP_CACHE_WB; + if (((t->_flags & BUS_DMA_COHERENT) == 0 && + (flags & BUS_DMA_COHERENT)) || (flags & BUS_DMA_NOCACHE)) + cache = PMAP_CACHE_CI; + for (curseg = 0; curseg < nsegs; curseg++) { + segs[curseg]._ds_vaddr = va; + segs[curseg]._ds_coherent = !!(flags & BUS_DMA_COHERENT); + for (addr = segs[curseg].ds_addr; + addr < (segs[curseg].ds_addr + segs[curseg].ds_len); + addr += NBPG, va += NBPG, size -= NBPG) { + if (size == 0) + panic("_dmamem_map: size botch"); + pmap_kenter_cache(va, addr, + PROT_READ | PROT_WRITE | pmap_flags, + cache); + } + pmap_update(pmap_kernel()); + } + + return (0); +} + +/* + * Common function for unmapping DMA-safe memory. May be called by + * bus-specific DMA memory unmapping functions. + */ +void +_dmamem_unmap(bus_dma_tag_t t, caddr_t kva, size_t size) +{ + km_free(kva, round_page(size), &kv_any, &kp_none); +} + +/* + * Common function for mmap(2)'ing DMA-safe memory. May be called by + * bus-specific DMA mmap(2)'ing functions. + */ +paddr_t +_dmamem_mmap(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs, off_t off, + int prot, int flags) +{ + int i, pmapflags = 0; + + if (flags & BUS_DMA_NOCACHE) + pmapflags |= PMAP_NOCACHE; + + for (i = 0; i < nsegs; i++) { +#ifdef DIAGNOSTIC + if (off & PGOFSET) + panic("_dmamem_mmap: offset unaligned"); + if (segs[i].ds_addr & PGOFSET) + panic("_dmamem_mmap: segment unaligned"); + if (segs[i].ds_len & PGOFSET) + panic("_dmamem_mmap: segment size not multiple" + " of page size"); +#endif + if (off >= segs[i].ds_len) { + off -= segs[i].ds_len; + continue; + } + + return ((segs[i].ds_addr + off) | pmapflags); + } + + /* Page not found. */ + return (-1); +} + +/********************************************************************** + * DMA utility functions + **********************************************************************/ + +/* + * Utility function to load a linear buffer. lastaddrp holds state + * between invocations (for multiple-buffer loads). segp contains + * the starting segment on entrance, and the ending segment on exit. + * first indicates if this is the first invocation of this function. + */ +int +_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map, void *buf, + bus_size_t buflen, struct proc *p, int flags, paddr_t *lastaddrp, + int *segp, int *usedp, int *lastbouncep, int first) +{ + bus_size_t sgsize; + bus_addr_t lastaddr, baddr, bmask; + paddr_t curaddr; + vaddr_t pgva, vaddr = (vaddr_t)buf; + int bounce, lastbounce; + int seg, page, off; + pmap_t pmap; + struct vm_page *pg; + + if (p != NULL) + pmap = p->p_vmspace->vm_map.pmap; + else + pmap = pmap_kernel(); + + page = *usedp; + lastaddr = *lastaddrp; + lastbounce = *lastbouncep; + bmask = ~(map->_dm_boundary - 1); + if (t->_dma_mask != 0) + bmask &= t->_dma_mask; + + for (seg = *segp; buflen > 0; ) { + /* + * Get the physical address for this segment. + */ + if (pmap_extract(pmap, vaddr, &curaddr) == FALSE) + panic("_dmapmap_load_buffer: pmap_extract(%p, %lx) failed!", + pmap, vaddr); + + bounce = 0; + if (curaddr > dma_constraint.ucr_high && + (map->_dm_flags & BUS_DMA_64BIT) == 0) + bounce = 1; + if (curaddr < map->_dm_low || curaddr > map->_dm_high) + bounce = 1; + + if (bounce) { + if (page >= map->_dm_npages) + return (EFBIG); + + off = vaddr & PAGE_MASK; + pg = map->_dm_pages[page]; + curaddr = VM_PAGE_TO_PHYS(pg) + off; + pgva = map->_dm_pgva + (page << PGSHIFT) + off; + page++; + } else + pgva = -1; + + /* + * Compute the segment size, and adjust counts. + */ + sgsize = NBPG - ((u_long)vaddr & PGOFSET); + if (buflen < sgsize) + sgsize = buflen; + + /* + * Make sure we don't cross any boundaries. + */ + if (map->_dm_boundary > 0) { + baddr = ((bus_addr_t)curaddr + map->_dm_boundary) & + bmask; + if (sgsize > (baddr - (bus_addr_t)curaddr)) + sgsize = (baddr - (bus_addr_t)curaddr); + } + + /* + * Insert chunk into a segment, coalescing with + * previous segment if possible. + */ + if (first) { + map->dm_segs[seg].ds_addr = curaddr; + map->dm_segs[seg].ds_len = sgsize; + map->dm_segs[seg]._ds_paddr = curaddr; + map->dm_segs[seg]._ds_vaddr = vaddr; + map->dm_segs[seg]._ds_bounce_va = pgva; + first = 0; + } else { + if ((bus_addr_t)curaddr == lastaddr && + bounce == lastbounce && + (map->dm_segs[seg].ds_len + sgsize) <= + map->_dm_maxsegsz && + (map->_dm_boundary == 0 || + (map->dm_segs[seg].ds_addr & bmask) == + ((bus_addr_t)curaddr & bmask)) && + ((t->_flags & BUS_DMA_COHERENT && !bounce) || + (map->dm_segs[seg]._ds_vaddr + + map->dm_segs[seg].ds_len == vaddr))) + map->dm_segs[seg].ds_len += sgsize; + else { + if (++seg >= map->_dm_segcnt) + break; + map->dm_segs[seg].ds_addr = curaddr; + map->dm_segs[seg].ds_len = sgsize; + map->dm_segs[seg]._ds_paddr = curaddr; + map->dm_segs[seg]._ds_vaddr = vaddr; + map->dm_segs[seg]._ds_bounce_va = pgva; + } + } + + lastaddr = (bus_addr_t)curaddr + sgsize; + lastbounce = bounce; + vaddr += sgsize; + buflen -= sgsize; + } + + *segp = seg; + *usedp = page; + *lastaddrp = lastaddr; + *lastbouncep = lastbounce; + + /* + * Did we fit? + */ + if (buflen != 0) + return (EFBIG); /* XXX better return value here? */ + + return (0); +} + +/* + * Allocate physical memory from the given physical address range. + * Called by DMA-safe memory allocation methods. + */ +int +_dmamem_alloc_range(bus_dma_tag_t t, bus_size_t size, bus_size_t alignment, + bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs, + int flags, paddr_t low, paddr_t high) +{ + paddr_t curaddr, lastaddr; + vm_page_t m; + struct pglist mlist; + int curseg, error, plaflag; + + /* Always round the size. */ + size = round_page(size); + + /* + * Allocate pages from the VM system. + */ + plaflag = flags & BUS_DMA_NOWAIT ? UVM_PLA_NOWAIT : UVM_PLA_WAITOK; + if (flags & BUS_DMA_ZERO) + plaflag |= UVM_PLA_ZERO; + + TAILQ_INIT(&mlist); + error = uvm_pglistalloc(size, low, high, alignment, boundary, + &mlist, nsegs, plaflag); + if (error) + return (error); + + /* + * Compute the location, size, and number of segments actually + * returned by the VM code. + */ + m = TAILQ_FIRST(&mlist); + curseg = 0; + lastaddr = segs[curseg].ds_addr = VM_PAGE_TO_PHYS(m); + segs[curseg].ds_len = PAGE_SIZE; + m = TAILQ_NEXT(m, pageq); + + for (; m != NULL; m = TAILQ_NEXT(m, pageq)) { + curaddr = VM_PAGE_TO_PHYS(m); +#ifdef DIAGNOSTIC + if (curaddr < low || curaddr >= high) { + printf("vm_page_alloc_memory returned non-sensical" + " address 0x%lx\n", curaddr); + panic("_dmamem_alloc_range"); + } +#endif + if (curaddr == (lastaddr + PAGE_SIZE)) + segs[curseg].ds_len += PAGE_SIZE; + else { + curseg++; + segs[curseg].ds_addr = curaddr; + segs[curseg].ds_len = PAGE_SIZE; + } + lastaddr = curaddr; + } + + *rsegs = curseg + 1; + + return (0); +} diff --git sys/arch/loongarch64/loongarch64/bus_space.c sys/arch/loongarch64/loongarch64/bus_space.c new file mode 100644 index 00000000000..21a0548add1 --- /dev/null +++ sys/arch/loongarch64/loongarch64/bus_space.c @@ -0,0 +1,271 @@ +/* $OpenBSD: bus_space.c,v 1.3 2024/03/27 23:10:18 kettenis Exp $ */ + +/* + * Copyright (c) 2001-2003 Opsycon AB (www.opsycon.se / www.opsycon.com) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +/* + * Simple generic bus access primitives. + */ + +#include +#include + +#include +#include + +bus_space_t loongarch64_bs_tag = { + .bus_base = 0ULL, // XXX + .bus_private = NULL, + ._space_read_1 = generic_space_read_1, + ._space_write_1 = generic_space_write_1, + ._space_read_2 = generic_space_read_2, + ._space_write_2 = generic_space_write_2, + ._space_read_4 = generic_space_read_4, + ._space_write_4 = generic_space_write_4, + ._space_read_8 = generic_space_read_8, + ._space_write_8 = generic_space_write_8, + ._space_read_raw_2 = generic_space_read_raw_2, + ._space_write_raw_2 = generic_space_write_raw_2, + ._space_read_raw_4 = generic_space_read_raw_4, + ._space_write_raw_4 = generic_space_write_raw_4, + ._space_read_raw_8 = generic_space_read_raw_8, + ._space_write_raw_8 = generic_space_write_raw_8, + ._space_map = generic_space_map, + ._space_unmap = generic_space_unmap, + ._space_subregion = generic_space_region, + ._space_vaddr = generic_space_vaddr, + ._space_mmap = generic_space_mmap +}; +bus_space_t *fdt_cons_bs_tag = &loongarch64_bs_tag; + +uint8_t +generic_space_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o) +{ + uint8_t val = *(volatile uint8_t *)(h + o); + __asm volatile ("ibar 7" ::: "memory"); + return val; +} + +uint16_t +generic_space_read_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o) +{ + uint16_t val = *(volatile uint16_t *)(h + o); + __asm volatile ("ibar 7" ::: "memory"); + return val; +} + +uint32_t +generic_space_read_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o) +{ + uint32_t val = *(volatile uint32_t *)(h + o); + __asm volatile ("ibar 7" ::: "memory"); + return val; +} + +uint64_t +generic_space_read_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o) +{ + uint64_t val = *(volatile uint64_t *)(h + o); + __asm volatile ("ibar 7" ::: "memory"); + return val; +} + +void +generic_space_write_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, + uint8_t v) +{ + __asm volatile ("dbar 5" ::: "memory"); + *(volatile uint8_t *)(h + o) = v; + __asm volatile ("dbar 6" ::: "memory"); +} + +void +generic_space_write_2(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, + uint16_t v) +{ + __asm volatile ("dbar 5" ::: "memory"); + *(volatile uint16_t *)(h + o) = v; + __asm volatile ("dbar 6" ::: "memory"); +} + +void +generic_space_write_4(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, + uint32_t v) +{ + __asm volatile ("dbar 5" ::: "memory"); + *(volatile uint32_t *)(h + o) = v; + __asm volatile ("dbar 6" ::: "memory"); +} + +void +generic_space_write_8(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, + uint64_t v) +{ + __asm volatile ("dbar 5" ::: "memory"); + *(volatile uint64_t *)(h + o) = v; + __asm volatile ("dbar 6" ::: "memory"); +} + +void +generic_space_read_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, + uint8_t *buf, bus_size_t len) +{ + volatile uint16_t *addr = (volatile uint16_t *)(h + o); + len >>= 1; + while (len-- != 0) { + *(uint16_t *)buf = *addr; + buf += 2; + } + __asm volatile ("ibar 7" ::: "memory"); +} + +void +generic_space_write_raw_2(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, + const uint8_t *buf, bus_size_t len) +{ + volatile uint16_t *addr = (volatile uint16_t *)(h + o); + __asm volatile ("dbar 5" ::: "memory"); + len >>= 1; + while (len-- != 0) { + *addr = *(uint16_t *)buf; + buf += 2; + } + __asm volatile ("dbar 6" ::: "memory"); +} + +void +generic_space_read_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, + uint8_t *buf, bus_size_t len) +{ + volatile uint32_t *addr = (volatile uint32_t *)(h + o); + len >>= 2; + while (len-- != 0) { + *(uint32_t *)buf = *addr; + buf += 4; + } + __asm volatile ("ibar 7" ::: "memory"); +} + +void +generic_space_write_raw_4(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, + const uint8_t *buf, bus_size_t len) +{ + volatile uint32_t *addr = (volatile uint32_t *)(h + o); + __asm volatile ("dbar 5" ::: "memory"); + len >>= 2; + while (len-- != 0) { + *addr = *(uint32_t *)buf; + buf += 4; + } + __asm volatile ("dbar 6" ::: "memory"); +} + +void +generic_space_read_raw_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, + uint8_t *buf, bus_size_t len) +{ + volatile uint64_t *addr = (volatile uint64_t *)(h + o); + len >>= 3; + while (len-- != 0) { + *(uint64_t *)buf = *addr; + buf += 8; + } + __asm volatile ("ibar 7" ::: "memory"); +} + +void +generic_space_write_raw_8(bus_space_tag_t t, bus_space_handle_t h, bus_addr_t o, + const uint8_t *buf, bus_size_t len) +{ + volatile uint64_t *addr = (volatile uint64_t *)(h + o); + __asm volatile ("dbar 5" ::: "memory"); + len >>= 3; + while (len-- != 0) { + *addr = *(uint64_t *)buf; + buf += 8; + } + __asm volatile ("dbar 6" ::: "memory"); +} + +int +generic_space_map(bus_space_tag_t t, bus_addr_t offs, bus_size_t size, + int flags, bus_space_handle_t *bshp) +{ + u_long startpa, endpa, pa; + vaddr_t va; + int cache = flags & BUS_SPACE_MAP_CACHEABLE ? + PMAP_CACHE_WB : PMAP_CACHE_DEV; + + startpa = trunc_page(offs); + endpa = round_page(offs + size); + + va = (vaddr_t)km_alloc(endpa - startpa, &kv_any, &kp_none, &kd_nowait); + if (! va) + return(ENOMEM); + + *bshp = (bus_space_handle_t)(va + (offs - startpa)); + + for (pa = startpa; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE) { + pmap_kenter_cache(va, pa, PROT_READ | PROT_WRITE, cache); + } + pmap_update(pmap_kernel()); + + return(0); +} + +void +generic_space_unmap(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size) +{ + vaddr_t va, endva; + + va = trunc_page((vaddr_t)bsh); + endva = round_page((vaddr_t)bsh + size); + + pmap_kremove(va, endva - va); + pmap_update(pmap_kernel()); + km_free((void *)va, endva - va, &kv_any, &kp_none); +} + +int +generic_space_region(bus_space_tag_t t, bus_space_handle_t bsh, + bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp) +{ + *nbshp = bsh + offset; + return 0; +} + +void * +generic_space_vaddr(bus_space_tag_t t, bus_space_handle_t h) +{ + return (void *)h; +} + +paddr_t +generic_space_mmap(bus_space_tag_t t, bus_addr_t addr, off_t off, + int prot, int flags) +{ + return (addr + off); +} diff --git sys/arch/loongarch64/loongarch64/clock.c sys/arch/loongarch64/loongarch64/clock.c new file mode 100644 index 00000000000..44a3197cf13 --- /dev/null +++ sys/arch/loongarch64/loongarch64/clock.c @@ -0,0 +1,172 @@ +/* $OpenBSD: clock.c,v 1.15 2026/07/27 11:39:45 jca Exp $ */ + +/* + * Copyright (c) 2020 Mark Kettenis + * Copyright (c) 2003 Dale Rahn + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +extern uint64_t tb_freq; /* machdep.c */ +uint64_t timer_nsec_max; +uint64_t timer_nsec_cycle_ratio; + +struct evcount clock_count; + +void timer_startclock(void); +void timer_rearm(void *, uint64_t); +void timer_trigger(void *); + +const struct intrclock timer_intrclock = { + .ic_rearm = timer_rearm, + .ic_trigger = timer_trigger +}; + +u_int tb_get_timecount(struct timecounter *); + +static struct timecounter tb_timecounter = { + .tc_get_timecount = tb_get_timecount, + .tc_counter_mask = 0xffffffff, + .tc_frequency = 0, + .tc_name = "tb", + .tc_quality = 0, + .tc_priv = NULL, + .tc_user = TC_TB, +}; + +void (*cpu_startclock_fcn)(void) = timer_startclock; +int clock_intr(void *); + +static inline void +timer_set(uint64_t nsecs) +{ + sbi_set_timer(nsecs); +} + +void +timer_rearm(void *unused, uint64_t nsecs) +{ + uint32_t cycles; + + if (nsecs > timer_nsec_max) + nsecs = timer_nsec_max; + cycles = (nsecs * timer_nsec_cycle_ratio) >> 32; + timer_set(rdtime() + cycles); +} + +void +timer_trigger(void *unused) +{ + timer_set(0); +} + +u_int +tb_get_timecount(struct timecounter *tc) +{ + return rdtime(); +} + +void +cpu_initclocks(void) +{ + tb_timecounter.tc_frequency = tb_freq; + tc_init(&tb_timecounter); + + stathz = hz; + profhz = stathz * 10; + statclock_is_randomized = 1; + + if (cpu_startclock_fcn == timer_startclock) { + timer_nsec_cycle_ratio = tb_freq * (1ULL << 32) / 1000000000; + timer_nsec_max = UINT64_MAX / timer_nsec_cycle_ratio; + + loongarch_intc_intr_establish(IRQ_TIMER_SUPERVISOR, 0, + clock_intr, NULL, NULL); + + evcount_attach(&clock_count, "clock", NULL); + evcount_percpu(&clock_count); + } +} + +void +timer_startclock(void) +{ + clockintr_cpu_init(&timer_intrclock); + clockintr_trigger(); + csr_set(LOONGARCH_CSR_ECFG, SIE_STIE); +} + +void +cpu_startclock(void) +{ + cpu_startclock_fcn(); +} + +int +clock_intr(void *frame) +{ + struct cpu_info *ci = curcpu(); + int s; + + timer_set(UINT64_MAX); /* clear timer interrupt */ + + /* + * If the clock interrupt is masked, defer all clock interrupt + * work until the clock interrupt is unmasked from splx(9). + */ + if (ci->ci_cpl >= IPL_CLOCK) { + ci->ci_timer_deferred = 1; + return 0; + } + ci->ci_timer_deferred = 0; + + s = splclock(); + intr_enable(); + clockintr_dispatch(frame); + intr_disable(); + splx(s); + + evcount_inc(&clock_count); + + return 0; +} + +void +setstatclockrate(int newhz) +{ +} + +void +delay(u_int us) +{ + uint64_t tb; + + tb = rdtime(); + tb += (us * tb_freq + 999999) / 1000000; + while (tb > rdtime()) + continue; +} diff --git sys/arch/loongarch64/loongarch64/conf.c sys/arch/loongarch64/loongarch64/conf.c new file mode 100644 index 00000000000..04ffa87ad49 --- /dev/null +++ sys/arch/loongarch64/loongarch64/conf.c @@ -0,0 +1,357 @@ +/* $OpenBSD: conf.c,v 1.18 2024/06/11 09:21:32 jsg Exp $ */ + +/* + * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "wd.h" +bdev_decl(wd); +#include "sd.h" +#include "cd.h" +#include "uk.h" +#include "vnd.h" +#include "rd.h" + +struct bdevsw bdevsw[] = +{ + bdev_disk_init(NWD,wd), /* 0: ST506/ESDI/IDE disk */ + bdev_swap_init(1,sw), /* 1: swap pseudo-device */ + bdev_notdef(), /* 2: was floppy diskette */ + bdev_notdef(), /* 3 */ + bdev_disk_init(NSD,sd), /* 4: SCSI disk */ + bdev_notdef(), /* 5: was: SCSI tape */ + bdev_disk_init(NCD,cd), /* 6: SCSI CD-ROM */ + bdev_notdef(), /* 7 */ + bdev_disk_init(NRD,rd), /* 8: ram disk driver */ + bdev_notdef(), /* 9 */ + bdev_notdef(), /* 10 */ + bdev_notdef(), /* 11 */ + bdev_notdef(), /* 12 */ + bdev_notdef(), /* 13 */ + bdev_disk_init(NVND,vnd), /* 14: vnode disk driver */ + bdev_notdef(), /* 15: was: Sony CD-ROM */ + bdev_notdef(), /* 16: was: concatenated disk driver */ + bdev_notdef(), /* 17 */ + bdev_notdef(), /* 18 */ +}; +int nblkdev = nitems(bdevsw); + +#define mmread mmrw +#define mmwrite mmrw +cdev_decl(mm); +cdev_decl(wd); +#include "bio.h" +#include "pty.h" +#include "com.h" +cdev_decl(com); +#include "lpt.h" +cdev_decl(lpt); +#include "ch.h" +#include "bpfilter.h" +#include "tun.h" +#include "audio.h" +#include "video.h" +#include "midi.h" +#include "ksyms.h" +#include "kstat.h" +#include "usb.h" +#include "uhid.h" +#include "fido.h" +#include "ujoy.h" +#include "ugen.h" +#include "ulpt.h" +#include "ucom.h" +#include "radio.h" +#include "drm.h" + +#include "wsdisplay.h" +#include "wskbd.h" +#include "wsmouse.h" +#include "wsmux.h" + +#ifdef USER_PCICONF +#include "pci.h" +cdev_decl(pci); +#endif + +#include "dt.h" +#include "pf.h" +#include "hotplug.h" +#include "vscsi.h" +#include "pppx.h" +#include "fuse.h" +#include "openprom.h" +#include "gpio.h" +#include "ipmi.h" + +struct cdevsw cdevsw[] = +{ + cdev_cn_init(1,cn), /* 0: virtual console */ + cdev_ctty_init(1,ctty), /* 1: controlling terminal */ + cdev_mm_init(1,mm), /* 2: /dev/{null,mem,kmem,...} */ + cdev_disk_init(NWD,wd), /* 3: ST506/ESDI/IDE disk */ + cdev_notdef(), /* 4 was /dev/drum */ + cdev_tty_init(NPTY,pts), /* 5: pseudo-tty slave */ + cdev_ptc_init(NPTY,ptc), /* 6: pseudo-tty master */ + cdev_log_init(1,log), /* 7: /dev/klog */ + cdev_tty_init(NCOM,com), /* 8: serial port */ + cdev_notdef(), /* 9: was floppy disk */ + cdev_notdef(), /* 10 */ + cdev_notdef(), /* 11: Sony CD-ROM */ + cdev_wsdisplay_init(NWSDISPLAY, /* 12: frame buffers, etc. */ + wsdisplay), + cdev_disk_init(NSD,sd), /* 13: SCSI disk */ + cdev_notdef(), /* 14: was: SCSI tape */ + cdev_disk_init(NCD,cd), /* 15: SCSI CD-ROM */ + cdev_lpt_init(NLPT,lpt), /* 16: parallel printer */ + cdev_ch_init(NCH,ch), /* 17: SCSI autochanger */ + cdev_notdef(), /* 18: was: concatenated disk driver */ + cdev_notdef(), /* 19 */ + cdev_uk_init(NUK,uk), /* 20: unknown SCSI */ + cdev_notdef(), /* 21 */ + cdev_fd_init(1,filedesc), /* 22: file descriptor pseudo-device */ + cdev_bpf_init(NBPFILTER,bpf), /* 23: Berkeley packet filter */ + cdev_notdef(), /* 24 */ + cdev_notdef(), /* 25 */ + cdev_notdef(), /* 26 */ + cdev_notdef(), /* 27 */ + cdev_notdef(), /* 28 was LKM */ + cdev_notdef(), /* 29 */ + cdev_dt_init(NDT,dt), /* 30: dynamic tracer */ + cdev_notdef(), /* 31 */ + cdev_notdef(), /* 32 */ + cdev_notdef(), /* 33 */ + cdev_notdef(), /* 34 */ + cdev_notdef(), /* 35: Microsoft mouse */ + cdev_notdef(), /* 36: Logitech mouse */ + cdev_notdef(), /* 37: Extended PS/2 mouse */ + cdev_notdef(), /* 38: was: Cyclom serial port */ + cdev_notdef(), /* 39: Mitsumi CD-ROM */ + cdev_tun_init(NTUN,tun), /* 40: network tunnel */ + cdev_disk_init(NVND,vnd), /* 41: vnode disk driver */ + cdev_audio_init(NAUDIO,audio), /* 42: generic audio I/O */ + cdev_notdef(), /* 43 */ + cdev_video_init(NVIDEO,video), /* 44: generic video I/O */ + cdev_random_init(1,random), /* 45: random data source */ + cdev_notdef(), /* 46 */ + cdev_disk_init(NRD,rd), /* 47: ram disk driver */ + cdev_notdef(), /* 48 */ + cdev_notdef(), /* 49: Bt848 video capture device */ + cdev_ksyms_init(NKSYMS,ksyms), /* 50: Kernel symbols device */ + cdev_kstat_init(NKSTAT,kstat), /* 51: kernel statistics */ + cdev_midi_init(NMIDI,midi), /* 52: MIDI I/O */ + cdev_notdef(), /* 53 was: sequencer I/O */ + cdev_notdef(), /* 54 was: RAIDframe disk driver */ + cdev_notdef(), /* 55: */ + /* The following slots are reserved for isdn4bsd. */ + cdev_notdef(), /* 56: i4b main device */ + cdev_notdef(), /* 57: i4b control device */ + cdev_notdef(), /* 58: i4b raw b-channel access */ + cdev_notdef(), /* 59: i4b trace device */ + cdev_notdef(), /* 60: i4b phone device */ + /* End of reserved slots for isdn4bsd. */ + cdev_usb_init(NUSB,usb), /* 61: USB controller */ + cdev_usbdev_init(NUHID,uhid), /* 62: USB generic HID */ + cdev_usbdev_init(NUGEN,ugen), /* 63: USB generic driver */ + cdev_ulpt_init(NULPT,ulpt), /* 64: USB printers */ + cdev_notdef(), /* 65: urio */ + cdev_tty_init(NUCOM,ucom), /* 66: USB tty */ + cdev_mouse_init(NWSKBD, wskbd), /* 67: keyboards */ + cdev_mouse_init(NWSMOUSE, /* 68: mice */ + wsmouse), + cdev_mouse_init(NWSMUX, wsmux), /* 69: ws multiplexor */ + cdev_openprom_init(NOPENPROM,openprom), /* 70: /dev/openprom */ + cdev_notdef(), /* 71: was: Cyclades-Z serial port */ +#ifdef USER_PCICONF + cdev_pci_init(NPCI,pci), /* 72: PCI user */ +#else + cdev_notdef(), +#endif + cdev_pf_init(NPF,pf), /* 73: packet filter */ + cdev_notdef(), /* 74: ALTQ (deprecated) */ + cdev_notdef(), + cdev_radio_init(NRADIO, radio), /* 76: generic radio I/O */ + cdev_notdef(), /* 77: was USB scanners */ + cdev_notdef(), /* 78: was: system call tracing */ + cdev_bio_init(NBIO,bio), /* 79: ioctl tunnel */ + cdev_notdef(), /* 80 */ + cdev_ptm_init(NPTY,ptm), /* 81: pseudo-tty ptm device */ + cdev_hotplug_init(NHOTPLUG,hotplug), /* 82: devices hot plugging */ + cdev_notdef(), /* 83: apm */ + cdev_notdef(), /* 84 */ + cdev_notdef(), /* 85 */ + cdev_notdef(), /* 86 */ + cdev_drm_init(NDRM,drm), /* 87: drm */ + cdev_gpio_init(NGPIO,gpio), /* 88: GPIO interface */ + cdev_vscsi_init(NVSCSI,vscsi), /* 89: vscsi */ + cdev_disk_init(1,diskmap), /* 90: disk mapper */ + cdev_pppx_init(NPPPX,pppx), /* 91: pppx */ + cdev_fuse_init(NFUSE,fuse), /* 92: fuse */ + cdev_tun_init(NTUN,tap), /* 93: Ethernet network tunnel */ + cdev_notdef(), /* 94 */ + cdev_notdef(), /* 95 */ + cdev_ipmi_init(NIPMI,ipmi), /* 96: ipmi */ + cdev_notdef(), /* 97: was switch(4) */ + cdev_fido_init(NFIDO,fido), /* 98: FIDO/U2F security key */ + cdev_pppx_init(NPPPX,pppac), /* 99: PPP Access Concentrator */ + cdev_ujoy_init(NUJOY,ujoy), /* 100: USB joystick/gamecontroller */ +}; +int nchrdev = nitems(cdevsw); + +int mem_no = 2; /* major device number of memory special file */ + +/* + * Swapdev is a fake device implemented + * in sw.c used only internally to get to swstrategy. + * It cannot be provided to the users, because the + * swstrategy routine munches the b_dev and b_blkno entries + * before calling the appropriate driver. This would horribly + * confuse, e.g. the hashing routines. Instead, /dev/drum is + * provided as a character (raw) device. + */ +dev_t swapdev = makedev(1, 0); + +/* + * Returns true if dev is /dev/mem or /dev/kmem. + */ +int +iskmemdev(dev_t dev) +{ + + return (major(dev) == mem_no && minor(dev) < 2); +} + +/* + * Returns true if dev is /dev/zero. + */ +int +iszerodev(dev_t dev) +{ + + return (major(dev) == mem_no && minor(dev) == 12); +} + +dev_t +getnulldev(void) +{ + return makedev(mem_no, 2); +} + +const int chrtoblktbl[] = { + /*VCHR*/ /*VBLK*/ + /* 0 */ NODEV, + /* 1 */ NODEV, + /* 2 */ NODEV, + /* 3 */ 0, /* wd */ + /* 4 */ NODEV, + /* 5 */ NODEV, + /* 6 */ NODEV, + /* 7 */ NODEV, + /* 8 */ NODEV, + /* 9 */ NODEV, /* was fd */ + /* 10 */ NODEV, + /* 11 */ NODEV, + /* 12 */ NODEV, + /* 13 */ 4, /* sd */ + /* 14 */ NODEV, + /* 15 */ 6, /* cd */ + /* 16 */ NODEV, + /* 17 */ NODEV, + /* 18 */ NODEV, + /* 19 */ NODEV, + /* 20 */ NODEV, + /* 21 */ NODEV, + /* 22 */ NODEV, + /* 23 */ NODEV, + /* 24 */ NODEV, + /* 25 */ NODEV, + /* 26 */ NODEV, + /* 27 */ NODEV, + /* 28 */ NODEV, + /* 29 */ NODEV, + /* 30 */ NODEV, + /* 31 */ NODEV, + /* 32 */ NODEV, + /* 33 */ NODEV, + /* 34 */ NODEV, + /* 35 */ NODEV, + /* 36 */ NODEV, + /* 37 */ NODEV, + /* 38 */ NODEV, + /* 39 */ NODEV, + /* 40 */ NODEV, + /* 41 */ 14, /* vnd */ + /* 42 */ NODEV, + /* 43 */ NODEV, + /* 44 */ NODEV, + /* 45 */ NODEV, + /* 46 */ NODEV, + /* 47 */ 8, /* rd */ +}; + +const int nchrtoblktbl = nitems(chrtoblktbl); + +/* + * In order to map BSD bdev numbers of disks to their BIOS equivalents + * we use several heuristics, one being using checksums of the first + * few blocks of a disk to get a signature we can match with /boot's + * computed signatures. To know where from to read, we must provide a + * disk driver name -> bdev major number table, which follows. + * Note: floppies are not included as those are differentiated by the BIOS. + */ +int findblkmajor(struct device *dv); +dev_t dev_rawpart(struct device *); /* XXX */ + +dev_t +dev_rawpart(struct device *dv) +{ + int majdev; + + majdev = findblkmajor(dv); + + switch (majdev) { + /* add here any device you want to be checksummed on boot */ + case 0: + case 4: + return (MAKEDISKDEV(majdev, dv->dv_unit, RAW_PART)); + break; + default: + ; + } + + return (NODEV); +} diff --git sys/arch/loongarch64/loongarch64/copy.S sys/arch/loongarch64/loongarch64/copy.S new file mode 100644 index 00000000000..2c61b98f8f6 --- /dev/null +++ sys/arch/loongarch64/loongarch64/copy.S @@ -0,0 +1,177 @@ +/* $OpenBSD: copy.S,v 1.7 2021/07/23 15:31:14 jca Exp $ */ + +/* + * Copyright (c) 2020 Brian Bamsch + * Copyright (c) 2015 Dale Rahn + * Copyright (c) 2014 Patrick Wildt + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "assym.h" +#include +#include +#include +#include +#include + + + .text + +/* + * a0 = user space address + * a1 = kernel space address + * a2 = length + * + * Copies bytes from user space to kernel space + */ +ENTRY(copyin) + RETGUARD_SETUP(copyio, $a6) + beqz $a2, .Lcopyiodone /* If len = 0, skip loop. */ + /* Check whether source+len overflows. */ + add.d $a3, $a0, $a2 + bltu $a3, $a0, .Lcopyiofault_nopcb + /* Check that source+len is in userspace. */ + li.d $a4, VM_MAXUSER_ADDRESS + bgtu $a3, $a4, .Lcopyiofault_nopcb + + la $a3, .Lcopyiofault_user + SWAP_FAULT_HANDLER($a3, $a4, $a5) + ENTER_USER_ACCESS($a4) + +.Lcopyio: +.Lcopy8: + li.d $a5, 8 + bltu $a2, $a5, .Lcopy4 + + or $a7, $a0, $a1 + andi $a7, $a7, 7 + bnez $a7, .Lcopy4 + +1: ld.d $a4, $a0, 0 + addi.d $a0, $a0, 8 + st.d $a4, $a1, 0 + addi.d $a1, $a1, 8 + addi.d $a2, $a2, -8 + bgeu $a2, $a5, 1b + +.Lcopy4: + li.d $a5, 4 + bltu $a2, $a5, .Lcopy1 + + andi $a7, $a7, 3 + bnez $a7, .Lcopy1 + +1: ld.w $a4, $a0, 0 + addi.d $a0, $a0, 4 + st.w $a4, $a1, 0 + addi.d $a1, $a1, 4 + addi.d $a2, $a2, -4 + bgeu $a2, $a5, 1b + +.Lcopy1: + beqz $a2, .Lcopy0 +1: ld.b $a4, $a0, 0 + addi.d $a0, $a0, 1 + st.b $a4, $a1, 0 + addi.d $a1, $a1, 1 + addi.d $a2, $a2, -1 + bnez $a2, 1b + +.Lcopy0: + EXIT_USER_ACCESS($a4) + SET_FAULT_HANDLER($a3, $a4) +.Lcopyiodone: + move $a0, $zero + RETGUARD_CHECK(copyio, $a6) + ret + +.Lcopyiofault_user: + EXIT_USER_ACCESS($a4) +.Lcopyiofault: + SET_FAULT_HANDLER($a3, $a4) +.Lcopyiofault_nopcb: + li.d $a0, EFAULT + RETGUARD_CHECK(copyio, $a6) + ret +END(copyin) + +/* + * a0 = user space address + * a1 = kernel space address + * + * Atomically copies a 32-bit word from user space to kernel space + */ +ENTRY(copyin32) + RETGUARD_SETUP(copyio, $a6) + /* Check source alignment. */ + andi $a2, $a0, 3 + bnez $a2, .Lcopyiofault_nopcb + /* Check that source is in userspace. */ + li.d $a4, VM_MAXUSER_ADDRESS + bgeu $a0, $a4, .Lcopyiofault_nopcb + + la $a3, .Lcopyiofault_user + SWAP_FAULT_HANDLER($a3, $a4, $a5) + ENTER_USER_ACCESS($a4) + + ld.w $a2, $a0, 0 + st.w $a2, $a1, 0 + + EXIT_USER_ACCESS($a4) + SET_FAULT_HANDLER($a3, $a4) + b .Lcopyiodone +END(copyin) + +/* + * a0 = kernel space address + * a1 = user space address + * a2 = length + * + * Copies bytes from kernel space to user space + */ + +ENTRY(copyout) + RETGUARD_SETUP(copyio, $a6) + beqz $a2, .Lcopyiodone /* If len = 0, skip loop. */ + /* Check whether source+len overflows. */ + add.d $a3, $a1, $a2 + bltu $a3, $a1, .Lcopyiofault_nopcb + /* Check that source+len is in userspace. */ + li.d $a4, VM_MAXUSER_ADDRESS + bgtu $a3, $a4, .Lcopyiofault_nopcb + + la $a3, .Lcopyiofault_user + SWAP_FAULT_HANDLER($a3, $a4, $a5) + ENTER_USER_ACCESS($a4) + + b .Lcopyio +END(copyout) + +/* + * a0 = kernel space source address + * a1 = kernel space destination address + * a2 = length + * + * Copies bytes from kernel space to kernel space, aborting on page fault + */ + +ENTRY(kcopy) + RETGUARD_SETUP(copyio, $a6) + beqz $a2, .Lcopyiodone /* If len = 0, skip loop. */ + + la $a3, .Lcopyiofault + SWAP_FAULT_HANDLER($a3, $a4, $a5) + + b .Lcopyio +END(kcopy) diff --git sys/arch/loongarch64/loongarch64/copystr.S sys/arch/loongarch64/loongarch64/copystr.S new file mode 100644 index 00000000000..27a2d4ba772 --- /dev/null +++ sys/arch/loongarch64/loongarch64/copystr.S @@ -0,0 +1,116 @@ +/* $OpenBSD: copystr.S,v 1.5 2023/01/06 19:10:18 miod Exp $ */ + +/* + * Copyright (c) 2015 Dale Rahn + * Copyright (c) 2014 Patrick Wildt + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "assym.h" +#include +#include +#include +#include +#include + + .text + +/* + * a0 - user space address + * a1 - kernel space address + * a2 - maxlens + * a3 - lencopied + * + * Copy string from user space to kernel space + */ +ENTRY(copyinstr) + RETGUARD_SETUP(copyiostr, $a6) + beqz $a2, .Lcopyiostrtoolong_early + la $a4, .Lcopyiostrfault_user + SWAP_FAULT_HANDLER($a4, $t0, $t1) + ENTER_USER_ACCESS($t0) + + move $a5, $r0 + + li.d $t1, VM_MAXUSER_ADDRESS +1: bgtu $a0, $t1, .Lcopyiostrfault_user + ld.b $t0, $a0, 0 + addi.d $a0, $a0, 1 + st.b $t0, $a1, 0 + addi.d $a1, $a1, 1 + addi.d $a2, $a2, -1 + addi.d $a5, $a5, 1 + beqz $t0, .Lcopyiostrsuccess_user + bnez $a2, 1b + +.Lcopyiostrtoolong_user: + EXIT_USER_ACCESS($t0) +.Lcopyiostrtoolong: + SET_FAULT_HANDLER($a4, $t0) +.Lcopyiostrtoolong_early: + li.d $a0, ENAMETOOLONG + b .Lcopyiostrcleanup + +.Lcopyiostrfault_user: + EXIT_USER_ACCESS($t0) +.Lcopyiostrfault: + SET_FAULT_HANDLER($a4, $t0) + li.d $a0, EFAULT + b .Lcopyiostrcleanup + +.Lcopyiostrsuccess_user: + EXIT_USER_ACCESS($t0) +.Lcopyiostrsuccess: + SET_FAULT_HANDLER($a4, $t0) + move $a0, $r0 + +.Lcopyiostrcleanup: + beqz $a3, 2f + st.d $a5, $a3, 0 +2: + RETGUARD_CHECK(copyiostr, $a6) + ret + +END(copyinstr) + +/* + * a0 - kernel space address + * a1 - user space address + * a2 - maxlens + * a3 - lencopied + * + * Copy string from kernel space to user space + */ +ENTRY(copyoutstr) + RETGUARD_SETUP(copyiostr, $a6) + beqz $a2, .Lcopyiostrtoolong_early + la $a4, .Lcopyiostrfault_user + SWAP_FAULT_HANDLER($a4, $t0, $t1) + ENTER_USER_ACCESS($t0) + + move $a5, $r0 + + li.d $t1, VM_MAXUSER_ADDRESS +1: bgtu $a1, $t1, .Lcopyiostrfault_user + ld.b $t0, $a0, 0 + addi.d $a0, $a0, 1 + st.b $t0, $a1, 0 + addi.d $a1, $a1, 1 + addi.d $a2, $a2, -1 + addi.d $a5, $a5, 1 + beqz $t0, .Lcopyiostrsuccess_user + bnez $a2, 1b + + b .Lcopyiostrtoolong_user +END(copyoutstr) diff --git sys/arch/loongarch64/loongarch64/cpu.c sys/arch/loongarch64/loongarch64/cpu.c new file mode 100644 index 00000000000..07e8832e9b9 --- /dev/null +++ sys/arch/loongarch64/loongarch64/cpu.c @@ -0,0 +1,887 @@ +/* $OpenBSD: cpu.c,v 1.28 2026/05/09 17:38:50 jsing Exp $ */ + +/* + * Copyright (c) 2016 Dale Rahn + * Copyright (c) 2017 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* CPU Identification */ +#define CPU_VENDOR_MIPS 0x029 +#define CPU_VENDOR_ANDES 0x31e +#define CPU_VENDOR_SIFIVE 0x489 +#define CPU_VENDOR_THEAD 0x5b7 +#define CPU_VENDOR_SPACEMIT 0x710 + +/* SiFive */ +#define CPU_ARCH_U5 0x0000000000000001 +#define CPU_ARCH_U7 0x8000000000000007 + +/* SpacemiT */ +#define CPU_ARCH_X60 0x8000000058000001 +#define CPU_ARCH_X100 0x8000000058000002 + +/* Architectures */ +struct arch { + uint64_t id; + char *name; +}; + +struct arch cpu_arch_none[] = { + { 0, NULL } +}; + +struct arch cpu_arch_sifive[] = { + { CPU_ARCH_U5, "U5" }, + { CPU_ARCH_U7, "U7" }, + { 0, NULL } +}; + +struct arch cpu_arch_spacemit[] = { + { CPU_ARCH_X60, "X60" }, + { CPU_ARCH_X100, "X100" }, + { 0, NULL } +}; + +/* Vendors */ +const struct vendor { + uint32_t id; + char *name; + struct arch *archlist; +} cpu_vendors[] = { + { CPU_VENDOR_ANDES, "Andes", cpu_arch_none }, + { CPU_VENDOR_MIPS, "MIPS", cpu_arch_none }, + { CPU_VENDOR_SIFIVE, "SiFive", cpu_arch_sifive }, + { CPU_VENDOR_SPACEMIT, "SpacemiT", cpu_arch_spacemit }, + { CPU_VENDOR_THEAD, "T-Head", cpu_arch_none }, + { 0, NULL, NULL } +}; + +size_t loongarch_vlenb; + +unsigned long loongarch_hwcap; +unsigned long loongarch_hwcap2; + +/* Extensions */ +const struct extension { + const char *name; + unsigned long hwcap; + unsigned long hwcap2; +} cpu_extensions[] = { + { "b", HWCAP_ISA_B, 0 }, + { "h", HWCAP_ISA_H, 0 }, + { "scofpmf", HWCAP_ISA_SCOFPMF, 0 }, + { "ssnpm", HWCAP_ISA_SSNPM, 0 }, + { "sstc", HWCAP_ISA_SSTC, 0 }, + { "svinval", HWCAP_ISA_SVINVAL, 0 }, + { "svnapot", HWCAP_ISA_SVNAPOT, 0 }, + { "svpbmt", HWCAP_ISA_SVPBMT, 0 }, + { "v", HWCAP_ISA_V, 0 }, + { "zba", 0, HWCAP2_ISA_ZBA }, + { "zbb", 0, HWCAP2_ISA_ZBB }, + { "zbc", 0, HWCAP2_ISA_ZBC }, + { "zbs", 0, HWCAP2_ISA_ZBS }, + { "zkt", 0, HWCAP2_ISA_ZKT }, + { "zvbb", 0, HWCAP2_ISA_ZVBB }, + { "zvbc", 0, HWCAP2_ISA_ZVBC }, + { "zvfh", 0, HWCAP2_ISA_ZVFH }, + { "zvkg", 0, HWCAP2_ISA_ZVKG }, + { "zvkned", 0, HWCAP2_ISA_ZVKNED }, + { "zvknha", 0, HWCAP2_ISA_ZVKNHA }, + { "zvknhb", 0, HWCAP2_ISA_ZVKNHB }, + { "zvksed", 0, HWCAP2_ISA_ZVKSED }, + { "zvksh", 0, HWCAP2_ISA_ZVKSH }, + { "zvkt", 0, HWCAP2_ISA_ZVKT }, + { NULL, 0, 0 } +}; + +char cpu_model[64]; +int cpu_node; + +struct cpu_info *cpu_info_list = &cpu_info_primary; + +int cpu_match(struct device *, void *, void *); +void cpu_attach(struct device *, struct device *, void *); + +const struct cfattach cpu_ca = { + sizeof(struct device), cpu_match, cpu_attach +}; + +struct cfdriver cpu_cd = { + NULL, "cpu", DV_DULL +}; + +int cpu_errata_sifive_cip_1200; + +void cpu_opp_init(struct cpu_info *, uint32_t); + +void +cpu_identify(struct cpu_info *ci) +{ + uint64_t marchid, mimpid; + uint32_t mvendorid; + const char *vendor_name = NULL; + const char *arch_name = NULL; + struct arch *archlist = cpu_arch_none; + unsigned long cpu_hwcap, cpu_hwcap2; + size_t vlenb = 0; + char *names; + char *name; + char *end; + int i, len; + + mvendorid = sbi_get_mvendorid(); + marchid = sbi_get_marchid(); + mimpid = sbi_get_mimpid(); + + cpu_hwcap = cpu_hwcap2 = 0; + + for (i = 0; cpu_vendors[i].name; i++) { + if (mvendorid == cpu_vendors[i].id) { + vendor_name = cpu_vendors[i].name; + archlist = cpu_vendors[i].archlist; + break; + } + } + + for (i = 0; archlist[i].name; i++) { + if (marchid == archlist[i].id) { + arch_name = archlist[i].name; + break; + } + } + + if (vendor_name) + printf(": %s", vendor_name); + else + printf(": vendor %x", mvendorid); + if (arch_name) + printf(" %s", arch_name); + else + printf(" arch %llx", marchid); + printf(" imp %llx\n", mimpid); + + if (CPU_IS_PRIMARY(ci)) { + if (vendor_name && arch_name) + snprintf(cpu_model, sizeof(cpu_model), + "%s %s imp %llx", vendor_name, arch_name, mimpid); + else if (vendor_name) + snprintf(cpu_model, sizeof(cpu_model), + "%s arch %llx imp %llx", vendor_name, marchid, + mimpid); + else + snprintf(cpu_model, sizeof(cpu_model), "Unknown"); + } + + len = OF_getproplen(ci->ci_node, "loongarch,isa-extensions"); + if (len > 0) { + names = malloc(len, M_TEMP, M_WAITOK); + OF_getprop(ci->ci_node, "loongarch,isa-extensions", names, len); + end = names + len; + name = names; + while (name < end) { + for (i = 0; cpu_extensions[i].name; i++) { + if (strcmp(name, cpu_extensions[i].name) == 0) { + cpu_hwcap |= cpu_extensions[i].hwcap; + cpu_hwcap2 |= cpu_extensions[i].hwcap2; + break; + } + } + name += strlen(name) + 1; + } + free(names, M_TEMP, len); + } + + if (CPU_IS_PRIMARY(ci)) { + loongarch_hwcap = cpu_hwcap; + loongarch_hwcap2 = cpu_hwcap2; + + /* Handle errata. */ + if (mvendorid == CPU_VENDOR_SIFIVE && marchid == CPU_ARCH_U7) + cpu_errata_sifive_cip_1200 = 1; + } + + if (loongarch_hwcap != cpu_hwcap) { + printf("%s: mismatched extensions (hwcap 0x%lx != 0x%lx)\n", + ci->ci_dev->dv_xname, loongarch_hwcap, cpu_hwcap); + loongarch_hwcap &= cpu_hwcap; + } + if (loongarch_hwcap2 != cpu_hwcap2) { + printf("%s: mismatched extensions (hwcap2 0x%lx != 0x%lx)\n", + ci->ci_dev->dv_xname, loongarch_hwcap2, cpu_hwcap2); + loongarch_hwcap2 &= cpu_hwcap2; + } + + if ((loongarch_hwcap & HWCAP_ISA_V) != 0) { + vlenb = csr_read(vlenb); + + if (CPU_IS_PRIMARY(ci)) { + if (vlenb > 32) { + printf("%s: vlenb exceeds maximum (%lu > %d)\n", + ci->ci_dev->dv_xname, vlenb, 32); + } else { + loongarch_vlenb = vlenb; + } + } else if (loongarch_vlenb != vlenb) { + printf("%s: mismatched vlenb (%zu != %lu)\n", + ci->ci_dev->dv_xname, loongarch_vlenb, vlenb); + loongarch_hwcap &= ~HWCAP_ISA_V; + } + } +} + +void +cpu_identify_cleanup(void) +{ + hwcap = HWCAP_ISA_G | HWCAP_ISA_C; + hwcap |= loongarch_hwcap & ~(HWCAP_ISA_K_MASK | HWCAP_ISA_S_MASK); + + hwcap2 = loongarch_hwcap2; + + /* B implies Zba, Zbb and Zbs */ + if ((loongarch_hwcap & HWCAP_ISA_B) != 0) + hwcap2 |= HWCAP2_ISA_ZBA | HWCAP2_ISA_ZBB | HWCAP2_ISA_ZBS; + + /* Remove H extension since userland does not need to know about it. */ + hwcap &= ~HWCAP_ISA_H; +} + +#ifdef MULTIPROCESSOR +int cpu_hatch_secondary(struct cpu_info *ci); +#endif +int cpu_clockspeed(int *); + +int +cpu_match(struct device *parent, void *cfdata, void *aux) +{ + struct fdt_attach_args *faa = aux; + char buf[32]; + + if (OF_getprop(faa->fa_node, "device_type", buf, sizeof(buf)) <= 0 || + strcmp(buf, "cpu") != 0) + return 0; + + if (ncpus < MAXCPUS || faa->fa_reg[0].addr == boot_hart) /* the primary cpu */ + return 1; + + return 0; +} + +void +cpu_attach(struct device *parent, struct device *dev, void *aux) +{ + struct fdt_attach_args *faa = aux; + struct cpu_info *ci; + int node, level; + uint32_t opp; + + KASSERT(faa->fa_nreg > 0); + +#ifdef MULTIPROCESSOR + if (faa->fa_reg[0].addr == boot_hart) { + ci = &cpu_info_primary; + ci->ci_flags |= CPUF_RUNNING | CPUF_PRESENT | CPUF_PRIMARY; + csr_set(sie, SIE_SSIE); + } else { + struct cpu_info *ci_last; + + ci = malloc(sizeof(*ci), M_DEVBUF, M_WAITOK | M_ZERO); + cpu_info[dev->dv_unit] = ci; + ci_last = cpu_info_list; + while (ci_last->ci_next != NULL) + ci_last = ci_last->ci_next; + ci_last->ci_next = ci; + ci->ci_flags |= CPUF_AP; + ncpus++; + } +#else + ci = &cpu_info_primary; +#endif + + ci->ci_dev = dev; + ci->ci_cpuid = dev->dv_unit; + ci->ci_hartid = faa->fa_reg[0].addr; + ci->ci_node = faa->fa_node; + ci->ci_self = ci; + +#ifdef MULTIPROCESSOR + if (ci->ci_flags & CPUF_AP) { + int timeout = 10000; + + clockqueue_init(&ci->ci_queue); + sched_init_cpu(ci); + if (cpu_hatch_secondary(ci)) { + atomic_setbits_int(&ci->ci_flags, CPUF_IDENTIFY); + membar_producer(); + + while ((ci->ci_flags & CPUF_IDENTIFIED) == 0 && + --timeout) + delay(1000); + if (timeout == 0) { + printf(" failed to identify"); + ci->ci_flags = 0; + } + } else { + printf(" failed to spin up"); + ci->ci_flags = 0; + } + } else { +#endif + cpu_identify(ci); + + if (OF_getproplen(ci->ci_node, "clocks") > 0) { + cpu_node = ci->ci_node; + cpu_cpuspeed = cpu_clockspeed; + } + + /* + * attach cpu's children node, so far there is only the + * cpu-embedded interrupt controller + */ + struct fdt_attach_args fa_intc; + for (node = OF_child(faa->fa_node); node; node = OF_peer(node)) { + fa_intc.fa_node = node; + /* no specifying match func, will call cfdata's match func*/ + config_found(dev, &fa_intc, NULL); + } + +#ifdef MULTIPROCESSOR + } +#endif + + opp = OF_getpropint(ci->ci_node, "operating-points-v2", 0); + if (opp) + cpu_opp_init(ci, opp); + + node = faa->fa_node; + + level = 1; + + while (node) { + const char *unit = "KB"; + uint32_t line, iline, dline; + uint32_t size, isize, dsize; + uint32_t ways, iways, dways; + uint32_t cache; + + line = OF_getpropint(node, "cache-block-size", 0); + size = OF_getpropint(node, "cache-size", 0); + ways = OF_getpropint(node, "cache-sets", 0); + iline = OF_getpropint(node, "i-cache-block-size", line); + isize = OF_getpropint(node, "i-cache-size", size) / 1024; + iways = OF_getpropint(node, "i-cache-sets", ways); + dline = OF_getpropint(node, "d-cache-block-size", line); + dsize = OF_getpropint(node, "d-cache-size", size) / 1024; + dways = OF_getpropint(node, "d-cache-sets", ways); + + if (isize == 0 && dsize == 0) + break; + + /* Print large cache sizes in MB. */ + if (isize > 4096 && dsize > 4096) { + unit = "MB"; + isize /= 1024; + dsize /= 1024; + } + + printf("%s:", dev->dv_xname); + + if (OF_getproplen(node, "cache-unified") == 0) { + printf(" %d%s %db/line %d-way L%d cache", + isize, unit, iline, iways, level); + } else { + printf(" %d%s %db/line %d-way L%d I-cache", + isize, unit, iline, iways, level); + printf(", %d%s %db/line %d-way L%d D-cache", + dsize, unit, dline, dways, level); + } + + cache = OF_getpropint(node, "next-level-cache", 0); + node = OF_getnodebyphandle(cache); + level++; + + printf("\n"); + } +} + +int +cpu_clockspeed(int *freq) +{ + *freq = clock_get_frequency(cpu_node, NULL) / 1000000; + return 0; +} + +void +cpu_cache_nop_range(vaddr_t va, vsize_t len) +{ +} + +void (*cpu_dcache_wbinv_range)(vaddr_t, vsize_t) = cpu_cache_nop_range; +void (*cpu_dcache_inv_range)(vaddr_t, vsize_t) = cpu_cache_nop_range; +void (*cpu_dcache_wb_range)(vaddr_t, vsize_t) = cpu_cache_nop_range; + +#ifdef MULTIPROCESSOR + +void cpu_hatch(void); + +void +cpu_boot_secondary(struct cpu_info *ci) +{ + atomic_setbits_int(&ci->ci_flags, CPUF_GO); + membar_producer(); + + while ((ci->ci_flags & CPUF_RUNNING) == 0) + CPU_BUSY_CYCLE(); +} + +void +cpu_boot_secondary_processors(void) +{ + struct cpu_info *ci; + CPU_INFO_ITERATOR cii; + + CPU_INFO_FOREACH(cii, ci) { + if ((ci->ci_flags & CPUF_AP) == 0) + continue; + if (ci->ci_flags & CPUF_PRIMARY) + continue; + + ci->ci_randseed = (arc4random() & 0x7fffffff) + 1; + cpu_boot_secondary(ci); + } +} + +int +cpu_hatch_secondary(struct cpu_info *ci) +{ + paddr_t start_addr, a1; + void *kstack; + int error; + + kstack = km_alloc(USPACE, &kv_any, &kp_zero, &kd_waitok); + ci->ci_initstack_end = (vaddr_t)kstack + USPACE - 16; + + pmap_extract(pmap_kernel(), (vaddr_t)cpu_hatch, &start_addr); + pmap_extract(pmap_kernel(), (vaddr_t)ci, &a1); + + ci->ci_satp = pmap_kernel()->pm_satp; + + error = sbi_hsm_hart_start(ci->ci_hartid, start_addr, a1); + return (error == SBI_SUCCESS); +} + +void cpu_startclock(void); + +void +cpu_start_secondary(void) +{ + struct cpu_info *ci = curcpu(); + int s; + + ci->ci_flags |= CPUF_PRESENT; + membar_producer(); + + while ((ci->ci_flags & CPUF_IDENTIFY) == 0) + membar_consumer(); + + cpu_identify(ci); + + atomic_setbits_int(&ci->ci_flags, CPUF_IDENTIFIED); + membar_producer(); + + while ((ci->ci_flags & CPUF_GO) == 0) + membar_consumer(); + + s = splhigh(); + loongarch_intr_cpu_enable(); + cpu_startclock(); + + csr_clear(sstatus, SSTATUS_FS_MASK | SSTATUS_VS_MASK); + csr_set(sie, SIE_SSIE); + + atomic_setbits_int(&ci->ci_flags, CPUF_RUNNING); + membar_producer(); + + spllower(IPL_NONE); + intr_enable(); + + sched_toidle(); +} + +void +cpu_kick(struct cpu_info *ci) +{ + if (ci != curcpu()) + intr_send_ipi(ci, IPI_NOP); +} + +void +cpu_unidle(struct cpu_info *ci) +{ + if (ci != curcpu()) + intr_send_ipi(ci, IPI_NOP); +} + +#endif + +int cpu_suspended; + +/* + * Dynamic voltage and frequency scaling implementation. + */ + +extern int perflevel; + +struct opp { + uint64_t opp_hz; + uint32_t opp_microvolt; +}; + +struct opp_table { + LIST_ENTRY(opp_table) ot_list; + uint32_t ot_phandle; + + struct opp *ot_opp; + u_int ot_nopp; + uint64_t ot_opp_hz_min; + uint64_t ot_opp_hz_max; + + struct cpu_info *ot_master; +}; + +LIST_HEAD(, opp_table) opp_tables = LIST_HEAD_INITIALIZER(opp_tables); +struct task cpu_opp_task; + +void cpu_opp_mountroot(struct device *); +void cpu_opp_dotask(void *); +void cpu_opp_setperf(int); + +uint32_t cpu_opp_get_cooling_level(void *, uint32_t *); +void cpu_opp_set_cooling_level(void *, uint32_t *, uint32_t); + +void +cpu_opp_init(struct cpu_info *ci, uint32_t phandle) +{ + struct opp_table *ot; + struct cooling_device *cd; + int count, node, child; + uint32_t opp_hz, opp_microvolt; + uint32_t values[3]; + int i, j, len; + + LIST_FOREACH(ot, &opp_tables, ot_list) { + if (ot->ot_phandle == phandle) { + ci->ci_opp_table = ot; + return; + } + } + + node = OF_getnodebyphandle(phandle); + if (node == 0) + return; + + if (!OF_is_compatible(node, "operating-points-v2")) + return; + + count = 0; + for (child = OF_child(node); child != 0; child = OF_peer(child)) { + if (OF_getproplen(child, "turbo-mode") == 0) + continue; + count++; + } + if (count == 0) + return; + + ot = malloc(sizeof(struct opp_table), M_DEVBUF, M_ZERO | M_WAITOK); + ot->ot_phandle = phandle; + ot->ot_opp = mallocarray(count, sizeof(struct opp), + M_DEVBUF, M_ZERO | M_WAITOK); + ot->ot_nopp = count; + + count = 0; + for (child = OF_child(node); child != 0; child = OF_peer(child)) { + if (OF_getproplen(child, "turbo-mode") == 0) + continue; + opp_hz = OF_getpropint64(child, "opp-hz", 0); + len = OF_getpropintarray(child, "opp-microvolt", + values, sizeof(values)); + opp_microvolt = 0; + if (len == sizeof(uint32_t) || len == 3 * sizeof(uint32_t)) + opp_microvolt = values[0]; + + /* Insert into the array, keeping things sorted. */ + for (i = 0; i < count; i++) { + if (opp_hz < ot->ot_opp[i].opp_hz) + break; + } + for (j = count; j > i; j--) + ot->ot_opp[j] = ot->ot_opp[j - 1]; + ot->ot_opp[i].opp_hz = opp_hz; + ot->ot_opp[i].opp_microvolt = opp_microvolt; + count++; + } + + ot->ot_opp_hz_min = ot->ot_opp[0].opp_hz; + ot->ot_opp_hz_max = ot->ot_opp[count - 1].opp_hz; + + if (OF_getproplen(node, "opp-shared") == 0) + ot->ot_master = ci; + + LIST_INSERT_HEAD(&opp_tables, ot, ot_list); + + ci->ci_opp_table = ot; + ci->ci_opp_idx = -1; + ci->ci_opp_max = ot->ot_nopp - 1; + ci->ci_cpu_supply = OF_getpropint(ci->ci_node, "cpu-supply", 0); + + cd = malloc(sizeof(struct cooling_device), M_DEVBUF, M_ZERO | M_WAITOK); + cd->cd_node = ci->ci_node; + cd->cd_cookie = ci; + cd->cd_get_level = cpu_opp_get_cooling_level; + cd->cd_set_level = cpu_opp_set_cooling_level; + cooling_device_register(cd); + + /* + * Do additional checks at mountroot when all the clocks and + * regulators are available. + */ + config_mountroot(ci->ci_dev, cpu_opp_mountroot); +} + +void +cpu_opp_mountroot(struct device *self) +{ + struct cpu_info *ci; + CPU_INFO_ITERATOR cii; + int count = 0; + int level = 0; + + if (cpu_setperf) + return; + + CPU_INFO_FOREACH(cii, ci) { + struct opp_table *ot = ci->ci_opp_table; + uint64_t curr_hz; + uint32_t curr_microvolt; + int error; + + if (ot == NULL) + continue; + + /* Skip if this table is shared and we're not the master. */ + if (ot->ot_master && ot->ot_master != ci) + continue; + + /* PWM regulators may need to be explicitly enabled. */ + regulator_enable(ci->ci_cpu_supply); + + curr_hz = clock_get_frequency(ci->ci_node, NULL); + curr_microvolt = regulator_get_voltage(ci->ci_cpu_supply); + + /* Disable if clock isn't implemented. */ + error = ENODEV; + if (curr_hz != 0) + error = clock_set_frequency(ci->ci_node, NULL, curr_hz); + if (error) { + ci->ci_opp_table = NULL; + printf("%s: clock not implemented\n", + ci->ci_dev->dv_xname); + continue; + } + + /* Disable if regulator isn't implemented. */ + error = ci->ci_cpu_supply ? ENODEV : 0; + if (ci->ci_cpu_supply && curr_microvolt != 0) + error = regulator_set_voltage(ci->ci_cpu_supply, + curr_microvolt); + if (error) { + ci->ci_opp_table = NULL; + printf("%s: regulator not implemented\n", + ci->ci_dev->dv_xname); + continue; + } + + /* + * Initialize performance level based on the current + * speed of the first CPU that supports DVFS. + */ + if (level == 0) { + uint64_t min, max; + uint64_t level_hz; + + min = ot->ot_opp_hz_min; + max = ot->ot_opp_hz_max; + level_hz = clock_get_frequency(ci->ci_node, NULL); + if (level_hz < min) + level_hz = min; + if (level_hz > max) + level_hz = max; + level = howmany(100 * (level_hz - min), (max - min)); + } + + count++; + } + + if (count > 0) { + task_set(&cpu_opp_task, cpu_opp_dotask, NULL); + cpu_setperf = cpu_opp_setperf; + + perflevel = (level > 0) ? level : 0; + cpu_setperf(perflevel); + } +} + +void +cpu_opp_dotask(void *arg) +{ + struct cpu_info *ci; + CPU_INFO_ITERATOR cii; + + CPU_INFO_FOREACH(cii, ci) { + struct opp_table *ot = ci->ci_opp_table; + uint64_t curr_hz, opp_hz; + uint32_t curr_microvolt, opp_microvolt; + int opp_idx; + int error = 0; + + if (ot == NULL) + continue; + + /* Skip if this table is shared and we're not the master. */ + if (ot->ot_master && ot->ot_master != ci) + continue; + + opp_idx = MIN(ci->ci_opp_idx, ci->ci_opp_max); + opp_hz = ot->ot_opp[opp_idx].opp_hz; + opp_microvolt = ot->ot_opp[opp_idx].opp_microvolt; + + curr_hz = clock_get_frequency(ci->ci_node, NULL); + curr_microvolt = regulator_get_voltage(ci->ci_cpu_supply); + + if (error == 0 && opp_hz < curr_hz) + error = clock_set_frequency(ci->ci_node, NULL, opp_hz); + if (error == 0 && ci->ci_cpu_supply && + opp_microvolt != 0 && opp_microvolt != curr_microvolt) { + error = regulator_set_voltage(ci->ci_cpu_supply, + opp_microvolt); + } + if (error == 0 && opp_hz > curr_hz) + error = clock_set_frequency(ci->ci_node, NULL, opp_hz); + + if (error) + printf("%s: DVFS failed\n", ci->ci_dev->dv_xname); + } +} + +void +cpu_opp_setperf(int level) +{ + struct cpu_info *ci; + CPU_INFO_ITERATOR cii; + int update = 0; + + CPU_INFO_FOREACH(cii, ci) { + struct opp_table *ot = ci->ci_opp_table; + uint64_t min, max; + uint64_t level_hz, opp_hz; + int opp_idx = -1; + int i; + + if (ot == NULL) + continue; + + /* Skip if this table is shared and we're not the master. */ + if (ot->ot_master && ot->ot_master != ci) + continue; + + min = ot->ot_opp_hz_min; + max = ot->ot_opp_hz_max; + level_hz = min + (level * (max - min)) / 100; + opp_hz = min; + for (i = 0; i < ot->ot_nopp; i++) { + if (ot->ot_opp[i].opp_hz <= level_hz && + ot->ot_opp[i].opp_hz >= opp_hz) + opp_hz = ot->ot_opp[i].opp_hz; + } + + /* Find index of selected operating point. */ + for (i = 0; i < ot->ot_nopp; i++) { + if (ot->ot_opp[i].opp_hz == opp_hz) { + opp_idx = i; + break; + } + } + KASSERT(opp_idx >= 0); + + if (ci->ci_opp_idx != opp_idx) { + ci->ci_opp_idx = opp_idx; + update = 1; + } + } + + /* + * Update the hardware from a task since setting the + * regulators might need process context. + */ + if (update) + task_add(systq, &cpu_opp_task); +} + +uint32_t +cpu_opp_get_cooling_level(void *cookie, uint32_t *cells) +{ + struct cpu_info *ci = cookie; + struct opp_table *ot = ci->ci_opp_table; + + return ot->ot_nopp - ci->ci_opp_max - 1; +} + +void +cpu_opp_set_cooling_level(void *cookie, uint32_t *cells, uint32_t level) +{ + struct cpu_info *ci = cookie; + struct opp_table *ot = ci->ci_opp_table; + int opp_max; + + if (level > (ot->ot_nopp - 1)) + level = ot->ot_nopp - 1; + + opp_max = (ot->ot_nopp - level - 1); + if (ci->ci_opp_max != opp_max) { + ci->ci_opp_max = opp_max; + task_add(systq, &cpu_opp_task); + } +} diff --git sys/arch/loongarch64/loongarch64/cpuswitch.S sys/arch/loongarch64/loongarch64/cpuswitch.S new file mode 100644 index 00000000000..67ab87540ec --- /dev/null +++ sys/arch/loongarch64/loongarch64/cpuswitch.S @@ -0,0 +1,95 @@ +/* $OpenBSD: cpuswitch.S,v 1.10 2024/10/17 02:20:53 jsg Exp $ */ + +/* + * Copyright (c) 2015 Dale Rahn + * Copyright (c) 2020 Brian Bamsch + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "assym.h" + +/* + * cpu_switchto(struct proc *oldproc, struct proc *newproc) + * a0 'struct proc *' of the old context + * a1 'struct proc *' of the new context + */ +ENTRY(cpu_switchto_asm) + // check if old context needs to be saved + beqz $a0, 1f + + // create switchframe + addi.d $sp, $sp, -SWITCHFRAME_SIZEOF + st.d $fp, $sp, SF_S + 0 * 8 + st.d $s0, $sp, SF_S + 1 * 8 + st.d $s1, $sp, SF_S + 2 * 8 + st.d $s2, $sp, SF_S + 3 * 8 + st.d $s3, $sp, SF_S + 4 * 8 + st.d $s4, $sp, SF_S + 5 * 8 + st.d $s5, $sp, SF_S + 6 * 8 + st.d $s6, $sp, SF_S + 7 * 8 + st.d $s7, $sp, SF_S + 8 * 8 + st.d $s8, $sp, SF_S + 9 * 8 + st.d $ra, $sp, SF_RA + + // store switchframe + ld.d $a5, $tp, CI_CURPCB + st.d $sp, $a5, PCB_SP + +1: + RETGUARD_SYMBOL(cpu_switchto) + RETGUARD_LOAD_RANDOM(cpu_switchto, s0) + + li.d $a5, SONPROC + st.b $a5, $a1, P_STAT + st.d $tp, $a1, P_CPU + ld.d $a5, $a1, P_ADDR + st.d $a5, $tp, CI_CURPCB + st.d $a1, $tp, CI_CURPROC + + // Unlike AArch64, RISC-V does not have a dedicated register in which + // we can also store pcb_tcb. Supervisor must access tcb indirectly. + + ld.d $s1, $a5, PCB_SP + move $a0, $a1 + bl pmap_set_satp + + move $a7, $fp // move retguard random + move $sp, $s0 // restore stack pointer + + ld.d $fp, $sp, (SF_S + 0 * 8) + ld.d $s0, $sp, (SF_S + 1 * 8) + ld.d $s1, $sp, (SF_S + 2 * 8) + ld.d $s2, $sp, (SF_S + 3 * 8) + ld.d $s3, $sp, (SF_S + 4 * 8) + ld.d $s4, $sp, (SF_S + 5 * 8) + ld.d $s5, $sp, (SF_S + 6 * 8) + ld.d $s6, $sp, (SF_S + 7 * 8) + ld.d $s7, $sp, (SF_S + 8 * 8) + ld.d $s8, $sp, (SF_S + 9 * 8) + ld.d $ra, $sp, SF_RA + + RETGUARD_CALC_COOKIE($a7) + addi.d $sp, $sp, SWITCHFRAME_SIZEOF + RETGUARD_CHECK(cpu_switchto, $a7) + ret +END(cpu_switch_asm) + +ENTRY(proc_trampoline) + bl proc_trampoline_mi + move $a0, $s1 + jirl $zero, $s0, 0 + la $t0, syscall_return + jr $t0 +END(cpu_switch) diff --git sys/arch/loongarch64/loongarch64/db_disasm.c sys/arch/loongarch64/loongarch64/db_disasm.c new file mode 100644 index 00000000000..4e845592c8f --- /dev/null +++ sys/arch/loongarch64/loongarch64/db_disasm.c @@ -0,0 +1,608 @@ +/* $OpenBSD: db_disasm.c,v 1.6 2024/09/20 02:00:46 jsg Exp $ */ + +/*- + * Copyright (c) 2016-2018 Ruslan Bukin + * All rights reserved. + * + * Portions of this software were developed by SRI International and the + * University of Cambridge Computer Laboratory under DARPA/AFRL contract + * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. + * + * Portions of this software were developed by the University of Cambridge + * Computer Laboratory as part of the CTSRD Project, with support from the + * UK Higher Education Innovation Fund (HEIF). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define X_RA 1 +#define X_SP 2 +#define X_GP 3 +#define X_TP 4 +#define X_T0 5 +#define X_T1 6 +#define X_T2 7 +#define X_T3 28 + +#define RD_SHIFT 7 +#define RD_MASK (0x1f << RD_SHIFT) +#define RS1_SHIFT 15 +#define RS1_MASK (0x1f << RS1_SHIFT) +#define RS2_SHIFT 20 +#define RS2_MASK (0x1f << RS2_SHIFT) +#define IMM_SHIFT 20 +#define IMM_MASK (0xfff << IMM_SHIFT) + +static char *reg_name[32] = { + "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", + "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", + "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", + "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6" +}; + +static char *fp_reg_name[32] = { + "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7", + "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", + "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", + "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11" +}; + +struct loongarch_op { + char *name; + char *fmt; + int match; + int mask; + int (*match_func)(struct loongarch_op *op, uint32_t insn); +}; + +static int +m_op(struct loongarch_op *op, uint32_t insn) +{ + + if (((insn ^ op->match) & op->mask) == 0) + return (1); + + return (0); +} + +static struct loongarch_op loongarch_opcodes[] = { + /* Aliases first */ + {"ret","", MATCH_JALR | (X_RA << RS1_SHIFT), + MASK_JALR | RD_MASK | RS1_MASK | IMM_MASK, m_op }, + + { "beq", "s,t,p", MATCH_BEQ, MASK_BEQ, m_op }, + { "bne", "s,t,p", MATCH_BNE, MASK_BNE, m_op }, + { "blt", "s,t,p", MATCH_BLT, MASK_BLT, m_op }, + { "bge", "s,t,p", MATCH_BGE, MASK_BGE, m_op }, + { "bltu", "s,t,p", MATCH_BLTU, MASK_BLTU, m_op }, + { "bgeu", "s,t,p", MATCH_BGEU, MASK_BGEU, m_op }, + { "jalr", "d,o(s)", MATCH_JALR, MASK_JALR, m_op }, + { "jal", "d,a", MATCH_JAL, MASK_JAL, m_op }, + { "lui", "d,u", MATCH_LUI, MASK_LUI, m_op }, + { "auipc", "d,u", MATCH_AUIPC, MASK_AUIPC, m_op }, + { "addi", "d,s,j", MATCH_ADDI, MASK_ADDI, m_op }, + { "slli", "d,s,>", MATCH_SLLI, MASK_SLLI, m_op }, + { "slti", "d,s,j", MATCH_SLTI, MASK_SLTI, m_op }, + { "sltiu", "d,s,j", MATCH_SLTIU, MASK_SLTIU, m_op }, + { "xori", "d,s,j", MATCH_XORI, MASK_XORI, m_op }, + { "srli", "d,s,>", MATCH_SRLI, MASK_SRLI, m_op }, + { "srai", "d,s,>", MATCH_SRAI, MASK_SRAI, m_op }, + { "ori", "d,s,j", MATCH_ORI, MASK_ORI, m_op }, + { "andi", "d,s,j", MATCH_ANDI, MASK_ANDI, m_op }, + { "add", "d,s,t", MATCH_ADD, MASK_ADD, m_op }, + { "sub", "d,s,t", MATCH_SUB, MASK_SUB, m_op }, + { "sll", "d,s,t", MATCH_SLL, MASK_SLL, m_op }, + { "slt", "d,s,t", MATCH_SLT, MASK_SLT, m_op }, + { "sltu", "d,s,t", MATCH_SLTU, MASK_SLTU, m_op }, + { "xor", "d,s,t", MATCH_XOR, MASK_XOR, m_op }, + { "srl", "d,s,t", MATCH_SRL, MASK_SRL, m_op }, + { "sra", "d,s,t", MATCH_SRA, MASK_SRA, m_op }, + { "or", "d,s,t", MATCH_OR, MASK_OR, m_op }, + { "and", "d,s,t", MATCH_AND, MASK_AND, m_op }, + { "addiw", "d,s,j", MATCH_ADDIW, MASK_ADDIW, m_op }, + { "slliw", "d,s,<", MATCH_SLLIW, MASK_SLLIW, m_op }, + { "srliw", "d,s,<", MATCH_SRLIW, MASK_SRLIW, m_op }, + { "sraiw", "d,s,<", MATCH_SRAIW, MASK_SRAIW, m_op }, + { "addw", "d,s,t", MATCH_ADDW, MASK_ADDW, m_op }, + { "subw", "d,s,t", MATCH_SUBW, MASK_SUBW, m_op }, + { "sllw", "d,s,t", MATCH_SLLW, MASK_SLLW, m_op }, + { "srlw", "d,s,t", MATCH_SRLW, MASK_SRLW, m_op }, + { "sraw", "d,s,t", MATCH_SRAW, MASK_SRAW, m_op }, + { "lb", "d,o(s)", MATCH_LB, MASK_LB, m_op }, + { "lh", "d,o(s)", MATCH_LH, MASK_LH, m_op }, + { "lw", "d,o(s)", MATCH_LW, MASK_LW, m_op }, + { "ld", "d,o(s)", MATCH_LD, MASK_LD, m_op }, + { "lbu", "d,o(s)", MATCH_LBU, MASK_LBU, m_op }, + { "lhu", "d,o(s)", MATCH_LHU, MASK_LHU, m_op }, + { "lwu", "d,o(s)", MATCH_LWU, MASK_LWU, m_op }, + { "sb", "t,q(s)", MATCH_SB, MASK_SB, m_op }, + { "sh", "t,q(s)", MATCH_SH, MASK_SH, m_op }, + { "sw", "t,q(s)", MATCH_SW, MASK_SW, m_op }, + { "sd", "t,q(s)", MATCH_SD, MASK_SD, m_op }, + { "fence", "P,Q", MATCH_FENCE, MASK_FENCE, m_op }, + { "fence.i", "", MATCH_FENCE_I, MASK_FENCE_I, m_op }, + { "mul", "d,s,t", MATCH_MUL, MASK_MUL, m_op }, + { "mulh", "d,s,t", MATCH_MULH, MASK_MULH, m_op }, + { "mulhsu", "d,s,t", MATCH_MULHSU, MASK_MULHSU, m_op }, + { "mulhu", "d,s,t", MATCH_MULHU, MASK_MULHU, m_op }, + { "div", "d,s,t", MATCH_DIV, MASK_DIV, m_op }, + { "divu", "d,s,t", MATCH_DIVU, MASK_DIVU, m_op }, + { "rem", "d,s,t", MATCH_REM, MASK_REM, m_op }, + { "remu", "d,s,t", MATCH_REMU, MASK_REMU, m_op }, + { "mulw", "d,s,t", MATCH_MULW, MASK_MULW, m_op }, + { "divw", "d,s,t", MATCH_DIVW, MASK_DIVW, m_op }, + { "divuw", "d,s,t", MATCH_DIVUW, MASK_DIVUW, m_op }, + { "remw", "d,s,t", MATCH_REMW, MASK_REMW, m_op }, + { "remuw", "d,s,t", MATCH_REMUW, MASK_REMUW, m_op }, + { "amoadd.w", "d,t,0(s)", MATCH_AMOADD_W, MASK_AMOADD_W, m_op }, + { "amoxor.w", "d,t,0(s)", MATCH_AMOXOR_W, MASK_AMOXOR_W, m_op }, + { "amoor.w", "d,t,0(s)", MATCH_AMOOR_W, MASK_AMOOR_W, m_op }, + { "amoand.w", "d,t,0(s)", MATCH_AMOAND_W, MASK_AMOAND_W, m_op }, + { "amomin.w", "d,t,0(s)", MATCH_AMOMIN_W, MASK_AMOMIN_W, m_op }, + { "amomax.w", "d,t,0(s)", MATCH_AMOMAX_W, MASK_AMOMAX_W, m_op }, + { "amominu.w", "d,t,0(s)", MATCH_AMOMINU_W, MASK_AMOMINU_W,m_op }, + { "amomaxu.w", "d,t,0(s)", MATCH_AMOMAXU_W, MASK_AMOMAXU_W,m_op }, + { "amoswap.w", "d,t,0(s)", MATCH_AMOSWAP_W, MASK_AMOSWAP_W,m_op }, + { "lr.w", "d,0(s)", MATCH_LR_W, MASK_LR_W, m_op }, + { "sc.w", "d,t,0(s)", MATCH_SC_W, MASK_SC_W, m_op }, + { "amoadd.d", "d,t,0(s)", MATCH_AMOADD_D, MASK_AMOADD_D, m_op }, + { "amoxor.d", "d,t,0(s)", MATCH_AMOXOR_D, MASK_AMOXOR_D, m_op }, + { "amoor.d", "d,t,0(s)", MATCH_AMOOR_D, MASK_AMOOR_D, m_op }, + { "amoand.d", "d,t,0(s)", MATCH_AMOAND_D, MASK_AMOAND_D, m_op }, + { "amomin.d", "d,t,0(s)", MATCH_AMOMIN_D, MASK_AMOMIN_D, m_op }, + { "amomax.d", "d,t,0(s)", MATCH_AMOMAX_D, MASK_AMOMAX_D, m_op }, + { "amominu.d", "d,t,0(s)", MATCH_AMOMINU_D, MASK_AMOMINU_D,m_op }, + { "amomaxu.d", "d,t,0(s)", MATCH_AMOMAXU_D, MASK_AMOMAXU_D,m_op }, + { "amoswap.d", "d,t,0(s)", MATCH_AMOSWAP_D, MASK_AMOSWAP_D,m_op }, + { "lr.d", "d,0(s)", MATCH_LR_D, MASK_LR_D, m_op }, + { "sc.d", "d,t,0(s)", MATCH_SC_D, MASK_SC_D, m_op }, + { "ecall", "", MATCH_ECALL, MASK_ECALL, m_op }, + { "ebreak", "", MATCH_EBREAK, MASK_EBREAK, m_op }, + { "uret", "", MATCH_URET, MASK_URET, m_op }, + { "sret", "", MATCH_SRET, MASK_SRET, m_op }, + { "mret", "", MATCH_MRET, MASK_MRET, m_op }, + { "dret", "", MATCH_DRET, MASK_DRET, m_op }, + { "sfence.vma", "", MATCH_SFENCE_VMA, MASK_SFENCE_VMA, m_op }, + { "wfi", "", MATCH_WFI, MASK_WFI, m_op }, + { "csrrw", "d,E,s", MATCH_CSRRW, MASK_CSRRW, m_op }, + { "csrrs", "d,E,s", MATCH_CSRRS, MASK_CSRRS, m_op }, + { "csrrc", "d,E,s", MATCH_CSRRC, MASK_CSRRC, m_op }, + { "csrrwi", "d,E,Z", MATCH_CSRRWI, MASK_CSRRWI, m_op }, + { "csrrsi", "d,E,Z", MATCH_CSRRSI, MASK_CSRRSI, m_op }, + { "csrrci", "d,E,Z", MATCH_CSRRCI, MASK_CSRRCI, m_op }, + { "fadd.s", "D,S,T", MATCH_FADD_S, MASK_FADD_S, m_op }, + { "fsub.s", "D,S,T", MATCH_FSUB_S, MASK_FSUB_S, m_op }, + { "fmul.s", "D,S,T", MATCH_FMUL_S, MASK_FMUL_S, m_op }, + { "fdiv.s", "D,S,T", MATCH_FDIV_S, MASK_FDIV_S, m_op }, + { "fsgnj.s", "D,S,T", MATCH_FSGNJ_S, MASK_FSGNJ_S, m_op }, + { "fsgnjn.s", "D,S,T", MATCH_FSGNJN_S, MASK_FSGNJN_S, m_op }, + { "fsgnjx.s", "D,S,T", MATCH_FSGNJX_S, MASK_FSGNJX_S, m_op }, + { "fmin.s", "D,S,T", MATCH_FMIN_S, MASK_FMIN_S, m_op }, + { "fmax.s", "D,S,T", MATCH_FMAX_S, MASK_FMAX_S, m_op }, + { "fsqrt.s", "D,S", MATCH_FSQRT_S, MASK_FSQRT_S, m_op }, + { "fadd.d", "D,S,T", MATCH_FADD_D, MASK_FADD_D, m_op }, + { "fsub.d", "D,S,T", MATCH_FSUB_D, MASK_FSUB_D, m_op }, + { "fmul.d", "D,S,T", MATCH_FMUL_D, MASK_FMUL_D, m_op }, + { "fdiv.d", "D,S,T", MATCH_FDIV_D, MASK_FDIV_D, m_op }, + { "fsgnj.d", "D,S,T", MATCH_FSGNJ_D, MASK_FSGNJ_D, m_op }, + { "fsgnjn.d", "D,S,T", MATCH_FSGNJN_D, MASK_FSGNJN_D, m_op }, + { "fsgnjx.d", "D,S,T", MATCH_FSGNJX_D, MASK_FSGNJX_D, m_op }, + { "fmin.d", "D,S,T", MATCH_FMIN_D, MASK_FMIN_D, m_op }, + { "fmax.d", "D,S,T", MATCH_FMAX_D, MASK_FMAX_D, m_op }, + { "fcvt.s.d", "D,S", MATCH_FCVT_S_D, MASK_FCVT_S_D, m_op }, + { "fcvt.d.s", "D,S", MATCH_FCVT_D_S, MASK_FCVT_D_S, m_op }, + { "fsqrt.d", "D,S", MATCH_FSQRT_D, MASK_FSQRT_D, m_op }, + { "fadd.q", "D,S,T", MATCH_FADD_Q, MASK_FADD_Q, m_op }, + { "fsub.q", "D,S,T", MATCH_FSUB_Q, MASK_FSUB_Q, m_op }, + { "fmul.q", "D,S,T", MATCH_FMUL_Q, MASK_FMUL_Q, m_op }, + { "fdiv.q", "D,S,T", MATCH_FDIV_Q, MASK_FDIV_Q, m_op }, + { "fsgnj.q", "D,S,T", MATCH_FSGNJ_Q, MASK_FSGNJ_Q, m_op }, + { "fsgnjn.q", "D,S,T", MATCH_FSGNJN_Q, MASK_FSGNJN_Q, m_op }, + { "fsgnjx.q", "D,S,T", MATCH_FSGNJX_Q, MASK_FSGNJX_Q, m_op }, + { "fmin.q", "D,S,T", MATCH_FMIN_Q, MASK_FMIN_Q, m_op }, + { "fmax.q", "D,S,T", MATCH_FMAX_Q, MASK_FMAX_Q, m_op }, + { "fcvt.s.q", "D,S", MATCH_FCVT_S_Q, MASK_FCVT_S_Q, m_op }, + { "fcvt.q.s", "D,S", MATCH_FCVT_Q_S, MASK_FCVT_Q_S, m_op }, + { "fcvt.d.q", "D,S", MATCH_FCVT_D_Q, MASK_FCVT_D_Q, m_op }, + { "fcvt.q.d", "D,S", MATCH_FCVT_Q_D, MASK_FCVT_Q_D, m_op }, + { "fsqrt.q", "D,S", MATCH_FSQRT_Q, MASK_FSQRT_Q, m_op }, + { "fle.s", "d,S,T", MATCH_FLE_S, MASK_FLE_S, m_op }, + { "flt.s", "d,S,T", MATCH_FLT_S, MASK_FLT_S, m_op }, + { "feq.s", "d,S,T", MATCH_FEQ_S, MASK_FEQ_S, m_op }, + { "fle.d", "d,S,T", MATCH_FLE_D, MASK_FLE_D, m_op }, + { "flt.d", "d,S,T", MATCH_FLT_D, MASK_FLT_D, m_op }, + { "feq.d", "d,S,T", MATCH_FEQ_D, MASK_FEQ_D, m_op }, + { "fle.q", "d,S,T", MATCH_FLE_Q, MASK_FLE_Q, m_op }, + { "flt.q", "d,S,T", MATCH_FLT_Q, MASK_FLT_Q, m_op }, + { "feq.q", "d,S,T", MATCH_FEQ_Q, MASK_FEQ_Q, m_op }, + { "fcvt.w.s", "d,S", MATCH_FCVT_W_S, MASK_FCVT_W_S, m_op }, + { "fcvt.wu.s", "d,S", MATCH_FCVT_WU_S, MASK_FCVT_WU_S,m_op }, + { "fcvt.l.s", "d,S", MATCH_FCVT_L_S, MASK_FCVT_L_S, m_op }, + { "fcvt.lu.s", "d,S", MATCH_FCVT_LU_S, MASK_FCVT_LU_S,m_op }, + { "fmv.x.w", "d,S", MATCH_FMV_X_W, MASK_FMV_X_W, m_op }, + { "fclass.s", "d,S", MATCH_FCLASS_S, MASK_FCLASS_S, m_op }, + { "fcvt.w.d", "d,S", MATCH_FCVT_W_D, MASK_FCVT_W_D, m_op }, + { "fcvt.wu.d", "d,S", MATCH_FCVT_WU_D, MASK_FCVT_WU_D,m_op }, + { "fcvt.l.d", "d,S", MATCH_FCVT_L_D, MASK_FCVT_L_D, m_op }, + { "fcvt.lu.d", "d,S", MATCH_FCVT_LU_D, MASK_FCVT_LU_D,m_op }, + { "fmv.x.d", "d,S", MATCH_FMV_X_D, MASK_FMV_X_D, m_op }, + { "fclass.d", "d,S", MATCH_FCLASS_D, MASK_FCLASS_D, m_op }, + { "fcvt.w.q", "d,S", MATCH_FCVT_W_Q, MASK_FCVT_W_Q, m_op }, + { "fcvt.wu.q", "d,S", MATCH_FCVT_WU_Q, MASK_FCVT_WU_Q,m_op }, + { "fcvt.l.q", "d,S", MATCH_FCVT_L_Q, MASK_FCVT_L_Q, m_op }, + { "fcvt.lu.q", "d,S", MATCH_FCVT_LU_Q, MASK_FCVT_LU_Q,m_op }, +#ifdef RV128Q + { "fmv.x.q", "d,S", MATCH_FMV_X_Q, MASK_FMV_X_Q, m_op }, +#endif + { "fclass.q", "d,S", MATCH_FCLASS_Q, MASK_FCLASS_Q, m_op }, + { "fcvt.s.w", "D,s", MATCH_FCVT_S_W, MASK_FCVT_S_W, m_op }, + { "fcvt.s.wu", "D,s", MATCH_FCVT_S_WU, MASK_FCVT_S_WU,m_op }, + { "fcvt.s.l", "D,s", MATCH_FCVT_S_L, MASK_FCVT_S_L, m_op }, + { "fcvt.s.lu", "D,s", MATCH_FCVT_S_LU, MASK_FCVT_S_LU,m_op }, + { "fmv.w.x", "D,s", MATCH_FMV_W_X, MASK_FMV_W_X, m_op }, + { "fcvt.d.w", "D,s", MATCH_FCVT_D_W, MASK_FCVT_D_W, m_op }, + { "fcvt.d.wu", "D,s", MATCH_FCVT_D_WU, MASK_FCVT_D_WU,m_op }, + { "fcvt.d.l", "D,s", MATCH_FCVT_D_L, MASK_FCVT_D_L, m_op }, + { "fcvt.d.lu", "D,s", MATCH_FCVT_D_LU, MASK_FCVT_D_LU,m_op }, + { "fmv.d.x", "D,s", MATCH_FMV_D_X, MASK_FMV_D_X, m_op }, + { "fcvt.q.w", "D,s", MATCH_FCVT_Q_W, MASK_FCVT_Q_W, m_op }, + { "fcvt.q.wu", "D,s", MATCH_FCVT_Q_WU, MASK_FCVT_Q_WU,m_op }, + { "fcvt.q.l", "D,s", MATCH_FCVT_Q_L, MASK_FCVT_Q_L, m_op }, + { "fcvt.q.lu", "D,s", MATCH_FCVT_Q_LU, MASK_FCVT_Q_LU,m_op }, +#ifdef RV128Q + { "fmv.q.x", "D,s", MATCH_FMV_Q_X, MASK_FMV_Q_X, m_op }, +#endif + { "flw", "D,o(s)", MATCH_FLW, MASK_FLW, m_op }, + { "fld", "D,o(s)", MATCH_FLD, MASK_FLD, m_op }, + { "flq", "D,o(s)", MATCH_FLQ, MASK_FLQ, m_op }, + { "fsw", "T,q(s)", MATCH_FSW, MASK_FSW, m_op }, + { "fsd", "T,q(s)", MATCH_FSD, MASK_FSD, m_op }, + { "fsq", "T,q(s)", MATCH_FSQ, MASK_FSQ, m_op }, + { "fmadd.s", "D,S,T,R", MATCH_FMADD_S, MASK_FMADD_S, m_op }, + { "fmsub.s", "D,S,T,R", MATCH_FMSUB_S, MASK_FMSUB_S, m_op }, + { "fnmsub.s", "D,S,T,R", MATCH_FNMSUB_S, MASK_FNMSUB_S, m_op }, + { "fnmadd.s", "D,S,T,R", MATCH_FNMADD_S, MASK_FNMADD_S, m_op }, + { "fmadd.d", "D,S,T,R", MATCH_FMADD_D, MASK_FMADD_D, m_op }, + { "fmsub.d", "D,S,T,R", MATCH_FMSUB_D, MASK_FMSUB_D, m_op }, + { "fnmsub.d", "D,S,T,R", MATCH_FNMSUB_D, MASK_FNMSUB_D, m_op }, + { "fnmadd.d", "D,S,T,R", MATCH_FNMADD_D, MASK_FNMADD_D, m_op }, + { "fmadd.q", "D,S,T,R", MATCH_FMADD_Q, MASK_FMADD_Q, m_op }, + { "fmsub.q", "D,S,T,R", MATCH_FMSUB_Q, MASK_FMSUB_Q, m_op }, + { "fnmsub.q", "D,S,T,R", MATCH_FNMSUB_Q, MASK_FNMSUB_Q, m_op }, + { "fnmadd.q", "D,S,T,R", MATCH_FNMADD_Q, MASK_FNMADD_Q, m_op }, + { NULL, NULL, 0, 0, NULL }, +}; + +static struct loongarch_op loongarch_c_opcodes[] = { + /* Aliases first */ + { "ret","",MATCH_C_JR | (X_RA << RD_SHIFT), MASK_C_JR | RD_MASK, m_op}, + + /* C-Compressed ISA Extension Instructions */ + { "c.nop", "", MATCH_C_NOP, MASK_C_NOP, m_op }, + { "c.ebreak", "", MATCH_C_EBREAK, MASK_C_EBREAK, m_op }, + { "c.jr", "d", MATCH_C_JR, MASK_C_JR, m_op }, + { "c.jalr", "d", MATCH_C_JALR, MASK_C_JALR, m_op }, + { "c.jal", "Ca", MATCH_C_JAL, MASK_C_JAL, m_op }, + { "c.ld", "Ct,Cl(Cs)", MATCH_C_LD, MASK_C_LD, m_op }, + { "c.sd", "Ct,Cl(Cs)", MATCH_C_SD, MASK_C_SD, m_op }, + { "c.addiw", "d,Co", MATCH_C_ADDIW, MASK_C_ADDIW, m_op }, + { "c.ldsp", "d,Cn(Cc)", MATCH_C_LDSP, MASK_C_LDSP, m_op }, + { "c.sdsp", "CV,CN(Cc)", MATCH_C_SDSP, MASK_C_SDSP, m_op }, + { "c.addi4spn", "", MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN, m_op }, + { "c.addi16sp", "", MATCH_C_ADDI16SP, MASK_C_ADDI16SP, m_op }, + { "c.fld", "CD,Cl(Cs)", MATCH_C_FLD, MASK_C_FLD, m_op }, + { "c.lw", "Ct,Ck(Cs)", MATCH_C_LW, MASK_C_LW, m_op }, + { "c.flw", "CD,Ck(Cs)", MATCH_C_FLW, MASK_C_FLW, m_op }, + { "c.fsd", "CD,Cl(Cs)", MATCH_C_FSD, MASK_C_FSD, m_op }, + { "c.sw", "Ct,Ck(Cs)", MATCH_C_SW, MASK_C_SW, m_op }, + { "c.fsw", "CD,Ck(Cs)", MATCH_C_FSW, MASK_C_FSW, m_op }, + { "c.addi", "d,Co", MATCH_C_ADDI, MASK_C_ADDI, m_op }, + { "c.li", "d,Co", MATCH_C_LI, MASK_C_LI, m_op }, + { "c.lui", "d,Cu", MATCH_C_LUI, MASK_C_LUI, m_op }, + { "c.srli", "Cs,C>", MATCH_C_SRLI, MASK_C_SRLI, m_op }, + { "c.srai", "Cs,C>", MATCH_C_SRAI, MASK_C_SRAI, m_op }, + { "c.andi", "Cs,Co", MATCH_C_ANDI, MASK_C_ANDI, m_op }, + { "c.sub", "Cs,Ct", MATCH_C_SUB, MASK_C_SUB, m_op }, + { "c.xor", "Cs,Ct", MATCH_C_XOR, MASK_C_XOR, m_op }, + { "c.or", "Cs,Ct", MATCH_C_OR, MASK_C_OR, m_op }, + { "c.and", "Cs,Ct", MATCH_C_AND, MASK_C_AND, m_op }, + { "c.subw", "Cs,Ct", MATCH_C_SUBW, MASK_C_SUBW, m_op }, + { "c.addw", "Cs,Ct", MATCH_C_ADDW, MASK_C_ADDW, m_op }, + { "c.j", "Ca", MATCH_C_J, MASK_C_J, m_op }, + { "c.beqz", "Cs,Cp", MATCH_C_BEQZ, MASK_C_BEQZ, m_op }, + { "c.bnez", "Cs,Cp", MATCH_C_BNEZ, MASK_C_BNEZ, m_op }, + { "c.slli", "d,C>", MATCH_C_SLLI, MASK_C_SLLI, m_op }, + { "c.fldsp", "D,Cn(Cc)", MATCH_C_FLDSP, MASK_C_FLDSP, m_op }, + { "c.lwsp", "d,Cm(Cc)", MATCH_C_LWSP, MASK_C_LWSP, m_op }, + { "c.flwsp", "D,Cm(Cc)", MATCH_C_FLWSP, MASK_C_FLWSP, m_op }, + { "c.mv", "d,CV", MATCH_C_MV, MASK_C_MV, m_op }, + { "c.add", "d,CV", MATCH_C_ADD, MASK_C_ADD, m_op }, + { "c.fsdsp", "CT,CN(Cc)", MATCH_C_FSDSP, MASK_C_FSDSP, m_op }, + { "c.swsp", "CV,CM(Cc)", MATCH_C_SWSP, MASK_C_SWSP, m_op }, + { "c.fswsp", "CT,CM(Cc)", MATCH_C_FSWSP, MASK_C_FSWSP, m_op }, + { NULL, NULL, 0, 0, NULL }, +}; + +static int +oprint(struct loongarch_op *op, vaddr_t loc, int insn) +{ + uint32_t rd, rs1, rs2, rs3; + uint32_t val; + const char *csr_name; + int imm; + char *p; + + p = op->fmt; + + rd = (insn & RD_MASK) >> RD_SHIFT; + rs1 = (insn & RS1_MASK) >> RS1_SHIFT; + rs2 = (insn & RS2_MASK) >> RS2_SHIFT; + + db_printf("%s\t", op->name); + + while (*p) { + switch (*p) { + case 'C': /* C-Compressed ISA extension */ + switch (*++p) { + case 't': + rd = (insn >> 2) & 0x7; + rd += 0x8; + db_printf("%s", reg_name[rd]); + break; + case 's': + rs2 = (insn >> 7) & 0x7; + rs2 += 0x8; + db_printf("%s", reg_name[rs2]); + break; + case 'l': + imm = ((insn >> 10) & 0x7) << 3; + imm |= ((insn >> 5) & 0x3) << 6; + if (imm & (1 << 8)) + imm |= 0xffffff << 8; + db_printf("%d", imm); + break; + case 'k': + imm = ((insn >> 10) & 0x7) << 3; + imm |= ((insn >> 6) & 0x1) << 2; + imm |= ((insn >> 5) & 0x1) << 6; + if (imm & (1 << 8)) + imm |= 0xffffff << 8; + db_printf("%d", imm); + break; + case 'c': + db_printf("sp"); + break; + case 'n': + imm = ((insn >> 5) & 0x3) << 3; + imm |= ((insn >> 12) & 0x1) << 5; + imm |= ((insn >> 2) & 0x7) << 6; + if (imm & (1 << 8)) + imm |= 0xffffff << 8; + db_printf("%d", imm); + break; + case 'N': + imm = ((insn >> 10) & 0x7) << 3; + imm |= ((insn >> 7) & 0x7) << 6; + if (imm & (1 << 8)) + imm |= 0xffffff << 8; + db_printf("%d", imm); + break; + case 'u': + imm = ((insn >> 2) & 0x1f) << 0; + imm |= ((insn >> 12) & 0x1) << 5; + if (imm & (1 << 5)) + imm |= (0x7ffffff << 5); /* sign ext */ + db_printf("0x%x", imm); + break; + case 'o': + imm = ((insn >> 2) & 0x1f) << 0; + imm |= ((insn >> 12) & 0x1) << 5; + if (imm & (1 << 5)) + imm |= (0x7ffffff << 5); /* sign ext */ + db_printf("%d", imm); + break; + case 'a': + /* imm[11|4|9:8|10|6|7|3:1|5] << 2 */ + imm = ((insn >> 3) & 0x7) << 1; + imm |= ((insn >> 11) & 0x1) << 4; + imm |= ((insn >> 2) & 0x1) << 5; + imm |= ((insn >> 7) & 0x1) << 6; + imm |= ((insn >> 6) & 0x1) << 7; + imm |= ((insn >> 9) & 0x3) << 8; + imm |= ((insn >> 8) & 0x1) << 10; + imm |= ((insn >> 12) & 0x1) << 11; + if (imm & (1 << 11)) + imm |= (0xfffff << 12); /* sign ext */ + db_printf("0x%lx", (loc + imm)); + break; + case 'V': + rs2 = (insn >> 2) & 0x1f; + db_printf("%s", reg_name[rs2]); + break; + case '>': + imm = ((insn >> 2) & 0x1f) << 0; + imm |= ((insn >> 12) & 0x1) << 5; + db_printf("%d", imm); + } + break; + case 'd': + db_printf("%s", reg_name[rd]); + break; + case 'D': + db_printf("%s", fp_reg_name[rd]); + break; + case 's': + db_printf("%s", reg_name[rs1]); + break; + case 'S': + db_printf("%s", fp_reg_name[rs1]); + break; + case 't': + db_printf("%s", reg_name[rs2]); + break; + case 'T': + db_printf("%s", fp_reg_name[rs2]); + break; + case 'R': + rs3 = (insn >> 27) & 0x1f; + db_printf("%s", fp_reg_name[rs3]); + break; + case 'Z': + imm = (insn >> 15) & 0x1f; + db_printf("%d", imm); + break; + case 'p': + imm = ((insn >> 8) & 0xf) << 1; + imm |= ((insn >> 25) & 0x3f) << 5; + imm |= ((insn >> 7) & 0x1) << 11; + imm |= ((insn >> 31) & 0x1) << 12; + if (imm & (1 << 12)) + imm |= (0xfffff << 12); /* sign extend */ + db_printf("0x%016lx", (loc + imm)); + break; + case '(': + case ')': + case '[': + case ']': + case ',': + db_printf("%c", *p); + break; + case '0': + if (!p[1]) + db_printf("%c", *p); + break; + case 'o': + imm = (insn >> 20) & 0xfff; + if (imm & (1 << 11)) + imm |= (0xfffff << 12); /* sign extend */ + db_printf("%d", imm); + break; + case 'q': + imm = (insn >> 7) & 0x1f; + imm |= ((insn >> 25) & 0x7f) << 5; + if (imm & (1 << 11)) + imm |= (0xfffff << 12); /* sign extend */ + db_printf("%d", imm); + break; + case 'a': + /* imm[20|10:1|11|19:12] << 12 */ + imm = ((insn >> 21) & 0x3ff) << 1; + imm |= ((insn >> 20) & 0x1) << 11; + imm |= ((insn >> 12) & 0xff) << 12; + imm |= ((insn >> 31) & 0x1) << 20; + if (imm & (1 << 20)) + imm |= (0xfff << 20); /* sign extend */ + db_printf("0x%lx", (loc + imm)); + break; + case 'u': + /* imm[31:12] << 12 */ + imm = (insn >> 12) & 0xfffff; + if (imm & (1 << 20)) + imm |= (0xfff << 20); /* sign extend */ + db_printf("0x%x", imm); + break; + case 'j': + /* imm[11:0] << 20 */ + imm = (insn >> 20) & 0xfff; + if (imm & (1 << 11)) + imm |= (0xfffff << 12); /* sign extend */ + db_printf("%d", imm); + break; + case '>': + val = (insn >> 20) & 0x3f; + db_printf("0x%x", val); + break; + case '<': + val = (insn >> 20) & 0x1f; + db_printf("0x%x", val); + break; + case 'E': + val = (insn >> 20) & 0xfff; + csr_name = NULL; + switch (val) { +#define DECLARE_CSR(name, num) case num: csr_name = #name; break; +#include "loongarch64/loongarch64/db_instruction.h" +#undef DECLARE_CSR + } + if (csr_name) + db_printf("%s", csr_name); + else + db_printf("0x%x", val); + break; + case 'P': + if (insn & (1 << 27)) db_printf("i"); + if (insn & (1 << 26)) db_printf("o"); + if (insn & (1 << 25)) db_printf("r"); + if (insn & (1 << 24)) db_printf("w"); + break; + case 'Q': + if (insn & (1 << 23)) db_printf("i"); + if (insn & (1 << 22)) db_printf("o"); + if (insn & (1 << 21)) db_printf("r"); + if (insn & (1 << 20)) db_printf("w"); + break; + } + + p++; + } + + return (0); +} + +vaddr_t +db_disasm(vaddr_t loc, int altfmt) +{ + struct loongarch_op *op; + uint32_t insn; + int j; + + insn = db_get_value(loc, 4, 0); + for (j = 0; loongarch_opcodes[j].name != NULL; j++) { + op = &loongarch_opcodes[j]; + if (op->match_func(op, insn)) { + oprint(op, loc, insn); + return (loc + 4); + } + } + + insn = db_get_value(loc, 2, 0); + for (j = 0; loongarch_c_opcodes[j].name != NULL; j++) { + op = &loongarch_c_opcodes[j]; + if (op->match_func(op, insn)) { + oprint(op, loc, insn); + break; + } + } + + db_printf("\n"); + return (loc + 2); +} diff --git sys/arch/loongarch64/loongarch64/db_instruction.h sys/arch/loongarch64/loongarch64/db_instruction.h new file mode 100644 index 00000000000..2838d0cd847 --- /dev/null +++ sys/arch/loongarch64/loongarch64/db_instruction.h @@ -0,0 +1,3406 @@ +/* $OpenBSD: db_instruction.h,v 1.2 2021/05/12 01:24:32 jsg Exp $ */ + +/* + * db_instruction.h: $(ALL_OPCODES) parse_opcodes + * cat $(ALL_OPCODES) | python3 ./parse_opcodes -c > $@ + */ + +/* Automatically generated by parse_opcodes. */ +#ifndef LOONGARCH_ENCODING_H +#define LOONGARCH_ENCODING_H +#define MATCH_SLLI_RV32 0x1013 +#define MASK_SLLI_RV32 0xfe00707f +#define MATCH_SRLI_RV32 0x5013 +#define MASK_SRLI_RV32 0xfe00707f +#define MATCH_SRAI_RV32 0x40005013 +#define MASK_SRAI_RV32 0xfe00707f +#define MATCH_FRFLAGS 0x102073 +#define MASK_FRFLAGS 0xfffff07f +#define MATCH_FSFLAGS 0x101073 +#define MASK_FSFLAGS 0xfff0707f +#define MATCH_FSFLAGSI 0x105073 +#define MASK_FSFLAGSI 0xfff0707f +#define MATCH_FRRM 0x202073 +#define MASK_FRRM 0xfffff07f +#define MATCH_FSRM 0x201073 +#define MASK_FSRM 0xfff0707f +#define MATCH_FSRMI 0x205073 +#define MASK_FSRMI 0xfff0707f +#define MATCH_FSCSR 0x301073 +#define MASK_FSCSR 0xfff0707f +#define MATCH_FRCSR 0x302073 +#define MASK_FRCSR 0xfffff07f +#define MATCH_RDCYCLE 0xc0002073 +#define MASK_RDCYCLE 0xfffff07f +#define MATCH_RDTIME 0xc0102073 +#define MASK_RDTIME 0xfffff07f +#define MATCH_RDINSTRET 0xc0202073 +#define MASK_RDINSTRET 0xfffff07f +#define MATCH_RDCYCLEH 0xc8002073 +#define MASK_RDCYCLEH 0xfffff07f +#define MATCH_RDTIMEH 0xc8102073 +#define MASK_RDTIMEH 0xfffff07f +#define MATCH_RDINSTRETH 0xc8202073 +#define MASK_RDINSTRETH 0xfffff07f +#define MATCH_SCALL 0x73 +#define MASK_SCALL 0xffffffff +#define MATCH_SBREAK 0x100073 +#define MASK_SBREAK 0xffffffff +#define MATCH_FMV_X_S 0xe0000053 +#define MASK_FMV_X_S 0xfff0707f +#define MATCH_FMV_S_X 0xf0000053 +#define MASK_FMV_S_X 0xfff0707f +#define MATCH_FENCE_TSO 0x8330000f +#define MASK_FENCE_TSO 0xfff0707f +#define MATCH_PAUSE 0x100000f +#define MASK_PAUSE 0xffffffff +#define MATCH_BEQ 0x63 +#define MASK_BEQ 0x707f +#define MATCH_BNE 0x1063 +#define MASK_BNE 0x707f +#define MATCH_BLT 0x4063 +#define MASK_BLT 0x707f +#define MATCH_BGE 0x5063 +#define MASK_BGE 0x707f +#define MATCH_BLTU 0x6063 +#define MASK_BLTU 0x707f +#define MATCH_BGEU 0x7063 +#define MASK_BGEU 0x707f +#define MATCH_JALR 0x67 +#define MASK_JALR 0x707f +#define MATCH_JAL 0x6f +#define MASK_JAL 0x7f +#define MATCH_LUI 0x37 +#define MASK_LUI 0x7f +#define MATCH_AUIPC 0x17 +#define MASK_AUIPC 0x7f +#define MATCH_ADDI 0x13 +#define MASK_ADDI 0x707f +#define MATCH_SLLI 0x1013 +#define MASK_SLLI 0xfc00707f +#define MATCH_SLTI 0x2013 +#define MASK_SLTI 0x707f +#define MATCH_SLTIU 0x3013 +#define MASK_SLTIU 0x707f +#define MATCH_XORI 0x4013 +#define MASK_XORI 0x707f +#define MATCH_SRLI 0x5013 +#define MASK_SRLI 0xfc00707f +#define MATCH_SRAI 0x40005013 +#define MASK_SRAI 0xfc00707f +#define MATCH_ORI 0x6013 +#define MASK_ORI 0x707f +#define MATCH_ANDI 0x7013 +#define MASK_ANDI 0x707f +#define MATCH_ADD 0x33 +#define MASK_ADD 0xfe00707f +#define MATCH_SUB 0x40000033 +#define MASK_SUB 0xfe00707f +#define MATCH_SLL 0x1033 +#define MASK_SLL 0xfe00707f +#define MATCH_SLT 0x2033 +#define MASK_SLT 0xfe00707f +#define MATCH_SLTU 0x3033 +#define MASK_SLTU 0xfe00707f +#define MATCH_XOR 0x4033 +#define MASK_XOR 0xfe00707f +#define MATCH_SRL 0x5033 +#define MASK_SRL 0xfe00707f +#define MATCH_SRA 0x40005033 +#define MASK_SRA 0xfe00707f +#define MATCH_OR 0x6033 +#define MASK_OR 0xfe00707f +#define MATCH_AND 0x7033 +#define MASK_AND 0xfe00707f +#define MATCH_LB 0x3 +#define MASK_LB 0x707f +#define MATCH_LH 0x1003 +#define MASK_LH 0x707f +#define MATCH_LW 0x2003 +#define MASK_LW 0x707f +#define MATCH_LBU 0x4003 +#define MASK_LBU 0x707f +#define MATCH_LHU 0x5003 +#define MASK_LHU 0x707f +#define MATCH_SB 0x23 +#define MASK_SB 0x707f +#define MATCH_SH 0x1023 +#define MASK_SH 0x707f +#define MATCH_SW 0x2023 +#define MASK_SW 0x707f +#define MATCH_FENCE 0xf +#define MASK_FENCE 0x707f +#define MATCH_FENCE_I 0x100f +#define MASK_FENCE_I 0x707f +#define MATCH_ADDIW 0x1b +#define MASK_ADDIW 0x707f +#define MATCH_SLLIW 0x101b +#define MASK_SLLIW 0xfe00707f +#define MATCH_SRLIW 0x501b +#define MASK_SRLIW 0xfe00707f +#define MATCH_SRAIW 0x4000501b +#define MASK_SRAIW 0xfe00707f +#define MATCH_ADDW 0x3b +#define MASK_ADDW 0xfe00707f +#define MATCH_SUBW 0x4000003b +#define MASK_SUBW 0xfe00707f +#define MATCH_SLLW 0x103b +#define MASK_SLLW 0xfe00707f +#define MATCH_SRLW 0x503b +#define MASK_SRLW 0xfe00707f +#define MATCH_SRAW 0x4000503b +#define MASK_SRAW 0xfe00707f +#define MATCH_LD 0x3003 +#define MASK_LD 0x707f +#define MATCH_LWU 0x6003 +#define MASK_LWU 0x707f +#define MATCH_SD 0x3023 +#define MASK_SD 0x707f +#define MATCH_MUL 0x2000033 +#define MASK_MUL 0xfe00707f +#define MATCH_MULH 0x2001033 +#define MASK_MULH 0xfe00707f +#define MATCH_MULHSU 0x2002033 +#define MASK_MULHSU 0xfe00707f +#define MATCH_MULHU 0x2003033 +#define MASK_MULHU 0xfe00707f +#define MATCH_DIV 0x2004033 +#define MASK_DIV 0xfe00707f +#define MATCH_DIVU 0x2005033 +#define MASK_DIVU 0xfe00707f +#define MATCH_REM 0x2006033 +#define MASK_REM 0xfe00707f +#define MATCH_REMU 0x2007033 +#define MASK_REMU 0xfe00707f +#define MATCH_MULW 0x200003b +#define MASK_MULW 0xfe00707f +#define MATCH_DIVW 0x200403b +#define MASK_DIVW 0xfe00707f +#define MATCH_DIVUW 0x200503b +#define MASK_DIVUW 0xfe00707f +#define MATCH_REMW 0x200603b +#define MASK_REMW 0xfe00707f +#define MATCH_REMUW 0x200703b +#define MASK_REMUW 0xfe00707f +#define MATCH_AMOADD_W 0x202f +#define MASK_AMOADD_W 0xf800707f +#define MATCH_AMOXOR_W 0x2000202f +#define MASK_AMOXOR_W 0xf800707f +#define MATCH_AMOOR_W 0x4000202f +#define MASK_AMOOR_W 0xf800707f +#define MATCH_AMOAND_W 0x6000202f +#define MASK_AMOAND_W 0xf800707f +#define MATCH_AMOMIN_W 0x8000202f +#define MASK_AMOMIN_W 0xf800707f +#define MATCH_AMOMAX_W 0xa000202f +#define MASK_AMOMAX_W 0xf800707f +#define MATCH_AMOMINU_W 0xc000202f +#define MASK_AMOMINU_W 0xf800707f +#define MATCH_AMOMAXU_W 0xe000202f +#define MASK_AMOMAXU_W 0xf800707f +#define MATCH_AMOSWAP_W 0x800202f +#define MASK_AMOSWAP_W 0xf800707f +#define MATCH_LR_W 0x1000202f +#define MASK_LR_W 0xf9f0707f +#define MATCH_SC_W 0x1800202f +#define MASK_SC_W 0xf800707f +#define MATCH_AMOADD_D 0x302f +#define MASK_AMOADD_D 0xf800707f +#define MATCH_AMOXOR_D 0x2000302f +#define MASK_AMOXOR_D 0xf800707f +#define MATCH_AMOOR_D 0x4000302f +#define MASK_AMOOR_D 0xf800707f +#define MATCH_AMOAND_D 0x6000302f +#define MASK_AMOAND_D 0xf800707f +#define MATCH_AMOMIN_D 0x8000302f +#define MASK_AMOMIN_D 0xf800707f +#define MATCH_AMOMAX_D 0xa000302f +#define MASK_AMOMAX_D 0xf800707f +#define MATCH_AMOMINU_D 0xc000302f +#define MASK_AMOMINU_D 0xf800707f +#define MATCH_AMOMAXU_D 0xe000302f +#define MASK_AMOMAXU_D 0xf800707f +#define MATCH_AMOSWAP_D 0x800302f +#define MASK_AMOSWAP_D 0xf800707f +#define MATCH_LR_D 0x1000302f +#define MASK_LR_D 0xf9f0707f +#define MATCH_SC_D 0x1800302f +#define MASK_SC_D 0xf800707f +#define MATCH_HFENCE_VVMA 0x22000073 +#define MASK_HFENCE_VVMA 0xfe007fff +#define MATCH_HFENCE_GVMA 0x62000073 +#define MASK_HFENCE_GVMA 0xfe007fff +#define MATCH_HLV_B 0x60004073 +#define MASK_HLV_B 0xfff0707f +#define MATCH_HLV_BU 0x60104073 +#define MASK_HLV_BU 0xfff0707f +#define MATCH_HLV_H 0x64004073 +#define MASK_HLV_H 0xfff0707f +#define MATCH_HLV_HU 0x64104073 +#define MASK_HLV_HU 0xfff0707f +#define MATCH_HLVX_HU 0x64304073 +#define MASK_HLVX_HU 0xfff0707f +#define MATCH_HLV_W 0x68004073 +#define MASK_HLV_W 0xfff0707f +#define MATCH_HLVX_WU 0x68304073 +#define MASK_HLVX_WU 0xfff0707f +#define MATCH_HSV_B 0x62004073 +#define MASK_HSV_B 0xfe007fff +#define MATCH_HSV_H 0x66004073 +#define MASK_HSV_H 0xfe007fff +#define MATCH_HSV_W 0x6a004073 +#define MASK_HSV_W 0xfe007fff +#define MATCH_HLV_WU 0x68104073 +#define MASK_HLV_WU 0xfff0707f +#define MATCH_HLV_D 0x6c004073 +#define MASK_HLV_D 0xfff0707f +#define MATCH_HSV_D 0x6e004073 +#define MASK_HSV_D 0xfe007fff +#define MATCH_FADD_S 0x53 +#define MASK_FADD_S 0xfe00007f +#define MATCH_FSUB_S 0x8000053 +#define MASK_FSUB_S 0xfe00007f +#define MATCH_FMUL_S 0x10000053 +#define MASK_FMUL_S 0xfe00007f +#define MATCH_FDIV_S 0x18000053 +#define MASK_FDIV_S 0xfe00007f +#define MATCH_FSGNJ_S 0x20000053 +#define MASK_FSGNJ_S 0xfe00707f +#define MATCH_FSGNJN_S 0x20001053 +#define MASK_FSGNJN_S 0xfe00707f +#define MATCH_FSGNJX_S 0x20002053 +#define MASK_FSGNJX_S 0xfe00707f +#define MATCH_FMIN_S 0x28000053 +#define MASK_FMIN_S 0xfe00707f +#define MATCH_FMAX_S 0x28001053 +#define MASK_FMAX_S 0xfe00707f +#define MATCH_FSQRT_S 0x58000053 +#define MASK_FSQRT_S 0xfff0007f +#define MATCH_FLE_S 0xa0000053 +#define MASK_FLE_S 0xfe00707f +#define MATCH_FLT_S 0xa0001053 +#define MASK_FLT_S 0xfe00707f +#define MATCH_FEQ_S 0xa0002053 +#define MASK_FEQ_S 0xfe00707f +#define MATCH_FCVT_W_S 0xc0000053 +#define MASK_FCVT_W_S 0xfff0007f +#define MATCH_FCVT_WU_S 0xc0100053 +#define MASK_FCVT_WU_S 0xfff0007f +#define MATCH_FMV_X_W 0xe0000053 +#define MASK_FMV_X_W 0xfff0707f +#define MATCH_FCLASS_S 0xe0001053 +#define MASK_FCLASS_S 0xfff0707f +#define MATCH_FCVT_S_W 0xd0000053 +#define MASK_FCVT_S_W 0xfff0007f +#define MATCH_FCVT_S_WU 0xd0100053 +#define MASK_FCVT_S_WU 0xfff0007f +#define MATCH_FMV_W_X 0xf0000053 +#define MASK_FMV_W_X 0xfff0707f +#define MATCH_FLW 0x2007 +#define MASK_FLW 0x707f +#define MATCH_FSW 0x2027 +#define MASK_FSW 0x707f +#define MATCH_FMADD_S 0x43 +#define MASK_FMADD_S 0x600007f +#define MATCH_FMSUB_S 0x47 +#define MASK_FMSUB_S 0x600007f +#define MATCH_FNMSUB_S 0x4b +#define MASK_FNMSUB_S 0x600007f +#define MATCH_FNMADD_S 0x4f +#define MASK_FNMADD_S 0x600007f +#define MATCH_FCVT_L_S 0xc0200053 +#define MASK_FCVT_L_S 0xfff0007f +#define MATCH_FCVT_LU_S 0xc0300053 +#define MASK_FCVT_LU_S 0xfff0007f +#define MATCH_FCVT_S_L 0xd0200053 +#define MASK_FCVT_S_L 0xfff0007f +#define MATCH_FCVT_S_LU 0xd0300053 +#define MASK_FCVT_S_LU 0xfff0007f +#define MATCH_FADD_D 0x2000053 +#define MASK_FADD_D 0xfe00007f +#define MATCH_FSUB_D 0xa000053 +#define MASK_FSUB_D 0xfe00007f +#define MATCH_FMUL_D 0x12000053 +#define MASK_FMUL_D 0xfe00007f +#define MATCH_FDIV_D 0x1a000053 +#define MASK_FDIV_D 0xfe00007f +#define MATCH_FSGNJ_D 0x22000053 +#define MASK_FSGNJ_D 0xfe00707f +#define MATCH_FSGNJN_D 0x22001053 +#define MASK_FSGNJN_D 0xfe00707f +#define MATCH_FSGNJX_D 0x22002053 +#define MASK_FSGNJX_D 0xfe00707f +#define MATCH_FMIN_D 0x2a000053 +#define MASK_FMIN_D 0xfe00707f +#define MATCH_FMAX_D 0x2a001053 +#define MASK_FMAX_D 0xfe00707f +#define MATCH_FCVT_S_D 0x40100053 +#define MASK_FCVT_S_D 0xfff0007f +#define MATCH_FCVT_D_S 0x42000053 +#define MASK_FCVT_D_S 0xfff0007f +#define MATCH_FSQRT_D 0x5a000053 +#define MASK_FSQRT_D 0xfff0007f +#define MATCH_FLE_D 0xa2000053 +#define MASK_FLE_D 0xfe00707f +#define MATCH_FLT_D 0xa2001053 +#define MASK_FLT_D 0xfe00707f +#define MATCH_FEQ_D 0xa2002053 +#define MASK_FEQ_D 0xfe00707f +#define MATCH_FCVT_W_D 0xc2000053 +#define MASK_FCVT_W_D 0xfff0007f +#define MATCH_FCVT_WU_D 0xc2100053 +#define MASK_FCVT_WU_D 0xfff0007f +#define MATCH_FCLASS_D 0xe2001053 +#define MASK_FCLASS_D 0xfff0707f +#define MATCH_FCVT_D_W 0xd2000053 +#define MASK_FCVT_D_W 0xfff0007f +#define MATCH_FCVT_D_WU 0xd2100053 +#define MASK_FCVT_D_WU 0xfff0007f +#define MATCH_FLD 0x3007 +#define MASK_FLD 0x707f +#define MATCH_FSD 0x3027 +#define MASK_FSD 0x707f +#define MATCH_FMADD_D 0x2000043 +#define MASK_FMADD_D 0x600007f +#define MATCH_FMSUB_D 0x2000047 +#define MASK_FMSUB_D 0x600007f +#define MATCH_FNMSUB_D 0x200004b +#define MASK_FNMSUB_D 0x600007f +#define MATCH_FNMADD_D 0x200004f +#define MASK_FNMADD_D 0x600007f +#define MATCH_FCVT_L_D 0xc2200053 +#define MASK_FCVT_L_D 0xfff0007f +#define MATCH_FCVT_LU_D 0xc2300053 +#define MASK_FCVT_LU_D 0xfff0007f +#define MATCH_FMV_X_D 0xe2000053 +#define MASK_FMV_X_D 0xfff0707f +#define MATCH_FCVT_D_L 0xd2200053 +#define MASK_FCVT_D_L 0xfff0007f +#define MATCH_FCVT_D_LU 0xd2300053 +#define MASK_FCVT_D_LU 0xfff0007f +#define MATCH_FMV_D_X 0xf2000053 +#define MASK_FMV_D_X 0xfff0707f +#define MATCH_FADD_Q 0x6000053 +#define MASK_FADD_Q 0xfe00007f +#define MATCH_FSUB_Q 0xe000053 +#define MASK_FSUB_Q 0xfe00007f +#define MATCH_FMUL_Q 0x16000053 +#define MASK_FMUL_Q 0xfe00007f +#define MATCH_FDIV_Q 0x1e000053 +#define MASK_FDIV_Q 0xfe00007f +#define MATCH_FSGNJ_Q 0x26000053 +#define MASK_FSGNJ_Q 0xfe00707f +#define MATCH_FSGNJN_Q 0x26001053 +#define MASK_FSGNJN_Q 0xfe00707f +#define MATCH_FSGNJX_Q 0x26002053 +#define MASK_FSGNJX_Q 0xfe00707f +#define MATCH_FMIN_Q 0x2e000053 +#define MASK_FMIN_Q 0xfe00707f +#define MATCH_FMAX_Q 0x2e001053 +#define MASK_FMAX_Q 0xfe00707f +#define MATCH_FCVT_S_Q 0x40300053 +#define MASK_FCVT_S_Q 0xfff0007f +#define MATCH_FCVT_Q_S 0x46000053 +#define MASK_FCVT_Q_S 0xfff0007f +#define MATCH_FCVT_D_Q 0x42300053 +#define MASK_FCVT_D_Q 0xfff0007f +#define MATCH_FCVT_Q_D 0x46100053 +#define MASK_FCVT_Q_D 0xfff0007f +#define MATCH_FSQRT_Q 0x5e000053 +#define MASK_FSQRT_Q 0xfff0007f +#define MATCH_FLE_Q 0xa6000053 +#define MASK_FLE_Q 0xfe00707f +#define MATCH_FLT_Q 0xa6001053 +#define MASK_FLT_Q 0xfe00707f +#define MATCH_FEQ_Q 0xa6002053 +#define MASK_FEQ_Q 0xfe00707f +#define MATCH_FCVT_W_Q 0xc6000053 +#define MASK_FCVT_W_Q 0xfff0007f +#define MATCH_FCVT_WU_Q 0xc6100053 +#define MASK_FCVT_WU_Q 0xfff0007f +#define MATCH_FCLASS_Q 0xe6001053 +#define MASK_FCLASS_Q 0xfff0707f +#define MATCH_FCVT_Q_W 0xd6000053 +#define MASK_FCVT_Q_W 0xfff0007f +#define MATCH_FCVT_Q_WU 0xd6100053 +#define MASK_FCVT_Q_WU 0xfff0007f +#define MATCH_FLQ 0x4007 +#define MASK_FLQ 0x707f +#define MATCH_FSQ 0x4027 +#define MASK_FSQ 0x707f +#define MATCH_FMADD_Q 0x6000043 +#define MASK_FMADD_Q 0x600007f +#define MATCH_FMSUB_Q 0x6000047 +#define MASK_FMSUB_Q 0x600007f +#define MATCH_FNMSUB_Q 0x600004b +#define MASK_FNMSUB_Q 0x600007f +#define MATCH_FNMADD_Q 0x600004f +#define MASK_FNMADD_Q 0x600007f +#define MATCH_FCVT_L_Q 0xc6200053 +#define MASK_FCVT_L_Q 0xfff0007f +#define MATCH_FCVT_LU_Q 0xc6300053 +#define MASK_FCVT_LU_Q 0xfff0007f +#define MATCH_FCVT_Q_L 0xd6200053 +#define MASK_FCVT_Q_L 0xfff0007f +#define MATCH_FCVT_Q_LU 0xd6300053 +#define MASK_FCVT_Q_LU 0xfff0007f +#define MATCH_ANDN 0x40007033 +#define MASK_ANDN 0xfe00707f +#define MATCH_ORN 0x40006033 +#define MASK_ORN 0xfe00707f +#define MATCH_XNOR 0x40004033 +#define MASK_XNOR 0xfe00707f +#define MATCH_SLO 0x20001033 +#define MASK_SLO 0xfe00707f +#define MATCH_SRO 0x20005033 +#define MASK_SRO 0xfe00707f +#define MATCH_ROL 0x60001033 +#define MASK_ROL 0xfe00707f +#define MATCH_ROR 0x60005033 +#define MASK_ROR 0xfe00707f +#define MATCH_BCLR 0x48001033 +#define MASK_BCLR 0xfe00707f +#define MATCH_BSET 0x28001033 +#define MASK_BSET 0xfe00707f +#define MATCH_BINV 0x68001033 +#define MASK_BINV 0xfe00707f +#define MATCH_BEXT 0x48005033 +#define MASK_BEXT 0xfe00707f +#define MATCH_GORC 0x28005033 +#define MASK_GORC 0xfe00707f +#define MATCH_GREV 0x68005033 +#define MASK_GREV 0xfe00707f +#define MATCH_SLOI 0x20001013 +#define MASK_SLOI 0xfc00707f +#define MATCH_SROI 0x20005013 +#define MASK_SROI 0xfc00707f +#define MATCH_RORI 0x60005013 +#define MASK_RORI 0xfc00707f +#define MATCH_BCLRI 0x48001013 +#define MASK_BCLRI 0xfc00707f +#define MATCH_BSETI 0x28001013 +#define MASK_BSETI 0xfc00707f +#define MATCH_BINVI 0x68001013 +#define MASK_BINVI 0xfc00707f +#define MATCH_BEXTI 0x48005013 +#define MASK_BEXTI 0xfc00707f +#define MATCH_GORCI 0x28005013 +#define MASK_GORCI 0xfc00707f +#define MATCH_GREVI 0x68005013 +#define MASK_GREVI 0xfc00707f +#define MATCH_CMIX 0x6001033 +#define MASK_CMIX 0x600707f +#define MATCH_CMOV 0x6005033 +#define MASK_CMOV 0x600707f +#define MATCH_FSL 0x4001033 +#define MASK_FSL 0x600707f +#define MATCH_FSR 0x4005033 +#define MASK_FSR 0x600707f +#define MATCH_FSRI 0x4005013 +#define MASK_FSRI 0x400707f +#define MATCH_CLZ 0x60001013 +#define MASK_CLZ 0xfff0707f +#define MATCH_CTZ 0x60101013 +#define MASK_CTZ 0xfff0707f +#define MATCH_CPOP 0x60201013 +#define MASK_CPOP 0xfff0707f +#define MATCH_SEXT_B 0x60401013 +#define MASK_SEXT_B 0xfff0707f +#define MATCH_SEXT_H 0x60501013 +#define MASK_SEXT_H 0xfff0707f +#define MATCH_CRC32_B 0x61001013 +#define MASK_CRC32_B 0xfff0707f +#define MATCH_CRC32_H 0x61101013 +#define MASK_CRC32_H 0xfff0707f +#define MATCH_CRC32_W 0x61201013 +#define MASK_CRC32_W 0xfff0707f +#define MATCH_CRC32C_B 0x61801013 +#define MASK_CRC32C_B 0xfff0707f +#define MATCH_CRC32C_H 0x61901013 +#define MASK_CRC32C_H 0xfff0707f +#define MATCH_CRC32C_W 0x61a01013 +#define MASK_CRC32C_W 0xfff0707f +#define MATCH_SH1ADD 0x20002033 +#define MASK_SH1ADD 0xfe00707f +#define MATCH_SH2ADD 0x20004033 +#define MASK_SH2ADD 0xfe00707f +#define MATCH_SH3ADD 0x20006033 +#define MASK_SH3ADD 0xfe00707f +#define MATCH_CLMUL 0xa001033 +#define MASK_CLMUL 0xfe00707f +#define MATCH_CLMULR 0xa002033 +#define MASK_CLMULR 0xfe00707f +#define MATCH_CLMULH 0xa003033 +#define MASK_CLMULH 0xfe00707f +#define MATCH_MIN 0xa004033 +#define MASK_MIN 0xfe00707f +#define MATCH_MINU 0xa005033 +#define MASK_MINU 0xfe00707f +#define MATCH_MAX 0xa006033 +#define MASK_MAX 0xfe00707f +#define MATCH_MAXU 0xa007033 +#define MASK_MAXU 0xfe00707f +#define MATCH_SHFL 0x8001033 +#define MASK_SHFL 0xfe00707f +#define MATCH_UNSHFL 0x8005033 +#define MASK_UNSHFL 0xfe00707f +#define MATCH_BCOMPRESS 0x8006033 +#define MASK_BCOMPRESS 0xfe00707f +#define MATCH_BDECOMPRESS 0x48006033 +#define MASK_BDECOMPRESS 0xfe00707f +#define MATCH_PACK 0x8004033 +#define MASK_PACK 0xfe00707f +#define MATCH_PACKU 0x48004033 +#define MASK_PACKU 0xfe00707f +#define MATCH_PACKH 0x8007033 +#define MASK_PACKH 0xfe00707f +#define MATCH_BFP 0x48007033 +#define MASK_BFP 0xfe00707f +#define MATCH_SHFLI 0x8001013 +#define MASK_SHFLI 0xfe00707f +#define MATCH_UNSHFLI 0x8005013 +#define MASK_UNSHFLI 0xfe00707f +#define MATCH_XPERM_N 0x28002033 +#define MASK_XPERM_N 0xfe00707f +#define MATCH_XPERM_B 0x28004033 +#define MASK_XPERM_B 0xfe00707f +#define MATCH_XPERM_H 0x28006033 +#define MASK_XPERM_H 0xfe00707f +#define MATCH_BMATFLIP 0x60301013 +#define MASK_BMATFLIP 0xfff0707f +#define MATCH_CRC32_D 0x61301013 +#define MASK_CRC32_D 0xfff0707f +#define MATCH_CRC32C_D 0x61b01013 +#define MASK_CRC32C_D 0xfff0707f +#define MATCH_BMATOR 0x8003033 +#define MASK_BMATOR 0xfe00707f +#define MATCH_BMATXOR 0x48003033 +#define MASK_BMATXOR 0xfe00707f +#define MATCH_SLLI_UW 0x800101b +#define MASK_SLLI_UW 0xfc00707f +#define MATCH_ADD_UW 0x800003b +#define MASK_ADD_UW 0xfe00707f +#define MATCH_SLOW 0x2000103b +#define MASK_SLOW 0xfe00707f +#define MATCH_SROW 0x2000503b +#define MASK_SROW 0xfe00707f +#define MATCH_ROLW 0x6000103b +#define MASK_ROLW 0xfe00707f +#define MATCH_RORW 0x6000503b +#define MASK_RORW 0xfe00707f +#define MATCH_SBCLRW 0x4800103b +#define MASK_SBCLRW 0xfe00707f +#define MATCH_SBSETW 0x2800103b +#define MASK_SBSETW 0xfe00707f +#define MATCH_SBINVW 0x6800103b +#define MASK_SBINVW 0xfe00707f +#define MATCH_SBEXTW 0x4800503b +#define MASK_SBEXTW 0xfe00707f +#define MATCH_GORCW 0x2800503b +#define MASK_GORCW 0xfe00707f +#define MATCH_GREVW 0x6800503b +#define MASK_GREVW 0xfe00707f +#define MATCH_SLOIW 0x2000101b +#define MASK_SLOIW 0xfe00707f +#define MATCH_SROIW 0x2000501b +#define MASK_SROIW 0xfe00707f +#define MATCH_RORIW 0x6000501b +#define MASK_RORIW 0xfe00707f +#define MATCH_SBCLRIW 0x4800101b +#define MASK_SBCLRIW 0xfe00707f +#define MATCH_SBSETIW 0x2800101b +#define MASK_SBSETIW 0xfe00707f +#define MATCH_SBINVIW 0x6800101b +#define MASK_SBINVIW 0xfe00707f +#define MATCH_GORCIW 0x2800501b +#define MASK_GORCIW 0xfe00707f +#define MATCH_GREVIW 0x6800501b +#define MASK_GREVIW 0xfe00707f +#define MATCH_FSLW 0x400103b +#define MASK_FSLW 0x600707f +#define MATCH_FSRW 0x400503b +#define MASK_FSRW 0x600707f +#define MATCH_FSRIW 0x400501b +#define MASK_FSRIW 0x600707f +#define MATCH_CLZW 0x6000101b +#define MASK_CLZW 0xfff0707f +#define MATCH_CTZW 0x6010101b +#define MASK_CTZW 0xfff0707f +#define MATCH_CPOPW 0x6020101b +#define MASK_CPOPW 0xfff0707f +#define MATCH_SH1ADD_UW 0x2000203b +#define MASK_SH1ADD_UW 0xfe00707f +#define MATCH_SH2ADD_UW 0x2000403b +#define MASK_SH2ADD_UW 0xfe00707f +#define MATCH_SH3ADD_UW 0x2000603b +#define MASK_SH3ADD_UW 0xfe00707f +#define MATCH_SHFLW 0x800103b +#define MASK_SHFLW 0xfe00707f +#define MATCH_UNSHFLW 0x800503b +#define MASK_UNSHFLW 0xfe00707f +#define MATCH_BCOMPRESSW 0x800603b +#define MASK_BCOMPRESSW 0xfe00707f +#define MATCH_BDECOMPRESSW 0x4800603b +#define MASK_BDECOMPRESSW 0xfe00707f +#define MATCH_PACKW 0x800403b +#define MASK_PACKW 0xfe00707f +#define MATCH_PACKUW 0x4800403b +#define MASK_PACKUW 0xfe00707f +#define MATCH_BFPW 0x4800703b +#define MASK_BFPW 0xfe00707f +#define MATCH_XPERM_W 0x28000033 +#define MASK_XPERM_W 0xfe00707f +#define MATCH_ECALL 0x73 +#define MASK_ECALL 0xffffffff +#define MATCH_EBREAK 0x100073 +#define MASK_EBREAK 0xffffffff +#define MATCH_URET 0x200073 +#define MASK_URET 0xffffffff +#define MATCH_SRET 0x10200073 +#define MASK_SRET 0xffffffff +#define MATCH_MRET 0x30200073 +#define MASK_MRET 0xffffffff +#define MATCH_DRET 0x7b200073 +#define MASK_DRET 0xffffffff +#define MATCH_SFENCE_VMA 0x12000073 +#define MASK_SFENCE_VMA 0xfe007fff +#define MATCH_WFI 0x10500073 +#define MASK_WFI 0xffffffff +#define MATCH_CSRRW 0x1073 +#define MASK_CSRRW 0x707f +#define MATCH_CSRRS 0x2073 +#define MASK_CSRRS 0x707f +#define MATCH_CSRRC 0x3073 +#define MASK_CSRRC 0x707f +#define MATCH_CSRRWI 0x5073 +#define MASK_CSRRWI 0x707f +#define MATCH_CSRRSI 0x6073 +#define MASK_CSRRSI 0x707f +#define MATCH_CSRRCI 0x7073 +#define MASK_CSRRCI 0x707f +#define MATCH_FADD_H 0x4000053 +#define MASK_FADD_H 0xfe00007f +#define MATCH_FSUB_H 0xc000053 +#define MASK_FSUB_H 0xfe00007f +#define MATCH_FMUL_H 0x14000053 +#define MASK_FMUL_H 0xfe00007f +#define MATCH_FDIV_H 0x1c000053 +#define MASK_FDIV_H 0xfe00007f +#define MATCH_FSGNJ_H 0x24000053 +#define MASK_FSGNJ_H 0xfe00707f +#define MATCH_FSGNJN_H 0x24001053 +#define MASK_FSGNJN_H 0xfe00707f +#define MATCH_FSGNJX_H 0x24002053 +#define MASK_FSGNJX_H 0xfe00707f +#define MATCH_FMIN_H 0x2c000053 +#define MASK_FMIN_H 0xfe00707f +#define MATCH_FMAX_H 0x2c001053 +#define MASK_FMAX_H 0xfe00707f +#define MATCH_FCVT_H_S 0x44000053 +#define MASK_FCVT_H_S 0xfff0007f +#define MATCH_FCVT_S_H 0x40200053 +#define MASK_FCVT_S_H 0xfff0007f +#define MATCH_FSQRT_H 0x5c000053 +#define MASK_FSQRT_H 0xfff0007f +#define MATCH_FLE_H 0xa4000053 +#define MASK_FLE_H 0xfe00707f +#define MATCH_FLT_H 0xa4001053 +#define MASK_FLT_H 0xfe00707f +#define MATCH_FEQ_H 0xa4002053 +#define MASK_FEQ_H 0xfe00707f +#define MATCH_FCVT_W_H 0xc4000053 +#define MASK_FCVT_W_H 0xfff0007f +#define MATCH_FCVT_WU_H 0xc4100053 +#define MASK_FCVT_WU_H 0xfff0007f +#define MATCH_FMV_X_H 0xe4000053 +#define MASK_FMV_X_H 0xfff0707f +#define MATCH_FCLASS_H 0xe4001053 +#define MASK_FCLASS_H 0xfff0707f +#define MATCH_FCVT_H_W 0xd4000053 +#define MASK_FCVT_H_W 0xfff0007f +#define MATCH_FCVT_H_WU 0xd4100053 +#define MASK_FCVT_H_WU 0xfff0007f +#define MATCH_FMV_H_X 0xf4000053 +#define MASK_FMV_H_X 0xfff0707f +#define MATCH_FLH 0x1007 +#define MASK_FLH 0x707f +#define MATCH_FSH 0x1027 +#define MASK_FSH 0x707f +#define MATCH_FMADD_H 0x4000043 +#define MASK_FMADD_H 0x600007f +#define MATCH_FMSUB_H 0x4000047 +#define MASK_FMSUB_H 0x600007f +#define MATCH_FNMSUB_H 0x400004b +#define MASK_FNMSUB_H 0x600007f +#define MATCH_FNMADD_H 0x400004f +#define MASK_FNMADD_H 0x600007f +#define MATCH_FCVT_H_D 0x44100053 +#define MASK_FCVT_H_D 0xfff0007f +#define MATCH_FCVT_D_H 0x42200053 +#define MASK_FCVT_D_H 0xfff0007f +#define MATCH_FCVT_H_Q 0x44300053 +#define MASK_FCVT_H_Q 0xfff0007f +#define MATCH_FCVT_Q_H 0x46200053 +#define MASK_FCVT_Q_H 0xfff0007f +#define MATCH_FCVT_L_H 0xc4200053 +#define MASK_FCVT_L_H 0xfff0007f +#define MATCH_FCVT_LU_H 0xc4300053 +#define MASK_FCVT_LU_H 0xfff0007f +#define MATCH_FCVT_H_L 0xd4200053 +#define MASK_FCVT_H_L 0xfff0007f +#define MATCH_FCVT_H_LU 0xd4300053 +#define MASK_FCVT_H_LU 0xfff0007f +#define MATCH_POLLENTROPY 0xf1500073 +#define MASK_POLLENTROPY 0xfffff07f +#define MATCH_GETNOISE 0x7a900073 +#define MASK_GETNOISE 0xfffff07f +#define MATCH_SM4ED 0x30000033 +#define MASK_SM4ED 0x3e007fff +#define MATCH_SM4KS 0x34000033 +#define MASK_SM4KS 0x3e007fff +#define MATCH_SM3P0 0x10801013 +#define MASK_SM3P0 0xfff0707f +#define MATCH_SM3P1 0x10901013 +#define MASK_SM3P1 0xfff0707f +#define MATCH_SHA256SUM0 0x10001013 +#define MASK_SHA256SUM0 0xfff0707f +#define MATCH_SHA256SUM1 0x10101013 +#define MASK_SHA256SUM1 0xfff0707f +#define MATCH_SHA256SIG0 0x10201013 +#define MASK_SHA256SIG0 0xfff0707f +#define MATCH_SHA256SIG1 0x10301013 +#define MASK_SHA256SIG1 0xfff0707f +#define MATCH_AES32ESMI 0x36000033 +#define MASK_AES32ESMI 0x3e007fff +#define MATCH_AES32ESI 0x32000033 +#define MASK_AES32ESI 0x3e007fff +#define MATCH_AES32DSMI 0x3e000033 +#define MASK_AES32DSMI 0x3e007fff +#define MATCH_AES32DSI 0x3a000033 +#define MASK_AES32DSI 0x3e007fff +#define MATCH_SHA512SUM0R 0x50000033 +#define MASK_SHA512SUM0R 0xfe00707f +#define MATCH_SHA512SUM1R 0x52000033 +#define MASK_SHA512SUM1R 0xfe00707f +#define MATCH_SHA512SIG0L 0x54000033 +#define MASK_SHA512SIG0L 0xfe00707f +#define MATCH_SHA512SIG0H 0x5c000033 +#define MASK_SHA512SIG0H 0xfe00707f +#define MATCH_SHA512SIG1L 0x56000033 +#define MASK_SHA512SIG1L 0xfe00707f +#define MATCH_SHA512SIG1H 0x5e000033 +#define MASK_SHA512SIG1H 0xfe00707f +#define MATCH_AES64KS1I 0x31001013 +#define MASK_AES64KS1I 0xff00707f +#define MATCH_AES64IM 0x30001013 +#define MASK_AES64IM 0xfff0707f +#define MATCH_AES64KS2 0x7e000033 +#define MASK_AES64KS2 0xfe00707f +#define MATCH_AES64ESM 0x36000033 +#define MASK_AES64ESM 0xfe00707f +#define MATCH_AES64ES 0x32000033 +#define MASK_AES64ES 0xfe00707f +#define MATCH_AES64DSM 0x3e000033 +#define MASK_AES64DSM 0xfe00707f +#define MATCH_AES64DS 0x3a000033 +#define MASK_AES64DS 0xfe00707f +#define MATCH_SHA512SUM0 0x10401013 +#define MASK_SHA512SUM0 0xfff0707f +#define MATCH_SHA512SUM1 0x10501013 +#define MASK_SHA512SUM1 0xfff0707f +#define MATCH_SHA512SIG0 0x10601013 +#define MASK_SHA512SIG0 0xfff0707f +#define MATCH_SHA512SIG1 0x10701013 +#define MASK_SHA512SIG1 0xfff0707f +#define MATCH_C_NOP 0x1 +#define MASK_C_NOP 0xffff +#define MATCH_C_ADDI16SP 0x6101 +#define MASK_C_ADDI16SP 0xef83 +#define MATCH_C_JR 0x8002 +#define MASK_C_JR 0xf07f +#define MATCH_C_JALR 0x9002 +#define MASK_C_JALR 0xf07f +#define MATCH_C_EBREAK 0x9002 +#define MASK_C_EBREAK 0xffff +#define MATCH_C_ADDI4SPN 0x0 +#define MASK_C_ADDI4SPN 0xe003 +#define MATCH_C_FLD 0x2000 +#define MASK_C_FLD 0xe003 +#define MATCH_C_LW 0x4000 +#define MASK_C_LW 0xe003 +#define MATCH_C_FLW 0x6000 +#define MASK_C_FLW 0xe003 +#define MATCH_C_FSD 0xa000 +#define MASK_C_FSD 0xe003 +#define MATCH_C_SW 0xc000 +#define MASK_C_SW 0xe003 +#define MATCH_C_FSW 0xe000 +#define MASK_C_FSW 0xe003 +#define MATCH_C_ADDI 0x1 +#define MASK_C_ADDI 0xe003 +#define MATCH_C_JAL 0x2001 +#define MASK_C_JAL 0xe003 +#define MATCH_C_LI 0x4001 +#define MASK_C_LI 0xe003 +#define MATCH_C_LUI 0x6001 +#define MASK_C_LUI 0xe003 +#define MATCH_C_SRLI 0x8001 +#define MASK_C_SRLI 0xec03 +#define MATCH_C_SRAI 0x8401 +#define MASK_C_SRAI 0xec03 +#define MATCH_C_ANDI 0x8801 +#define MASK_C_ANDI 0xec03 +#define MATCH_C_SUB 0x8c01 +#define MASK_C_SUB 0xfc63 +#define MATCH_C_XOR 0x8c21 +#define MASK_C_XOR 0xfc63 +#define MATCH_C_OR 0x8c41 +#define MASK_C_OR 0xfc63 +#define MATCH_C_AND 0x8c61 +#define MASK_C_AND 0xfc63 +#define MATCH_C_J 0xa001 +#define MASK_C_J 0xe003 +#define MATCH_C_BEQZ 0xc001 +#define MASK_C_BEQZ 0xe003 +#define MATCH_C_BNEZ 0xe001 +#define MASK_C_BNEZ 0xe003 +#define MATCH_C_SLLI 0x2 +#define MASK_C_SLLI 0xe003 +#define MATCH_C_FLDSP 0x2002 +#define MASK_C_FLDSP 0xe003 +#define MATCH_C_LWSP 0x4002 +#define MASK_C_LWSP 0xe003 +#define MATCH_C_FLWSP 0x6002 +#define MASK_C_FLWSP 0xe003 +#define MATCH_C_MV 0x8002 +#define MASK_C_MV 0xf003 +#define MATCH_C_ADD 0x9002 +#define MASK_C_ADD 0xf003 +#define MATCH_C_FSDSP 0xa002 +#define MASK_C_FSDSP 0xe003 +#define MATCH_C_SWSP 0xc002 +#define MASK_C_SWSP 0xe003 +#define MATCH_C_FSWSP 0xe002 +#define MASK_C_FSWSP 0xe003 +#define MATCH_C_SRLI_RV32 0x8001 +#define MASK_C_SRLI_RV32 0xfc03 +#define MATCH_C_SRAI_RV32 0x8401 +#define MASK_C_SRAI_RV32 0xfc03 +#define MATCH_C_SLLI_RV32 0x2 +#define MASK_C_SLLI_RV32 0xf003 +#define MATCH_C_LD 0x6000 +#define MASK_C_LD 0xe003 +#define MATCH_C_SD 0xe000 +#define MASK_C_SD 0xe003 +#define MATCH_C_SUBW 0x9c01 +#define MASK_C_SUBW 0xfc63 +#define MATCH_C_ADDW 0x9c21 +#define MASK_C_ADDW 0xfc63 +#define MATCH_C_ADDIW 0x2001 +#define MASK_C_ADDIW 0xe003 +#define MATCH_C_LDSP 0x6002 +#define MASK_C_LDSP 0xe003 +#define MATCH_C_SDSP 0xe002 +#define MASK_C_SDSP 0xe003 +#define MATCH_CUSTOM0 0xb +#define MASK_CUSTOM0 0x707f +#define MATCH_CUSTOM0_RS1 0x200b +#define MASK_CUSTOM0_RS1 0x707f +#define MATCH_CUSTOM0_RS1_RS2 0x300b +#define MASK_CUSTOM0_RS1_RS2 0x707f +#define MATCH_CUSTOM0_RD 0x400b +#define MASK_CUSTOM0_RD 0x707f +#define MATCH_CUSTOM0_RD_RS1 0x600b +#define MASK_CUSTOM0_RD_RS1 0x707f +#define MATCH_CUSTOM0_RD_RS1_RS2 0x700b +#define MASK_CUSTOM0_RD_RS1_RS2 0x707f +#define MATCH_CUSTOM1 0x2b +#define MASK_CUSTOM1 0x707f +#define MATCH_CUSTOM1_RS1 0x202b +#define MASK_CUSTOM1_RS1 0x707f +#define MATCH_CUSTOM1_RS1_RS2 0x302b +#define MASK_CUSTOM1_RS1_RS2 0x707f +#define MATCH_CUSTOM1_RD 0x402b +#define MASK_CUSTOM1_RD 0x707f +#define MATCH_CUSTOM1_RD_RS1 0x602b +#define MASK_CUSTOM1_RD_RS1 0x707f +#define MATCH_CUSTOM1_RD_RS1_RS2 0x702b +#define MASK_CUSTOM1_RD_RS1_RS2 0x707f +#define MATCH_CUSTOM2 0x5b +#define MASK_CUSTOM2 0x707f +#define MATCH_CUSTOM2_RS1 0x205b +#define MASK_CUSTOM2_RS1 0x707f +#define MATCH_CUSTOM2_RS1_RS2 0x305b +#define MASK_CUSTOM2_RS1_RS2 0x707f +#define MATCH_CUSTOM2_RD 0x405b +#define MASK_CUSTOM2_RD 0x707f +#define MATCH_CUSTOM2_RD_RS1 0x605b +#define MASK_CUSTOM2_RD_RS1 0x707f +#define MATCH_CUSTOM2_RD_RS1_RS2 0x705b +#define MASK_CUSTOM2_RD_RS1_RS2 0x707f +#define MATCH_CUSTOM3 0x7b +#define MASK_CUSTOM3 0x707f +#define MATCH_CUSTOM3_RS1 0x207b +#define MASK_CUSTOM3_RS1 0x707f +#define MATCH_CUSTOM3_RS1_RS2 0x307b +#define MASK_CUSTOM3_RS1_RS2 0x707f +#define MATCH_CUSTOM3_RD 0x407b +#define MASK_CUSTOM3_RD 0x707f +#define MATCH_CUSTOM3_RD_RS1 0x607b +#define MASK_CUSTOM3_RD_RS1 0x707f +#define MATCH_CUSTOM3_RD_RS1_RS2 0x707b +#define MASK_CUSTOM3_RD_RS1_RS2 0x707f +#define MATCH_VSETIVLI 0xc0007057 +#define MASK_VSETIVLI 0xc000707f +#define MATCH_VSETVLI 0x7057 +#define MASK_VSETVLI 0x8000707f +#define MATCH_VSETVL 0x80007057 +#define MASK_VSETVL 0xfe00707f +#define MATCH_VLE1_V 0x2b00007 +#define MASK_VLE1_V 0xfff0707f +#define MATCH_VSE1_V 0x2b00027 +#define MASK_VSE1_V 0xfff0707f +#define MATCH_VLE8_V 0x7 +#define MASK_VLE8_V 0x1df0707f +#define MATCH_VLE16_V 0x5007 +#define MASK_VLE16_V 0x1df0707f +#define MATCH_VLE32_V 0x6007 +#define MASK_VLE32_V 0x1df0707f +#define MATCH_VLE64_V 0x7007 +#define MASK_VLE64_V 0x1df0707f +#define MATCH_VLE128_V 0x10000007 +#define MASK_VLE128_V 0x1df0707f +#define MATCH_VLE256_V 0x10005007 +#define MASK_VLE256_V 0x1df0707f +#define MATCH_VLE512_V 0x10006007 +#define MASK_VLE512_V 0x1df0707f +#define MATCH_VLE1024_V 0x10007007 +#define MASK_VLE1024_V 0x1df0707f +#define MATCH_VSE8_V 0x27 +#define MASK_VSE8_V 0x1df0707f +#define MATCH_VSE16_V 0x5027 +#define MASK_VSE16_V 0x1df0707f +#define MATCH_VSE32_V 0x6027 +#define MASK_VSE32_V 0x1df0707f +#define MATCH_VSE64_V 0x7027 +#define MASK_VSE64_V 0x1df0707f +#define MATCH_VSE128_V 0x10000027 +#define MASK_VSE128_V 0x1df0707f +#define MATCH_VSE256_V 0x10005027 +#define MASK_VSE256_V 0x1df0707f +#define MATCH_VSE512_V 0x10006027 +#define MASK_VSE512_V 0x1df0707f +#define MATCH_VSE1024_V 0x10007027 +#define MASK_VSE1024_V 0x1df0707f +#define MATCH_VLUXEI8_V 0x4000007 +#define MASK_VLUXEI8_V 0x1c00707f +#define MATCH_VLUXEI16_V 0x4005007 +#define MASK_VLUXEI16_V 0x1c00707f +#define MATCH_VLUXEI32_V 0x4006007 +#define MASK_VLUXEI32_V 0x1c00707f +#define MATCH_VLUXEI64_V 0x4007007 +#define MASK_VLUXEI64_V 0x1c00707f +#define MATCH_VLUXEI128_V 0x14000007 +#define MASK_VLUXEI128_V 0x1c00707f +#define MATCH_VLUXEI256_V 0x14005007 +#define MASK_VLUXEI256_V 0x1c00707f +#define MATCH_VLUXEI512_V 0x14006007 +#define MASK_VLUXEI512_V 0x1c00707f +#define MATCH_VLUXEI1024_V 0x14007007 +#define MASK_VLUXEI1024_V 0x1c00707f +#define MATCH_VSUXEI8_V 0x4000027 +#define MASK_VSUXEI8_V 0x1c00707f +#define MATCH_VSUXEI16_V 0x4005027 +#define MASK_VSUXEI16_V 0x1c00707f +#define MATCH_VSUXEI32_V 0x4006027 +#define MASK_VSUXEI32_V 0x1c00707f +#define MATCH_VSUXEI64_V 0x4007027 +#define MASK_VSUXEI64_V 0x1c00707f +#define MATCH_VSUXEI128_V 0x14000027 +#define MASK_VSUXEI128_V 0x1c00707f +#define MATCH_VSUXEI256_V 0x14005027 +#define MASK_VSUXEI256_V 0x1c00707f +#define MATCH_VSUXEI512_V 0x14006027 +#define MASK_VSUXEI512_V 0x1c00707f +#define MATCH_VSUXEI1024_V 0x14007027 +#define MASK_VSUXEI1024_V 0x1c00707f +#define MATCH_VLSE8_V 0x8000007 +#define MASK_VLSE8_V 0x1c00707f +#define MATCH_VLSE16_V 0x8005007 +#define MASK_VLSE16_V 0x1c00707f +#define MATCH_VLSE32_V 0x8006007 +#define MASK_VLSE32_V 0x1c00707f +#define MATCH_VLSE64_V 0x8007007 +#define MASK_VLSE64_V 0x1c00707f +#define MATCH_VLSE128_V 0x18000007 +#define MASK_VLSE128_V 0x1c00707f +#define MATCH_VLSE256_V 0x18005007 +#define MASK_VLSE256_V 0x1c00707f +#define MATCH_VLSE512_V 0x18006007 +#define MASK_VLSE512_V 0x1c00707f +#define MATCH_VLSE1024_V 0x18007007 +#define MASK_VLSE1024_V 0x1c00707f +#define MATCH_VSSE8_V 0x8000027 +#define MASK_VSSE8_V 0x1c00707f +#define MATCH_VSSE16_V 0x8005027 +#define MASK_VSSE16_V 0x1c00707f +#define MATCH_VSSE32_V 0x8006027 +#define MASK_VSSE32_V 0x1c00707f +#define MATCH_VSSE64_V 0x8007027 +#define MASK_VSSE64_V 0x1c00707f +#define MATCH_VSSE128_V 0x18000027 +#define MASK_VSSE128_V 0x1c00707f +#define MATCH_VSSE256_V 0x18005027 +#define MASK_VSSE256_V 0x1c00707f +#define MATCH_VSSE512_V 0x18006027 +#define MASK_VSSE512_V 0x1c00707f +#define MATCH_VSSE1024_V 0x18007027 +#define MASK_VSSE1024_V 0x1c00707f +#define MATCH_VLOXEI8_V 0xc000007 +#define MASK_VLOXEI8_V 0x1c00707f +#define MATCH_VLOXEI16_V 0xc005007 +#define MASK_VLOXEI16_V 0x1c00707f +#define MATCH_VLOXEI32_V 0xc006007 +#define MASK_VLOXEI32_V 0x1c00707f +#define MATCH_VLOXEI64_V 0xc007007 +#define MASK_VLOXEI64_V 0x1c00707f +#define MATCH_VLOXEI128_V 0x1c000007 +#define MASK_VLOXEI128_V 0x1c00707f +#define MATCH_VLOXEI256_V 0x1c005007 +#define MASK_VLOXEI256_V 0x1c00707f +#define MATCH_VLOXEI512_V 0x1c006007 +#define MASK_VLOXEI512_V 0x1c00707f +#define MATCH_VLOXEI1024_V 0x1c007007 +#define MASK_VLOXEI1024_V 0x1c00707f +#define MATCH_VSOXEI8_V 0xc000027 +#define MASK_VSOXEI8_V 0x1c00707f +#define MATCH_VSOXEI16_V 0xc005027 +#define MASK_VSOXEI16_V 0x1c00707f +#define MATCH_VSOXEI32_V 0xc006027 +#define MASK_VSOXEI32_V 0x1c00707f +#define MATCH_VSOXEI64_V 0xc007027 +#define MASK_VSOXEI64_V 0x1c00707f +#define MATCH_VSOXEI128_V 0x1c000027 +#define MASK_VSOXEI128_V 0x1c00707f +#define MATCH_VSOXEI256_V 0x1c005027 +#define MASK_VSOXEI256_V 0x1c00707f +#define MATCH_VSOXEI512_V 0x1c006027 +#define MASK_VSOXEI512_V 0x1c00707f +#define MATCH_VSOXEI1024_V 0x1c007027 +#define MASK_VSOXEI1024_V 0x1c00707f +#define MATCH_VLE8FF_V 0x1000007 +#define MASK_VLE8FF_V 0x1df0707f +#define MATCH_VLE16FF_V 0x1005007 +#define MASK_VLE16FF_V 0x1df0707f +#define MATCH_VLE32FF_V 0x1006007 +#define MASK_VLE32FF_V 0x1df0707f +#define MATCH_VLE64FF_V 0x1007007 +#define MASK_VLE64FF_V 0x1df0707f +#define MATCH_VLE128FF_V 0x11000007 +#define MASK_VLE128FF_V 0x1df0707f +#define MATCH_VLE256FF_V 0x11005007 +#define MASK_VLE256FF_V 0x1df0707f +#define MATCH_VLE512FF_V 0x11006007 +#define MASK_VLE512FF_V 0x1df0707f +#define MATCH_VLE1024FF_V 0x11007007 +#define MASK_VLE1024FF_V 0x1df0707f +#define MATCH_VL1RE8_V 0x2800007 +#define MASK_VL1RE8_V 0xfff0707f +#define MATCH_VL1RE16_V 0x2805007 +#define MASK_VL1RE16_V 0xfff0707f +#define MATCH_VL1RE32_V 0x2806007 +#define MASK_VL1RE32_V 0xfff0707f +#define MATCH_VL1RE64_V 0x2807007 +#define MASK_VL1RE64_V 0xfff0707f +#define MATCH_VL2RE8_V 0x22800007 +#define MASK_VL2RE8_V 0xfff0707f +#define MATCH_VL2RE16_V 0x22805007 +#define MASK_VL2RE16_V 0xfff0707f +#define MATCH_VL2RE32_V 0x22806007 +#define MASK_VL2RE32_V 0xfff0707f +#define MATCH_VL2RE64_V 0x22807007 +#define MASK_VL2RE64_V 0xfff0707f +#define MATCH_VL4RE8_V 0x62800007 +#define MASK_VL4RE8_V 0xfff0707f +#define MATCH_VL4RE16_V 0x62805007 +#define MASK_VL4RE16_V 0xfff0707f +#define MATCH_VL4RE32_V 0x62806007 +#define MASK_VL4RE32_V 0xfff0707f +#define MATCH_VL4RE64_V 0x62807007 +#define MASK_VL4RE64_V 0xfff0707f +#define MATCH_VL8RE8_V 0xe2800007 +#define MASK_VL8RE8_V 0xfff0707f +#define MATCH_VL8RE16_V 0xe2805007 +#define MASK_VL8RE16_V 0xfff0707f +#define MATCH_VL8RE32_V 0xe2806007 +#define MASK_VL8RE32_V 0xfff0707f +#define MATCH_VL8RE64_V 0xe2807007 +#define MASK_VL8RE64_V 0xfff0707f +#define MATCH_VS1R_V 0x2800027 +#define MASK_VS1R_V 0xfff0707f +#define MATCH_VS2R_V 0x22800027 +#define MASK_VS2R_V 0xfff0707f +#define MATCH_VS4R_V 0x62800027 +#define MASK_VS4R_V 0xfff0707f +#define MATCH_VS8R_V 0xe2800027 +#define MASK_VS8R_V 0xfff0707f +#define MATCH_VFADD_VF 0x5057 +#define MASK_VFADD_VF 0xfc00707f +#define MATCH_VFSUB_VF 0x8005057 +#define MASK_VFSUB_VF 0xfc00707f +#define MATCH_VFMIN_VF 0x10005057 +#define MASK_VFMIN_VF 0xfc00707f +#define MATCH_VFMAX_VF 0x18005057 +#define MASK_VFMAX_VF 0xfc00707f +#define MATCH_VFSGNJ_VF 0x20005057 +#define MASK_VFSGNJ_VF 0xfc00707f +#define MATCH_VFSGNJN_VF 0x24005057 +#define MASK_VFSGNJN_VF 0xfc00707f +#define MATCH_VFSGNJX_VF 0x28005057 +#define MASK_VFSGNJX_VF 0xfc00707f +#define MATCH_VFSLIDE1UP_VF 0x38005057 +#define MASK_VFSLIDE1UP_VF 0xfc00707f +#define MATCH_VFSLIDE1DOWN_VF 0x3c005057 +#define MASK_VFSLIDE1DOWN_VF 0xfc00707f +#define MATCH_VFMV_S_F 0x42005057 +#define MASK_VFMV_S_F 0xfff0707f +#define MATCH_VFMERGE_VFM 0x5c005057 +#define MASK_VFMERGE_VFM 0xfe00707f +#define MATCH_VFMV_V_F 0x5e005057 +#define MASK_VFMV_V_F 0xfff0707f +#define MATCH_VMFEQ_VF 0x60005057 +#define MASK_VMFEQ_VF 0xfc00707f +#define MATCH_VMFLE_VF 0x64005057 +#define MASK_VMFLE_VF 0xfc00707f +#define MATCH_VMFLT_VF 0x6c005057 +#define MASK_VMFLT_VF 0xfc00707f +#define MATCH_VMFNE_VF 0x70005057 +#define MASK_VMFNE_VF 0xfc00707f +#define MATCH_VMFGT_VF 0x74005057 +#define MASK_VMFGT_VF 0xfc00707f +#define MATCH_VMFGE_VF 0x7c005057 +#define MASK_VMFGE_VF 0xfc00707f +#define MATCH_VFDIV_VF 0x80005057 +#define MASK_VFDIV_VF 0xfc00707f +#define MATCH_VFRDIV_VF 0x84005057 +#define MASK_VFRDIV_VF 0xfc00707f +#define MATCH_VFMUL_VF 0x90005057 +#define MASK_VFMUL_VF 0xfc00707f +#define MATCH_VFRSUB_VF 0x9c005057 +#define MASK_VFRSUB_VF 0xfc00707f +#define MATCH_VFMADD_VF 0xa0005057 +#define MASK_VFMADD_VF 0xfc00707f +#define MATCH_VFNMADD_VF 0xa4005057 +#define MASK_VFNMADD_VF 0xfc00707f +#define MATCH_VFMSUB_VF 0xa8005057 +#define MASK_VFMSUB_VF 0xfc00707f +#define MATCH_VFNMSUB_VF 0xac005057 +#define MASK_VFNMSUB_VF 0xfc00707f +#define MATCH_VFMACC_VF 0xb0005057 +#define MASK_VFMACC_VF 0xfc00707f +#define MATCH_VFNMACC_VF 0xb4005057 +#define MASK_VFNMACC_VF 0xfc00707f +#define MATCH_VFMSAC_VF 0xb8005057 +#define MASK_VFMSAC_VF 0xfc00707f +#define MATCH_VFNMSAC_VF 0xbc005057 +#define MASK_VFNMSAC_VF 0xfc00707f +#define MATCH_VFWADD_VF 0xc0005057 +#define MASK_VFWADD_VF 0xfc00707f +#define MATCH_VFWSUB_VF 0xc8005057 +#define MASK_VFWSUB_VF 0xfc00707f +#define MATCH_VFWADD_WF 0xd0005057 +#define MASK_VFWADD_WF 0xfc00707f +#define MATCH_VFWSUB_WF 0xd8005057 +#define MASK_VFWSUB_WF 0xfc00707f +#define MATCH_VFWMUL_VF 0xe0005057 +#define MASK_VFWMUL_VF 0xfc00707f +#define MATCH_VFWMACC_VF 0xf0005057 +#define MASK_VFWMACC_VF 0xfc00707f +#define MATCH_VFWNMACC_VF 0xf4005057 +#define MASK_VFWNMACC_VF 0xfc00707f +#define MATCH_VFWMSAC_VF 0xf8005057 +#define MASK_VFWMSAC_VF 0xfc00707f +#define MATCH_VFWNMSAC_VF 0xfc005057 +#define MASK_VFWNMSAC_VF 0xfc00707f +#define MATCH_VFADD_VV 0x1057 +#define MASK_VFADD_VV 0xfc00707f +#define MATCH_VFREDSUM_VS 0x4001057 +#define MASK_VFREDSUM_VS 0xfc00707f +#define MATCH_VFSUB_VV 0x8001057 +#define MASK_VFSUB_VV 0xfc00707f +#define MATCH_VFREDOSUM_VS 0xc001057 +#define MASK_VFREDOSUM_VS 0xfc00707f +#define MATCH_VFMIN_VV 0x10001057 +#define MASK_VFMIN_VV 0xfc00707f +#define MATCH_VFREDMIN_VS 0x14001057 +#define MASK_VFREDMIN_VS 0xfc00707f +#define MATCH_VFMAX_VV 0x18001057 +#define MASK_VFMAX_VV 0xfc00707f +#define MATCH_VFREDMAX_VS 0x1c001057 +#define MASK_VFREDMAX_VS 0xfc00707f +#define MATCH_VFSGNJ_VV 0x20001057 +#define MASK_VFSGNJ_VV 0xfc00707f +#define MATCH_VFSGNJN_VV 0x24001057 +#define MASK_VFSGNJN_VV 0xfc00707f +#define MATCH_VFSGNJX_VV 0x28001057 +#define MASK_VFSGNJX_VV 0xfc00707f +#define MATCH_VFMV_F_S 0x42001057 +#define MASK_VFMV_F_S 0xfe0ff07f +#define MATCH_VMFEQ_VV 0x60001057 +#define MASK_VMFEQ_VV 0xfc00707f +#define MATCH_VMFLE_VV 0x64001057 +#define MASK_VMFLE_VV 0xfc00707f +#define MATCH_VMFLT_VV 0x6c001057 +#define MASK_VMFLT_VV 0xfc00707f +#define MATCH_VMFNE_VV 0x70001057 +#define MASK_VMFNE_VV 0xfc00707f +#define MATCH_VFDIV_VV 0x80001057 +#define MASK_VFDIV_VV 0xfc00707f +#define MATCH_VFMUL_VV 0x90001057 +#define MASK_VFMUL_VV 0xfc00707f +#define MATCH_VFMADD_VV 0xa0001057 +#define MASK_VFMADD_VV 0xfc00707f +#define MATCH_VFNMADD_VV 0xa4001057 +#define MASK_VFNMADD_VV 0xfc00707f +#define MATCH_VFMSUB_VV 0xa8001057 +#define MASK_VFMSUB_VV 0xfc00707f +#define MATCH_VFNMSUB_VV 0xac001057 +#define MASK_VFNMSUB_VV 0xfc00707f +#define MATCH_VFMACC_VV 0xb0001057 +#define MASK_VFMACC_VV 0xfc00707f +#define MATCH_VFNMACC_VV 0xb4001057 +#define MASK_VFNMACC_VV 0xfc00707f +#define MATCH_VFMSAC_VV 0xb8001057 +#define MASK_VFMSAC_VV 0xfc00707f +#define MATCH_VFNMSAC_VV 0xbc001057 +#define MASK_VFNMSAC_VV 0xfc00707f +#define MATCH_VFCVT_XU_F_V 0x48001057 +#define MASK_VFCVT_XU_F_V 0xfc0ff07f +#define MATCH_VFCVT_X_F_V 0x48009057 +#define MASK_VFCVT_X_F_V 0xfc0ff07f +#define MATCH_VFCVT_F_XU_V 0x48011057 +#define MASK_VFCVT_F_XU_V 0xfc0ff07f +#define MATCH_VFCVT_F_X_V 0x48019057 +#define MASK_VFCVT_F_X_V 0xfc0ff07f +#define MATCH_VFCVT_RTZ_XU_F_V 0x48031057 +#define MASK_VFCVT_RTZ_XU_F_V 0xfc0ff07f +#define MATCH_VFCVT_RTZ_X_F_V 0x48039057 +#define MASK_VFCVT_RTZ_X_F_V 0xfc0ff07f +#define MATCH_VFWCVT_XU_F_V 0x48041057 +#define MASK_VFWCVT_XU_F_V 0xfc0ff07f +#define MATCH_VFWCVT_X_F_V 0x48049057 +#define MASK_VFWCVT_X_F_V 0xfc0ff07f +#define MATCH_VFWCVT_F_XU_V 0x48051057 +#define MASK_VFWCVT_F_XU_V 0xfc0ff07f +#define MATCH_VFWCVT_F_X_V 0x48059057 +#define MASK_VFWCVT_F_X_V 0xfc0ff07f +#define MATCH_VFWCVT_F_F_V 0x48061057 +#define MASK_VFWCVT_F_F_V 0xfc0ff07f +#define MATCH_VFWCVT_RTZ_XU_F_V 0x48071057 +#define MASK_VFWCVT_RTZ_XU_F_V 0xfc0ff07f +#define MATCH_VFWCVT_RTZ_X_F_V 0x48079057 +#define MASK_VFWCVT_RTZ_X_F_V 0xfc0ff07f +#define MATCH_VFNCVT_XU_F_W 0x48081057 +#define MASK_VFNCVT_XU_F_W 0xfc0ff07f +#define MATCH_VFNCVT_X_F_W 0x48089057 +#define MASK_VFNCVT_X_F_W 0xfc0ff07f +#define MATCH_VFNCVT_F_XU_W 0x48091057 +#define MASK_VFNCVT_F_XU_W 0xfc0ff07f +#define MATCH_VFNCVT_F_X_W 0x48099057 +#define MASK_VFNCVT_F_X_W 0xfc0ff07f +#define MATCH_VFNCVT_F_F_W 0x480a1057 +#define MASK_VFNCVT_F_F_W 0xfc0ff07f +#define MATCH_VFNCVT_ROD_F_F_W 0x480a9057 +#define MASK_VFNCVT_ROD_F_F_W 0xfc0ff07f +#define MATCH_VFNCVT_RTZ_XU_F_W 0x480b1057 +#define MASK_VFNCVT_RTZ_XU_F_W 0xfc0ff07f +#define MATCH_VFNCVT_RTZ_X_F_W 0x480b9057 +#define MASK_VFNCVT_RTZ_X_F_W 0xfc0ff07f +#define MATCH_VFSQRT_V 0x4c001057 +#define MASK_VFSQRT_V 0xfc0ff07f +#define MATCH_VFRSQRT7_V 0x4c021057 +#define MASK_VFRSQRT7_V 0xfc0ff07f +#define MATCH_VFREC7_V 0x4c029057 +#define MASK_VFREC7_V 0xfc0ff07f +#define MATCH_VFCLASS_V 0x4c081057 +#define MASK_VFCLASS_V 0xfc0ff07f +#define MATCH_VFWADD_VV 0xc0001057 +#define MASK_VFWADD_VV 0xfc00707f +#define MATCH_VFWREDSUM_VS 0xc4001057 +#define MASK_VFWREDSUM_VS 0xfc00707f +#define MATCH_VFWSUB_VV 0xc8001057 +#define MASK_VFWSUB_VV 0xfc00707f +#define MATCH_VFWREDOSUM_VS 0xcc001057 +#define MASK_VFWREDOSUM_VS 0xfc00707f +#define MATCH_VFWADD_WV 0xd0001057 +#define MASK_VFWADD_WV 0xfc00707f +#define MATCH_VFWSUB_WV 0xd8001057 +#define MASK_VFWSUB_WV 0xfc00707f +#define MATCH_VFWMUL_VV 0xe0001057 +#define MASK_VFWMUL_VV 0xfc00707f +#define MATCH_VFDOT_VV 0xe4001057 +#define MASK_VFDOT_VV 0xfc00707f +#define MATCH_VFWMACC_VV 0xf0001057 +#define MASK_VFWMACC_VV 0xfc00707f +#define MATCH_VFWNMACC_VV 0xf4001057 +#define MASK_VFWNMACC_VV 0xfc00707f +#define MATCH_VFWMSAC_VV 0xf8001057 +#define MASK_VFWMSAC_VV 0xfc00707f +#define MATCH_VFWNMSAC_VV 0xfc001057 +#define MASK_VFWNMSAC_VV 0xfc00707f +#define MATCH_VADD_VX 0x4057 +#define MASK_VADD_VX 0xfc00707f +#define MATCH_VSUB_VX 0x8004057 +#define MASK_VSUB_VX 0xfc00707f +#define MATCH_VRSUB_VX 0xc004057 +#define MASK_VRSUB_VX 0xfc00707f +#define MATCH_VMINU_VX 0x10004057 +#define MASK_VMINU_VX 0xfc00707f +#define MATCH_VMIN_VX 0x14004057 +#define MASK_VMIN_VX 0xfc00707f +#define MATCH_VMAXU_VX 0x18004057 +#define MASK_VMAXU_VX 0xfc00707f +#define MATCH_VMAX_VX 0x1c004057 +#define MASK_VMAX_VX 0xfc00707f +#define MATCH_VAND_VX 0x24004057 +#define MASK_VAND_VX 0xfc00707f +#define MATCH_VOR_VX 0x28004057 +#define MASK_VOR_VX 0xfc00707f +#define MATCH_VXOR_VX 0x2c004057 +#define MASK_VXOR_VX 0xfc00707f +#define MATCH_VRGATHER_VX 0x30004057 +#define MASK_VRGATHER_VX 0xfc00707f +#define MATCH_VSLIDEUP_VX 0x38004057 +#define MASK_VSLIDEUP_VX 0xfc00707f +#define MATCH_VSLIDEDOWN_VX 0x3c004057 +#define MASK_VSLIDEDOWN_VX 0xfc00707f +#define MATCH_VADC_VXM 0x40004057 +#define MASK_VADC_VXM 0xfe00707f +#define MATCH_VMADC_VXM 0x44004057 +#define MASK_VMADC_VXM 0xfc00707f +#define MATCH_VSBC_VXM 0x48004057 +#define MASK_VSBC_VXM 0xfe00707f +#define MATCH_VMSBC_VXM 0x4c004057 +#define MASK_VMSBC_VXM 0xfc00707f +#define MATCH_VMERGE_VXM 0x5c004057 +#define MASK_VMERGE_VXM 0xfe00707f +#define MATCH_VMV_V_X 0x5e004057 +#define MASK_VMV_V_X 0xfff0707f +#define MATCH_VMSEQ_VX 0x60004057 +#define MASK_VMSEQ_VX 0xfc00707f +#define MATCH_VMSNE_VX 0x64004057 +#define MASK_VMSNE_VX 0xfc00707f +#define MATCH_VMSLTU_VX 0x68004057 +#define MASK_VMSLTU_VX 0xfc00707f +#define MATCH_VMSLT_VX 0x6c004057 +#define MASK_VMSLT_VX 0xfc00707f +#define MATCH_VMSLEU_VX 0x70004057 +#define MASK_VMSLEU_VX 0xfc00707f +#define MATCH_VMSLE_VX 0x74004057 +#define MASK_VMSLE_VX 0xfc00707f +#define MATCH_VMSGTU_VX 0x78004057 +#define MASK_VMSGTU_VX 0xfc00707f +#define MATCH_VMSGT_VX 0x7c004057 +#define MASK_VMSGT_VX 0xfc00707f +#define MATCH_VSADDU_VX 0x80004057 +#define MASK_VSADDU_VX 0xfc00707f +#define MATCH_VSADD_VX 0x84004057 +#define MASK_VSADD_VX 0xfc00707f +#define MATCH_VSSUBU_VX 0x88004057 +#define MASK_VSSUBU_VX 0xfc00707f +#define MATCH_VSSUB_VX 0x8c004057 +#define MASK_VSSUB_VX 0xfc00707f +#define MATCH_VSLL_VX 0x94004057 +#define MASK_VSLL_VX 0xfc00707f +#define MATCH_VSMUL_VX 0x9c004057 +#define MASK_VSMUL_VX 0xfc00707f +#define MATCH_VSRL_VX 0xa0004057 +#define MASK_VSRL_VX 0xfc00707f +#define MATCH_VSRA_VX 0xa4004057 +#define MASK_VSRA_VX 0xfc00707f +#define MATCH_VSSRL_VX 0xa8004057 +#define MASK_VSSRL_VX 0xfc00707f +#define MATCH_VSSRA_VX 0xac004057 +#define MASK_VSSRA_VX 0xfc00707f +#define MATCH_VNSRL_WX 0xb0004057 +#define MASK_VNSRL_WX 0xfc00707f +#define MATCH_VNSRA_WX 0xb4004057 +#define MASK_VNSRA_WX 0xfc00707f +#define MATCH_VNCLIPU_WX 0xb8004057 +#define MASK_VNCLIPU_WX 0xfc00707f +#define MATCH_VNCLIP_WX 0xbc004057 +#define MASK_VNCLIP_WX 0xfc00707f +#define MATCH_VADD_VV 0x57 +#define MASK_VADD_VV 0xfc00707f +#define MATCH_VSUB_VV 0x8000057 +#define MASK_VSUB_VV 0xfc00707f +#define MATCH_VMINU_VV 0x10000057 +#define MASK_VMINU_VV 0xfc00707f +#define MATCH_VMIN_VV 0x14000057 +#define MASK_VMIN_VV 0xfc00707f +#define MATCH_VMAXU_VV 0x18000057 +#define MASK_VMAXU_VV 0xfc00707f +#define MATCH_VMAX_VV 0x1c000057 +#define MASK_VMAX_VV 0xfc00707f +#define MATCH_VAND_VV 0x24000057 +#define MASK_VAND_VV 0xfc00707f +#define MATCH_VOR_VV 0x28000057 +#define MASK_VOR_VV 0xfc00707f +#define MATCH_VXOR_VV 0x2c000057 +#define MASK_VXOR_VV 0xfc00707f +#define MATCH_VRGATHER_VV 0x30000057 +#define MASK_VRGATHER_VV 0xfc00707f +#define MATCH_VRGATHEREI16_VV 0x38000057 +#define MASK_VRGATHEREI16_VV 0xfc00707f +#define MATCH_VADC_VVM 0x40000057 +#define MASK_VADC_VVM 0xfe00707f +#define MATCH_VMADC_VVM 0x44000057 +#define MASK_VMADC_VVM 0xfc00707f +#define MATCH_VSBC_VVM 0x48000057 +#define MASK_VSBC_VVM 0xfe00707f +#define MATCH_VMSBC_VVM 0x4c000057 +#define MASK_VMSBC_VVM 0xfc00707f +#define MATCH_VMERGE_VVM 0x5c000057 +#define MASK_VMERGE_VVM 0xfe00707f +#define MATCH_VMV_V_V 0x5e000057 +#define MASK_VMV_V_V 0xfff0707f +#define MATCH_VMSEQ_VV 0x60000057 +#define MASK_VMSEQ_VV 0xfc00707f +#define MATCH_VMSNE_VV 0x64000057 +#define MASK_VMSNE_VV 0xfc00707f +#define MATCH_VMSLTU_VV 0x68000057 +#define MASK_VMSLTU_VV 0xfc00707f +#define MATCH_VMSLT_VV 0x6c000057 +#define MASK_VMSLT_VV 0xfc00707f +#define MATCH_VMSLEU_VV 0x70000057 +#define MASK_VMSLEU_VV 0xfc00707f +#define MATCH_VMSLE_VV 0x74000057 +#define MASK_VMSLE_VV 0xfc00707f +#define MATCH_VSADDU_VV 0x80000057 +#define MASK_VSADDU_VV 0xfc00707f +#define MATCH_VSADD_VV 0x84000057 +#define MASK_VSADD_VV 0xfc00707f +#define MATCH_VSSUBU_VV 0x88000057 +#define MASK_VSSUBU_VV 0xfc00707f +#define MATCH_VSSUB_VV 0x8c000057 +#define MASK_VSSUB_VV 0xfc00707f +#define MATCH_VSLL_VV 0x94000057 +#define MASK_VSLL_VV 0xfc00707f +#define MATCH_VSMUL_VV 0x9c000057 +#define MASK_VSMUL_VV 0xfc00707f +#define MATCH_VSRL_VV 0xa0000057 +#define MASK_VSRL_VV 0xfc00707f +#define MATCH_VSRA_VV 0xa4000057 +#define MASK_VSRA_VV 0xfc00707f +#define MATCH_VSSRL_VV 0xa8000057 +#define MASK_VSSRL_VV 0xfc00707f +#define MATCH_VSSRA_VV 0xac000057 +#define MASK_VSSRA_VV 0xfc00707f +#define MATCH_VNSRL_WV 0xb0000057 +#define MASK_VNSRL_WV 0xfc00707f +#define MATCH_VNSRA_WV 0xb4000057 +#define MASK_VNSRA_WV 0xfc00707f +#define MATCH_VNCLIPU_WV 0xb8000057 +#define MASK_VNCLIPU_WV 0xfc00707f +#define MATCH_VNCLIP_WV 0xbc000057 +#define MASK_VNCLIP_WV 0xfc00707f +#define MATCH_VWREDSUMU_VS 0xc0000057 +#define MASK_VWREDSUMU_VS 0xfc00707f +#define MATCH_VWREDSUM_VS 0xc4000057 +#define MASK_VWREDSUM_VS 0xfc00707f +#define MATCH_VDOTU_VV 0xe0000057 +#define MASK_VDOTU_VV 0xfc00707f +#define MATCH_VDOT_VV 0xe4000057 +#define MASK_VDOT_VV 0xfc00707f +#define MATCH_VQMACCU_VV 0xf0000057 +#define MASK_VQMACCU_VV 0xfc00707f +#define MATCH_VQMACC_VV 0xf4000057 +#define MASK_VQMACC_VV 0xfc00707f +#define MATCH_VQMACCSU_VV 0xfc000057 +#define MASK_VQMACCSU_VV 0xfc00707f +#define MATCH_VADD_VI 0x3057 +#define MASK_VADD_VI 0xfc00707f +#define MATCH_VRSUB_VI 0xc003057 +#define MASK_VRSUB_VI 0xfc00707f +#define MATCH_VAND_VI 0x24003057 +#define MASK_VAND_VI 0xfc00707f +#define MATCH_VOR_VI 0x28003057 +#define MASK_VOR_VI 0xfc00707f +#define MATCH_VXOR_VI 0x2c003057 +#define MASK_VXOR_VI 0xfc00707f +#define MATCH_VRGATHER_VI 0x30003057 +#define MASK_VRGATHER_VI 0xfc00707f +#define MATCH_VSLIDEUP_VI 0x38003057 +#define MASK_VSLIDEUP_VI 0xfc00707f +#define MATCH_VSLIDEDOWN_VI 0x3c003057 +#define MASK_VSLIDEDOWN_VI 0xfc00707f +#define MATCH_VADC_VIM 0x40003057 +#define MASK_VADC_VIM 0xfe00707f +#define MATCH_VMADC_VIM 0x44003057 +#define MASK_VMADC_VIM 0xfc00707f +#define MATCH_VMERGE_VIM 0x5c003057 +#define MASK_VMERGE_VIM 0xfe00707f +#define MATCH_VMV_V_I 0x5e003057 +#define MASK_VMV_V_I 0xfff0707f +#define MATCH_VMSEQ_VI 0x60003057 +#define MASK_VMSEQ_VI 0xfc00707f +#define MATCH_VMSNE_VI 0x64003057 +#define MASK_VMSNE_VI 0xfc00707f +#define MATCH_VMSLEU_VI 0x70003057 +#define MASK_VMSLEU_VI 0xfc00707f +#define MATCH_VMSLE_VI 0x74003057 +#define MASK_VMSLE_VI 0xfc00707f +#define MATCH_VMSGTU_VI 0x78003057 +#define MASK_VMSGTU_VI 0xfc00707f +#define MATCH_VMSGT_VI 0x7c003057 +#define MASK_VMSGT_VI 0xfc00707f +#define MATCH_VSADDU_VI 0x80003057 +#define MASK_VSADDU_VI 0xfc00707f +#define MATCH_VSADD_VI 0x84003057 +#define MASK_VSADD_VI 0xfc00707f +#define MATCH_VSLL_VI 0x94003057 +#define MASK_VSLL_VI 0xfc00707f +#define MATCH_VMV1R_V 0x9e003057 +#define MASK_VMV1R_V 0xfe0ff07f +#define MATCH_VMV2R_V 0x9e00b057 +#define MASK_VMV2R_V 0xfe0ff07f +#define MATCH_VMV4R_V 0x9e01b057 +#define MASK_VMV4R_V 0xfe0ff07f +#define MATCH_VMV8R_V 0x9e03b057 +#define MASK_VMV8R_V 0xfe0ff07f +#define MATCH_VSRL_VI 0xa0003057 +#define MASK_VSRL_VI 0xfc00707f +#define MATCH_VSRA_VI 0xa4003057 +#define MASK_VSRA_VI 0xfc00707f +#define MATCH_VSSRL_VI 0xa8003057 +#define MASK_VSSRL_VI 0xfc00707f +#define MATCH_VSSRA_VI 0xac003057 +#define MASK_VSSRA_VI 0xfc00707f +#define MATCH_VNSRL_WI 0xb0003057 +#define MASK_VNSRL_WI 0xfc00707f +#define MATCH_VNSRA_WI 0xb4003057 +#define MASK_VNSRA_WI 0xfc00707f +#define MATCH_VNCLIPU_WI 0xb8003057 +#define MASK_VNCLIPU_WI 0xfc00707f +#define MATCH_VNCLIP_WI 0xbc003057 +#define MASK_VNCLIP_WI 0xfc00707f +#define MATCH_VREDSUM_VS 0x2057 +#define MASK_VREDSUM_VS 0xfc00707f +#define MATCH_VREDAND_VS 0x4002057 +#define MASK_VREDAND_VS 0xfc00707f +#define MATCH_VREDOR_VS 0x8002057 +#define MASK_VREDOR_VS 0xfc00707f +#define MATCH_VREDXOR_VS 0xc002057 +#define MASK_VREDXOR_VS 0xfc00707f +#define MATCH_VREDMINU_VS 0x10002057 +#define MASK_VREDMINU_VS 0xfc00707f +#define MATCH_VREDMIN_VS 0x14002057 +#define MASK_VREDMIN_VS 0xfc00707f +#define MATCH_VREDMAXU_VS 0x18002057 +#define MASK_VREDMAXU_VS 0xfc00707f +#define MATCH_VREDMAX_VS 0x1c002057 +#define MASK_VREDMAX_VS 0xfc00707f +#define MATCH_VAADDU_VV 0x20002057 +#define MASK_VAADDU_VV 0xfc00707f +#define MATCH_VAADD_VV 0x24002057 +#define MASK_VAADD_VV 0xfc00707f +#define MATCH_VASUBU_VV 0x28002057 +#define MASK_VASUBU_VV 0xfc00707f +#define MATCH_VASUB_VV 0x2c002057 +#define MASK_VASUB_VV 0xfc00707f +#define MATCH_VMV_X_S 0x42002057 +#define MASK_VMV_X_S 0xfe0ff07f +#define MATCH_VZEXT_VF8 0x48012057 +#define MASK_VZEXT_VF8 0xfc0ff07f +#define MATCH_VSEXT_VF8 0x4801a057 +#define MASK_VSEXT_VF8 0xfc0ff07f +#define MATCH_VZEXT_VF4 0x48022057 +#define MASK_VZEXT_VF4 0xfc0ff07f +#define MATCH_VSEXT_VF4 0x4802a057 +#define MASK_VSEXT_VF4 0xfc0ff07f +#define MATCH_VZEXT_VF2 0x48032057 +#define MASK_VZEXT_VF2 0xfc0ff07f +#define MATCH_VSEXT_VF2 0x4803a057 +#define MASK_VSEXT_VF2 0xfc0ff07f +#define MATCH_VCOMPRESS_VM 0x5e002057 +#define MASK_VCOMPRESS_VM 0xfe00707f +#define MATCH_VMANDNOT_MM 0x60002057 +#define MASK_VMANDNOT_MM 0xfc00707f +#define MATCH_VMAND_MM 0x64002057 +#define MASK_VMAND_MM 0xfc00707f +#define MATCH_VMOR_MM 0x68002057 +#define MASK_VMOR_MM 0xfc00707f +#define MATCH_VMXOR_MM 0x6c002057 +#define MASK_VMXOR_MM 0xfc00707f +#define MATCH_VMORNOT_MM 0x70002057 +#define MASK_VMORNOT_MM 0xfc00707f +#define MATCH_VMNAND_MM 0x74002057 +#define MASK_VMNAND_MM 0xfc00707f +#define MATCH_VMNOR_MM 0x78002057 +#define MASK_VMNOR_MM 0xfc00707f +#define MATCH_VMXNOR_MM 0x7c002057 +#define MASK_VMXNOR_MM 0xfc00707f +#define MATCH_VMSBF_M 0x5000a057 +#define MASK_VMSBF_M 0xfc0ff07f +#define MATCH_VMSOF_M 0x50012057 +#define MASK_VMSOF_M 0xfc0ff07f +#define MATCH_VMSIF_M 0x5001a057 +#define MASK_VMSIF_M 0xfc0ff07f +#define MATCH_VIOTA_M 0x50082057 +#define MASK_VIOTA_M 0xfc0ff07f +#define MATCH_VID_V 0x5008a057 +#define MASK_VID_V 0xfdfff07f +#define MATCH_VPOPC_M 0x40082057 +#define MASK_VPOPC_M 0xfc0ff07f +#define MATCH_VFIRST_M 0x4008a057 +#define MASK_VFIRST_M 0xfc0ff07f +#define MATCH_VDIVU_VV 0x80002057 +#define MASK_VDIVU_VV 0xfc00707f +#define MATCH_VDIV_VV 0x84002057 +#define MASK_VDIV_VV 0xfc00707f +#define MATCH_VREMU_VV 0x88002057 +#define MASK_VREMU_VV 0xfc00707f +#define MATCH_VREM_VV 0x8c002057 +#define MASK_VREM_VV 0xfc00707f +#define MATCH_VMULHU_VV 0x90002057 +#define MASK_VMULHU_VV 0xfc00707f +#define MATCH_VMUL_VV 0x94002057 +#define MASK_VMUL_VV 0xfc00707f +#define MATCH_VMULHSU_VV 0x98002057 +#define MASK_VMULHSU_VV 0xfc00707f +#define MATCH_VMULH_VV 0x9c002057 +#define MASK_VMULH_VV 0xfc00707f +#define MATCH_VMADD_VV 0xa4002057 +#define MASK_VMADD_VV 0xfc00707f +#define MATCH_VNMSUB_VV 0xac002057 +#define MASK_VNMSUB_VV 0xfc00707f +#define MATCH_VMACC_VV 0xb4002057 +#define MASK_VMACC_VV 0xfc00707f +#define MATCH_VNMSAC_VV 0xbc002057 +#define MASK_VNMSAC_VV 0xfc00707f +#define MATCH_VWADDU_VV 0xc0002057 +#define MASK_VWADDU_VV 0xfc00707f +#define MATCH_VWADD_VV 0xc4002057 +#define MASK_VWADD_VV 0xfc00707f +#define MATCH_VWSUBU_VV 0xc8002057 +#define MASK_VWSUBU_VV 0xfc00707f +#define MATCH_VWSUB_VV 0xcc002057 +#define MASK_VWSUB_VV 0xfc00707f +#define MATCH_VWADDU_WV 0xd0002057 +#define MASK_VWADDU_WV 0xfc00707f +#define MATCH_VWADD_WV 0xd4002057 +#define MASK_VWADD_WV 0xfc00707f +#define MATCH_VWSUBU_WV 0xd8002057 +#define MASK_VWSUBU_WV 0xfc00707f +#define MATCH_VWSUB_WV 0xdc002057 +#define MASK_VWSUB_WV 0xfc00707f +#define MATCH_VWMULU_VV 0xe0002057 +#define MASK_VWMULU_VV 0xfc00707f +#define MATCH_VWMULSU_VV 0xe8002057 +#define MASK_VWMULSU_VV 0xfc00707f +#define MATCH_VWMUL_VV 0xec002057 +#define MASK_VWMUL_VV 0xfc00707f +#define MATCH_VWMACCU_VV 0xf0002057 +#define MASK_VWMACCU_VV 0xfc00707f +#define MATCH_VWMACC_VV 0xf4002057 +#define MASK_VWMACC_VV 0xfc00707f +#define MATCH_VWMACCSU_VV 0xfc002057 +#define MASK_VWMACCSU_VV 0xfc00707f +#define MATCH_VAADDU_VX 0x20006057 +#define MASK_VAADDU_VX 0xfc00707f +#define MATCH_VAADD_VX 0x24006057 +#define MASK_VAADD_VX 0xfc00707f +#define MATCH_VASUBU_VX 0x28006057 +#define MASK_VASUBU_VX 0xfc00707f +#define MATCH_VASUB_VX 0x2c006057 +#define MASK_VASUB_VX 0xfc00707f +#define MATCH_VMV_S_X 0x42006057 +#define MASK_VMV_S_X 0xfff0707f +#define MATCH_VSLIDE1UP_VX 0x38006057 +#define MASK_VSLIDE1UP_VX 0xfc00707f +#define MATCH_VSLIDE1DOWN_VX 0x3c006057 +#define MASK_VSLIDE1DOWN_VX 0xfc00707f +#define MATCH_VDIVU_VX 0x80006057 +#define MASK_VDIVU_VX 0xfc00707f +#define MATCH_VDIV_VX 0x84006057 +#define MASK_VDIV_VX 0xfc00707f +#define MATCH_VREMU_VX 0x88006057 +#define MASK_VREMU_VX 0xfc00707f +#define MATCH_VREM_VX 0x8c006057 +#define MASK_VREM_VX 0xfc00707f +#define MATCH_VMULHU_VX 0x90006057 +#define MASK_VMULHU_VX 0xfc00707f +#define MATCH_VMUL_VX 0x94006057 +#define MASK_VMUL_VX 0xfc00707f +#define MATCH_VMULHSU_VX 0x98006057 +#define MASK_VMULHSU_VX 0xfc00707f +#define MATCH_VMULH_VX 0x9c006057 +#define MASK_VMULH_VX 0xfc00707f +#define MATCH_VMADD_VX 0xa4006057 +#define MASK_VMADD_VX 0xfc00707f +#define MATCH_VNMSUB_VX 0xac006057 +#define MASK_VNMSUB_VX 0xfc00707f +#define MATCH_VMACC_VX 0xb4006057 +#define MASK_VMACC_VX 0xfc00707f +#define MATCH_VNMSAC_VX 0xbc006057 +#define MASK_VNMSAC_VX 0xfc00707f +#define MATCH_VWADDU_VX 0xc0006057 +#define MASK_VWADDU_VX 0xfc00707f +#define MATCH_VWADD_VX 0xc4006057 +#define MASK_VWADD_VX 0xfc00707f +#define MATCH_VWSUBU_VX 0xc8006057 +#define MASK_VWSUBU_VX 0xfc00707f +#define MATCH_VWSUB_VX 0xcc006057 +#define MASK_VWSUB_VX 0xfc00707f +#define MATCH_VWADDU_WX 0xd0006057 +#define MASK_VWADDU_WX 0xfc00707f +#define MATCH_VWADD_WX 0xd4006057 +#define MASK_VWADD_WX 0xfc00707f +#define MATCH_VWSUBU_WX 0xd8006057 +#define MASK_VWSUBU_WX 0xfc00707f +#define MATCH_VWSUB_WX 0xdc006057 +#define MASK_VWSUB_WX 0xfc00707f +#define MATCH_VWMULU_VX 0xe0006057 +#define MASK_VWMULU_VX 0xfc00707f +#define MATCH_VWMULSU_VX 0xe8006057 +#define MASK_VWMULSU_VX 0xfc00707f +#define MATCH_VWMUL_VX 0xec006057 +#define MASK_VWMUL_VX 0xfc00707f +#define MATCH_VWMACCU_VX 0xf0006057 +#define MASK_VWMACCU_VX 0xfc00707f +#define MATCH_VWMACC_VX 0xf4006057 +#define MASK_VWMACC_VX 0xfc00707f +#define MATCH_VWMACCUS_VX 0xf8006057 +#define MASK_VWMACCUS_VX 0xfc00707f +#define MATCH_VWMACCSU_VX 0xfc006057 +#define MASK_VWMACCSU_VX 0xfc00707f +#define MATCH_VAMOSWAPEI8_V 0x800002f +#define MASK_VAMOSWAPEI8_V 0xf800707f +#define MATCH_VAMOADDEI8_V 0x2f +#define MASK_VAMOADDEI8_V 0xf800707f +#define MATCH_VAMOXOREI8_V 0x2000002f +#define MASK_VAMOXOREI8_V 0xf800707f +#define MATCH_VAMOANDEI8_V 0x6000002f +#define MASK_VAMOANDEI8_V 0xf800707f +#define MATCH_VAMOOREI8_V 0x4000002f +#define MASK_VAMOOREI8_V 0xf800707f +#define MATCH_VAMOMINEI8_V 0x8000002f +#define MASK_VAMOMINEI8_V 0xf800707f +#define MATCH_VAMOMAXEI8_V 0xa000002f +#define MASK_VAMOMAXEI8_V 0xf800707f +#define MATCH_VAMOMINUEI8_V 0xc000002f +#define MASK_VAMOMINUEI8_V 0xf800707f +#define MATCH_VAMOMAXUEI8_V 0xe000002f +#define MASK_VAMOMAXUEI8_V 0xf800707f +#define MATCH_VAMOSWAPEI16_V 0x800502f +#define MASK_VAMOSWAPEI16_V 0xf800707f +#define MATCH_VAMOADDEI16_V 0x502f +#define MASK_VAMOADDEI16_V 0xf800707f +#define MATCH_VAMOXOREI16_V 0x2000502f +#define MASK_VAMOXOREI16_V 0xf800707f +#define MATCH_VAMOANDEI16_V 0x6000502f +#define MASK_VAMOANDEI16_V 0xf800707f +#define MATCH_VAMOOREI16_V 0x4000502f +#define MASK_VAMOOREI16_V 0xf800707f +#define MATCH_VAMOMINEI16_V 0x8000502f +#define MASK_VAMOMINEI16_V 0xf800707f +#define MATCH_VAMOMAXEI16_V 0xa000502f +#define MASK_VAMOMAXEI16_V 0xf800707f +#define MATCH_VAMOMINUEI16_V 0xc000502f +#define MASK_VAMOMINUEI16_V 0xf800707f +#define MATCH_VAMOMAXUEI16_V 0xe000502f +#define MASK_VAMOMAXUEI16_V 0xf800707f +#define MATCH_VAMOSWAPEI32_V 0x800602f +#define MASK_VAMOSWAPEI32_V 0xf800707f +#define MATCH_VAMOADDEI32_V 0x602f +#define MASK_VAMOADDEI32_V 0xf800707f +#define MATCH_VAMOXOREI32_V 0x2000602f +#define MASK_VAMOXOREI32_V 0xf800707f +#define MATCH_VAMOANDEI32_V 0x6000602f +#define MASK_VAMOANDEI32_V 0xf800707f +#define MATCH_VAMOOREI32_V 0x4000602f +#define MASK_VAMOOREI32_V 0xf800707f +#define MATCH_VAMOMINEI32_V 0x8000602f +#define MASK_VAMOMINEI32_V 0xf800707f +#define MATCH_VAMOMAXEI32_V 0xa000602f +#define MASK_VAMOMAXEI32_V 0xf800707f +#define MATCH_VAMOMINUEI32_V 0xc000602f +#define MASK_VAMOMINUEI32_V 0xf800707f +#define MATCH_VAMOMAXUEI32_V 0xe000602f +#define MASK_VAMOMAXUEI32_V 0xf800707f +#define MATCH_VAMOSWAPEI64_V 0x800702f +#define MASK_VAMOSWAPEI64_V 0xf800707f +#define MATCH_VAMOADDEI64_V 0x702f +#define MASK_VAMOADDEI64_V 0xf800707f +#define MATCH_VAMOXOREI64_V 0x2000702f +#define MASK_VAMOXOREI64_V 0xf800707f +#define MATCH_VAMOANDEI64_V 0x6000702f +#define MASK_VAMOANDEI64_V 0xf800707f +#define MATCH_VAMOOREI64_V 0x4000702f +#define MASK_VAMOOREI64_V 0xf800707f +#define MATCH_VAMOMINEI64_V 0x8000702f +#define MASK_VAMOMINEI64_V 0xf800707f +#define MATCH_VAMOMAXEI64_V 0xa000702f +#define MASK_VAMOMAXEI64_V 0xf800707f +#define MATCH_VAMOMINUEI64_V 0xc000702f +#define MASK_VAMOMINUEI64_V 0xf800707f +#define MATCH_VAMOMAXUEI64_V 0xe000702f +#define MASK_VAMOMAXUEI64_V 0xf800707f +#define MATCH_VMVNFR_V 0x9e003057 +#define MASK_VMVNFR_V 0xfe00707f +#define MATCH_VL1R_V 0x2800007 +#define MASK_VL1R_V 0xfff0707f +#define MATCH_VL2R_V 0x6805007 +#define MASK_VL2R_V 0xfff0707f +#define MATCH_VL4R_V 0xe806007 +#define MASK_VL4R_V 0xfff0707f +#define MATCH_VL8R_V 0x1e807007 +#define MASK_VL8R_V 0xfff0707f +#define CSR_FFLAGS 0x1 +#define CSR_FRM 0x2 +#define CSR_FCSR 0x3 +#define CSR_USTATUS 0x0 +#define CSR_UIE 0x4 +#define CSR_UTVEC 0x5 +#define CSR_VSTART 0x8 +#define CSR_VXSAT 0x9 +#define CSR_VXRM 0xa +#define CSR_VCSR 0xf +#define CSR_USCRATCH 0x40 +#define CSR_UEPC 0x41 +#define CSR_UCAUSE 0x42 +#define CSR_UTVAL 0x43 +#define CSR_UIP 0x44 +#define CSR_CYCLE 0xc00 +#define CSR_TIME 0xc01 +#define CSR_INSTRET 0xc02 +#define CSR_HPMCOUNTER3 0xc03 +#define CSR_HPMCOUNTER4 0xc04 +#define CSR_HPMCOUNTER5 0xc05 +#define CSR_HPMCOUNTER6 0xc06 +#define CSR_HPMCOUNTER7 0xc07 +#define CSR_HPMCOUNTER8 0xc08 +#define CSR_HPMCOUNTER9 0xc09 +#define CSR_HPMCOUNTER10 0xc0a +#define CSR_HPMCOUNTER11 0xc0b +#define CSR_HPMCOUNTER12 0xc0c +#define CSR_HPMCOUNTER13 0xc0d +#define CSR_HPMCOUNTER14 0xc0e +#define CSR_HPMCOUNTER15 0xc0f +#define CSR_HPMCOUNTER16 0xc10 +#define CSR_HPMCOUNTER17 0xc11 +#define CSR_HPMCOUNTER18 0xc12 +#define CSR_HPMCOUNTER19 0xc13 +#define CSR_HPMCOUNTER20 0xc14 +#define CSR_HPMCOUNTER21 0xc15 +#define CSR_HPMCOUNTER22 0xc16 +#define CSR_HPMCOUNTER23 0xc17 +#define CSR_HPMCOUNTER24 0xc18 +#define CSR_HPMCOUNTER25 0xc19 +#define CSR_HPMCOUNTER26 0xc1a +#define CSR_HPMCOUNTER27 0xc1b +#define CSR_HPMCOUNTER28 0xc1c +#define CSR_HPMCOUNTER29 0xc1d +#define CSR_HPMCOUNTER30 0xc1e +#define CSR_HPMCOUNTER31 0xc1f +#define CSR_VL 0xc20 +#define CSR_VTYPE 0xc21 +#define CSR_VLENB 0xc22 +#define CSR_SSTATUS 0x100 +#define CSR_SEDELEG 0x102 +#define CSR_SIDELEG 0x103 +#define CSR_SIE 0x104 +#define CSR_STVEC 0x105 +#define CSR_SCOUNTEREN 0x106 +#define CSR_SSCRATCH 0x140 +#define CSR_SEPC 0x141 +#define CSR_SCAUSE 0x142 +#define CSR_STVAL 0x143 +#define CSR_SIP 0x144 +#define CSR_SATP 0x180 +#define CSR_VSSTATUS 0x200 +#define CSR_VSIE 0x204 +#define CSR_VSTVEC 0x205 +#define CSR_VSSCRATCH 0x240 +#define CSR_VSEPC 0x241 +#define CSR_VSCAUSE 0x242 +#define CSR_VSTVAL 0x243 +#define CSR_VSIP 0x244 +#define CSR_VSATP 0x280 +#define CSR_HSTATUS 0x600 +#define CSR_HEDELEG 0x602 +#define CSR_HIDELEG 0x603 +#define CSR_HIE 0x604 +#define CSR_HTIMEDELTA 0x605 +#define CSR_HCOUNTEREN 0x606 +#define CSR_HGEIE 0x607 +#define CSR_HTVAL 0x643 +#define CSR_HIP 0x644 +#define CSR_HVIP 0x645 +#define CSR_HTINST 0x64a +#define CSR_HGATP 0x680 +#define CSR_HGEIP 0xe12 +#define CSR_UTVT 0x7 +#define CSR_UNXTI 0x45 +#define CSR_UINTSTATUS 0x46 +#define CSR_USCRATCHCSW 0x48 +#define CSR_USCRATCHCSWL 0x49 +#define CSR_STVT 0x107 +#define CSR_SNXTI 0x145 +#define CSR_SINTSTATUS 0x146 +#define CSR_SSCRATCHCSW 0x148 +#define CSR_SSCRATCHCSWL 0x149 +#define CSR_MTVT 0x307 +#define CSR_MNXTI 0x345 +#define CSR_MINTSTATUS 0x346 +#define CSR_MSCRATCHCSW 0x348 +#define CSR_MSCRATCHCSWL 0x349 +#define CSR_MSTATUS 0x300 +#define CSR_MISA 0x301 +#define CSR_MEDELEG 0x302 +#define CSR_MIDELEG 0x303 +#define CSR_MIE 0x304 +#define CSR_MTVEC 0x305 +#define CSR_MCOUNTEREN 0x306 +#define CSR_MCOUNTINHIBIT 0x320 +#define CSR_MSCRATCH 0x340 +#define CSR_MEPC 0x341 +#define CSR_MCAUSE 0x342 +#define CSR_MTVAL 0x343 +#define CSR_MIP 0x344 +#define CSR_MTINST 0x34a +#define CSR_MTVAL2 0x34b +#define CSR_PMPCFG0 0x3a0 +#define CSR_PMPCFG1 0x3a1 +#define CSR_PMPCFG2 0x3a2 +#define CSR_PMPCFG3 0x3a3 +#define CSR_PMPADDR0 0x3b0 +#define CSR_PMPADDR1 0x3b1 +#define CSR_PMPADDR2 0x3b2 +#define CSR_PMPADDR3 0x3b3 +#define CSR_PMPADDR4 0x3b4 +#define CSR_PMPADDR5 0x3b5 +#define CSR_PMPADDR6 0x3b6 +#define CSR_PMPADDR7 0x3b7 +#define CSR_PMPADDR8 0x3b8 +#define CSR_PMPADDR9 0x3b9 +#define CSR_PMPADDR10 0x3ba +#define CSR_PMPADDR11 0x3bb +#define CSR_PMPADDR12 0x3bc +#define CSR_PMPADDR13 0x3bd +#define CSR_PMPADDR14 0x3be +#define CSR_PMPADDR15 0x3bf +#define CSR_TSELECT 0x7a0 +#define CSR_TDATA1 0x7a1 +#define CSR_TDATA2 0x7a2 +#define CSR_TDATA3 0x7a3 +#define CSR_TINFO 0x7a4 +#define CSR_TCONTROL 0x7a5 +#define CSR_MCONTEXT 0x7a8 +#define CSR_SCONTEXT 0x7aa +#define CSR_DCSR 0x7b0 +#define CSR_DPC 0x7b1 +#define CSR_DSCRATCH0 0x7b2 +#define CSR_DSCRATCH1 0x7b3 +#define CSR_MCYCLE 0xb00 +#define CSR_MINSTRET 0xb02 +#define CSR_MHPMCOUNTER3 0xb03 +#define CSR_MHPMCOUNTER4 0xb04 +#define CSR_MHPMCOUNTER5 0xb05 +#define CSR_MHPMCOUNTER6 0xb06 +#define CSR_MHPMCOUNTER7 0xb07 +#define CSR_MHPMCOUNTER8 0xb08 +#define CSR_MHPMCOUNTER9 0xb09 +#define CSR_MHPMCOUNTER10 0xb0a +#define CSR_MHPMCOUNTER11 0xb0b +#define CSR_MHPMCOUNTER12 0xb0c +#define CSR_MHPMCOUNTER13 0xb0d +#define CSR_MHPMCOUNTER14 0xb0e +#define CSR_MHPMCOUNTER15 0xb0f +#define CSR_MHPMCOUNTER16 0xb10 +#define CSR_MHPMCOUNTER17 0xb11 +#define CSR_MHPMCOUNTER18 0xb12 +#define CSR_MHPMCOUNTER19 0xb13 +#define CSR_MHPMCOUNTER20 0xb14 +#define CSR_MHPMCOUNTER21 0xb15 +#define CSR_MHPMCOUNTER22 0xb16 +#define CSR_MHPMCOUNTER23 0xb17 +#define CSR_MHPMCOUNTER24 0xb18 +#define CSR_MHPMCOUNTER25 0xb19 +#define CSR_MHPMCOUNTER26 0xb1a +#define CSR_MHPMCOUNTER27 0xb1b +#define CSR_MHPMCOUNTER28 0xb1c +#define CSR_MHPMCOUNTER29 0xb1d +#define CSR_MHPMCOUNTER30 0xb1e +#define CSR_MHPMCOUNTER31 0xb1f +#define CSR_MHPMEVENT3 0x323 +#define CSR_MHPMEVENT4 0x324 +#define CSR_MHPMEVENT5 0x325 +#define CSR_MHPMEVENT6 0x326 +#define CSR_MHPMEVENT7 0x327 +#define CSR_MHPMEVENT8 0x328 +#define CSR_MHPMEVENT9 0x329 +#define CSR_MHPMEVENT10 0x32a +#define CSR_MHPMEVENT11 0x32b +#define CSR_MHPMEVENT12 0x32c +#define CSR_MHPMEVENT13 0x32d +#define CSR_MHPMEVENT14 0x32e +#define CSR_MHPMEVENT15 0x32f +#define CSR_MHPMEVENT16 0x330 +#define CSR_MHPMEVENT17 0x331 +#define CSR_MHPMEVENT18 0x332 +#define CSR_MHPMEVENT19 0x333 +#define CSR_MHPMEVENT20 0x334 +#define CSR_MHPMEVENT21 0x335 +#define CSR_MHPMEVENT22 0x336 +#define CSR_MHPMEVENT23 0x337 +#define CSR_MHPMEVENT24 0x338 +#define CSR_MHPMEVENT25 0x339 +#define CSR_MHPMEVENT26 0x33a +#define CSR_MHPMEVENT27 0x33b +#define CSR_MHPMEVENT28 0x33c +#define CSR_MHPMEVENT29 0x33d +#define CSR_MHPMEVENT30 0x33e +#define CSR_MHPMEVENT31 0x33f +#define CSR_MVENDORID 0xf11 +#define CSR_MARCHID 0xf12 +#define CSR_MIMPID 0xf13 +#define CSR_MHARTID 0xf14 +#define CSR_MENTROPY 0xf15 +#define CSR_MNOISE 0x7a9 +#define CSR_HTIMEDELTAH 0x615 +#define CSR_CYCLEH 0xc80 +#define CSR_TIMEH 0xc81 +#define CSR_INSTRETH 0xc82 +#define CSR_HPMCOUNTER3H 0xc83 +#define CSR_HPMCOUNTER4H 0xc84 +#define CSR_HPMCOUNTER5H 0xc85 +#define CSR_HPMCOUNTER6H 0xc86 +#define CSR_HPMCOUNTER7H 0xc87 +#define CSR_HPMCOUNTER8H 0xc88 +#define CSR_HPMCOUNTER9H 0xc89 +#define CSR_HPMCOUNTER10H 0xc8a +#define CSR_HPMCOUNTER11H 0xc8b +#define CSR_HPMCOUNTER12H 0xc8c +#define CSR_HPMCOUNTER13H 0xc8d +#define CSR_HPMCOUNTER14H 0xc8e +#define CSR_HPMCOUNTER15H 0xc8f +#define CSR_HPMCOUNTER16H 0xc90 +#define CSR_HPMCOUNTER17H 0xc91 +#define CSR_HPMCOUNTER18H 0xc92 +#define CSR_HPMCOUNTER19H 0xc93 +#define CSR_HPMCOUNTER20H 0xc94 +#define CSR_HPMCOUNTER21H 0xc95 +#define CSR_HPMCOUNTER22H 0xc96 +#define CSR_HPMCOUNTER23H 0xc97 +#define CSR_HPMCOUNTER24H 0xc98 +#define CSR_HPMCOUNTER25H 0xc99 +#define CSR_HPMCOUNTER26H 0xc9a +#define CSR_HPMCOUNTER27H 0xc9b +#define CSR_HPMCOUNTER28H 0xc9c +#define CSR_HPMCOUNTER29H 0xc9d +#define CSR_HPMCOUNTER30H 0xc9e +#define CSR_HPMCOUNTER31H 0xc9f +#define CSR_MSTATUSH 0x310 +#define CSR_MCYCLEH 0xb80 +#define CSR_MINSTRETH 0xb82 +#define CSR_MHPMCOUNTER3H 0xb83 +#define CSR_MHPMCOUNTER4H 0xb84 +#define CSR_MHPMCOUNTER5H 0xb85 +#define CSR_MHPMCOUNTER6H 0xb86 +#define CSR_MHPMCOUNTER7H 0xb87 +#define CSR_MHPMCOUNTER8H 0xb88 +#define CSR_MHPMCOUNTER9H 0xb89 +#define CSR_MHPMCOUNTER10H 0xb8a +#define CSR_MHPMCOUNTER11H 0xb8b +#define CSR_MHPMCOUNTER12H 0xb8c +#define CSR_MHPMCOUNTER13H 0xb8d +#define CSR_MHPMCOUNTER14H 0xb8e +#define CSR_MHPMCOUNTER15H 0xb8f +#define CSR_MHPMCOUNTER16H 0xb90 +#define CSR_MHPMCOUNTER17H 0xb91 +#define CSR_MHPMCOUNTER18H 0xb92 +#define CSR_MHPMCOUNTER19H 0xb93 +#define CSR_MHPMCOUNTER20H 0xb94 +#define CSR_MHPMCOUNTER21H 0xb95 +#define CSR_MHPMCOUNTER22H 0xb96 +#define CSR_MHPMCOUNTER23H 0xb97 +#define CSR_MHPMCOUNTER24H 0xb98 +#define CSR_MHPMCOUNTER25H 0xb99 +#define CSR_MHPMCOUNTER26H 0xb9a +#define CSR_MHPMCOUNTER27H 0xb9b +#define CSR_MHPMCOUNTER28H 0xb9c +#define CSR_MHPMCOUNTER29H 0xb9d +#define CSR_MHPMCOUNTER30H 0xb9e +#define CSR_MHPMCOUNTER31H 0xb9f +#define CAUSE_MISALIGNED_FETCH 0x0 +#define CAUSE_FETCH_ACCESS 0x1 +#define CAUSE_ILLEGAL_INSTRUCTION 0x2 +#define CAUSE_BREAKPOINT 0x3 +#define CAUSE_MISALIGNED_LOAD 0x4 +#define CAUSE_LOAD_ACCESS 0x5 +#define CAUSE_MISALIGNED_STORE 0x6 +#define CAUSE_STORE_ACCESS 0x7 +#define CAUSE_USER_ECALL 0x8 +#define CAUSE_SUPERVISOR_ECALL 0x9 +#define CAUSE_VIRTUAL_SUPERVISOR_ECALL 0xa +#define CAUSE_MACHINE_ECALL 0xb +#define CAUSE_FETCH_PAGE_FAULT 0xc +#define CAUSE_LOAD_PAGE_FAULT 0xd +#define CAUSE_STORE_PAGE_FAULT 0xf +#define CAUSE_FETCH_GUEST_PAGE_FAULT 0x14 +#define CAUSE_LOAD_GUEST_PAGE_FAULT 0x15 +#define CAUSE_VIRTUAL_INSTRUCTION 0x16 +#define CAUSE_STORE_GUEST_PAGE_FAULT 0x17 +#endif +#ifdef DECLARE_INSN +DECLARE_INSN(slli_rv32, MATCH_SLLI_RV32, MASK_SLLI_RV32) +DECLARE_INSN(srli_rv32, MATCH_SRLI_RV32, MASK_SRLI_RV32) +DECLARE_INSN(srai_rv32, MATCH_SRAI_RV32, MASK_SRAI_RV32) +DECLARE_INSN(frflags, MATCH_FRFLAGS, MASK_FRFLAGS) +DECLARE_INSN(fsflags, MATCH_FSFLAGS, MASK_FSFLAGS) +DECLARE_INSN(fsflagsi, MATCH_FSFLAGSI, MASK_FSFLAGSI) +DECLARE_INSN(frrm, MATCH_FRRM, MASK_FRRM) +DECLARE_INSN(fsrm, MATCH_FSRM, MASK_FSRM) +DECLARE_INSN(fsrmi, MATCH_FSRMI, MASK_FSRMI) +DECLARE_INSN(fscsr, MATCH_FSCSR, MASK_FSCSR) +DECLARE_INSN(frcsr, MATCH_FRCSR, MASK_FRCSR) +DECLARE_INSN(rdcycle, MATCH_RDCYCLE, MASK_RDCYCLE) +DECLARE_INSN(rdtime, MATCH_RDTIME, MASK_RDTIME) +DECLARE_INSN(rdinstret, MATCH_RDINSTRET, MASK_RDINSTRET) +DECLARE_INSN(rdcycleh, MATCH_RDCYCLEH, MASK_RDCYCLEH) +DECLARE_INSN(rdtimeh, MATCH_RDTIMEH, MASK_RDTIMEH) +DECLARE_INSN(rdinstreth, MATCH_RDINSTRETH, MASK_RDINSTRETH) +DECLARE_INSN(scall, MATCH_SCALL, MASK_SCALL) +DECLARE_INSN(sbreak, MATCH_SBREAK, MASK_SBREAK) +DECLARE_INSN(fmv_x_s, MATCH_FMV_X_S, MASK_FMV_X_S) +DECLARE_INSN(fmv_s_x, MATCH_FMV_S_X, MASK_FMV_S_X) +DECLARE_INSN(fence_tso, MATCH_FENCE_TSO, MASK_FENCE_TSO) +DECLARE_INSN(pause, MATCH_PAUSE, MASK_PAUSE) +DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ) +DECLARE_INSN(bne, MATCH_BNE, MASK_BNE) +DECLARE_INSN(blt, MATCH_BLT, MASK_BLT) +DECLARE_INSN(bge, MATCH_BGE, MASK_BGE) +DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU) +DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU) +DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR) +DECLARE_INSN(jal, MATCH_JAL, MASK_JAL) +DECLARE_INSN(lui, MATCH_LUI, MASK_LUI) +DECLARE_INSN(auipc, MATCH_AUIPC, MASK_AUIPC) +DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI) +DECLARE_INSN(slli, MATCH_SLLI, MASK_SLLI) +DECLARE_INSN(slti, MATCH_SLTI, MASK_SLTI) +DECLARE_INSN(sltiu, MATCH_SLTIU, MASK_SLTIU) +DECLARE_INSN(xori, MATCH_XORI, MASK_XORI) +DECLARE_INSN(srli, MATCH_SRLI, MASK_SRLI) +DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI) +DECLARE_INSN(ori, MATCH_ORI, MASK_ORI) +DECLARE_INSN(andi, MATCH_ANDI, MASK_ANDI) +DECLARE_INSN(add, MATCH_ADD, MASK_ADD) +DECLARE_INSN(sub, MATCH_SUB, MASK_SUB) +DECLARE_INSN(sll, MATCH_SLL, MASK_SLL) +DECLARE_INSN(slt, MATCH_SLT, MASK_SLT) +DECLARE_INSN(sltu, MATCH_SLTU, MASK_SLTU) +DECLARE_INSN(xor, MATCH_XOR, MASK_XOR) +DECLARE_INSN(srl, MATCH_SRL, MASK_SRL) +DECLARE_INSN(sra, MATCH_SRA, MASK_SRA) +DECLARE_INSN(or, MATCH_OR, MASK_OR) +DECLARE_INSN(and, MATCH_AND, MASK_AND) +DECLARE_INSN(lb, MATCH_LB, MASK_LB) +DECLARE_INSN(lh, MATCH_LH, MASK_LH) +DECLARE_INSN(lw, MATCH_LW, MASK_LW) +DECLARE_INSN(lbu, MATCH_LBU, MASK_LBU) +DECLARE_INSN(lhu, MATCH_LHU, MASK_LHU) +DECLARE_INSN(sb, MATCH_SB, MASK_SB) +DECLARE_INSN(sh, MATCH_SH, MASK_SH) +DECLARE_INSN(sw, MATCH_SW, MASK_SW) +DECLARE_INSN(fence, MATCH_FENCE, MASK_FENCE) +DECLARE_INSN(fence_i, MATCH_FENCE_I, MASK_FENCE_I) +DECLARE_INSN(addiw, MATCH_ADDIW, MASK_ADDIW) +DECLARE_INSN(slliw, MATCH_SLLIW, MASK_SLLIW) +DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW) +DECLARE_INSN(sraiw, MATCH_SRAIW, MASK_SRAIW) +DECLARE_INSN(addw, MATCH_ADDW, MASK_ADDW) +DECLARE_INSN(subw, MATCH_SUBW, MASK_SUBW) +DECLARE_INSN(sllw, MATCH_SLLW, MASK_SLLW) +DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW) +DECLARE_INSN(sraw, MATCH_SRAW, MASK_SRAW) +DECLARE_INSN(ld, MATCH_LD, MASK_LD) +DECLARE_INSN(lwu, MATCH_LWU, MASK_LWU) +DECLARE_INSN(sd, MATCH_SD, MASK_SD) +DECLARE_INSN(mul, MATCH_MUL, MASK_MUL) +DECLARE_INSN(mulh, MATCH_MULH, MASK_MULH) +DECLARE_INSN(mulhsu, MATCH_MULHSU, MASK_MULHSU) +DECLARE_INSN(mulhu, MATCH_MULHU, MASK_MULHU) +DECLARE_INSN(div, MATCH_DIV, MASK_DIV) +DECLARE_INSN(divu, MATCH_DIVU, MASK_DIVU) +DECLARE_INSN(rem, MATCH_REM, MASK_REM) +DECLARE_INSN(remu, MATCH_REMU, MASK_REMU) +DECLARE_INSN(mulw, MATCH_MULW, MASK_MULW) +DECLARE_INSN(divw, MATCH_DIVW, MASK_DIVW) +DECLARE_INSN(divuw, MATCH_DIVUW, MASK_DIVUW) +DECLARE_INSN(remw, MATCH_REMW, MASK_REMW) +DECLARE_INSN(remuw, MATCH_REMUW, MASK_REMUW) +DECLARE_INSN(amoadd_w, MATCH_AMOADD_W, MASK_AMOADD_W) +DECLARE_INSN(amoxor_w, MATCH_AMOXOR_W, MASK_AMOXOR_W) +DECLARE_INSN(amoor_w, MATCH_AMOOR_W, MASK_AMOOR_W) +DECLARE_INSN(amoand_w, MATCH_AMOAND_W, MASK_AMOAND_W) +DECLARE_INSN(amomin_w, MATCH_AMOMIN_W, MASK_AMOMIN_W) +DECLARE_INSN(amomax_w, MATCH_AMOMAX_W, MASK_AMOMAX_W) +DECLARE_INSN(amominu_w, MATCH_AMOMINU_W, MASK_AMOMINU_W) +DECLARE_INSN(amomaxu_w, MATCH_AMOMAXU_W, MASK_AMOMAXU_W) +DECLARE_INSN(amoswap_w, MATCH_AMOSWAP_W, MASK_AMOSWAP_W) +DECLARE_INSN(lr_w, MATCH_LR_W, MASK_LR_W) +DECLARE_INSN(sc_w, MATCH_SC_W, MASK_SC_W) +DECLARE_INSN(amoadd_d, MATCH_AMOADD_D, MASK_AMOADD_D) +DECLARE_INSN(amoxor_d, MATCH_AMOXOR_D, MASK_AMOXOR_D) +DECLARE_INSN(amoor_d, MATCH_AMOOR_D, MASK_AMOOR_D) +DECLARE_INSN(amoand_d, MATCH_AMOAND_D, MASK_AMOAND_D) +DECLARE_INSN(amomin_d, MATCH_AMOMIN_D, MASK_AMOMIN_D) +DECLARE_INSN(amomax_d, MATCH_AMOMAX_D, MASK_AMOMAX_D) +DECLARE_INSN(amominu_d, MATCH_AMOMINU_D, MASK_AMOMINU_D) +DECLARE_INSN(amomaxu_d, MATCH_AMOMAXU_D, MASK_AMOMAXU_D) +DECLARE_INSN(amoswap_d, MATCH_AMOSWAP_D, MASK_AMOSWAP_D) +DECLARE_INSN(lr_d, MATCH_LR_D, MASK_LR_D) +DECLARE_INSN(sc_d, MATCH_SC_D, MASK_SC_D) +DECLARE_INSN(hfence_vvma, MATCH_HFENCE_VVMA, MASK_HFENCE_VVMA) +DECLARE_INSN(hfence_gvma, MATCH_HFENCE_GVMA, MASK_HFENCE_GVMA) +DECLARE_INSN(hlv_b, MATCH_HLV_B, MASK_HLV_B) +DECLARE_INSN(hlv_bu, MATCH_HLV_BU, MASK_HLV_BU) +DECLARE_INSN(hlv_h, MATCH_HLV_H, MASK_HLV_H) +DECLARE_INSN(hlv_hu, MATCH_HLV_HU, MASK_HLV_HU) +DECLARE_INSN(hlvx_hu, MATCH_HLVX_HU, MASK_HLVX_HU) +DECLARE_INSN(hlv_w, MATCH_HLV_W, MASK_HLV_W) +DECLARE_INSN(hlvx_wu, MATCH_HLVX_WU, MASK_HLVX_WU) +DECLARE_INSN(hsv_b, MATCH_HSV_B, MASK_HSV_B) +DECLARE_INSN(hsv_h, MATCH_HSV_H, MASK_HSV_H) +DECLARE_INSN(hsv_w, MATCH_HSV_W, MASK_HSV_W) +DECLARE_INSN(hlv_wu, MATCH_HLV_WU, MASK_HLV_WU) +DECLARE_INSN(hlv_d, MATCH_HLV_D, MASK_HLV_D) +DECLARE_INSN(hsv_d, MATCH_HSV_D, MASK_HSV_D) +DECLARE_INSN(fadd_s, MATCH_FADD_S, MASK_FADD_S) +DECLARE_INSN(fsub_s, MATCH_FSUB_S, MASK_FSUB_S) +DECLARE_INSN(fmul_s, MATCH_FMUL_S, MASK_FMUL_S) +DECLARE_INSN(fdiv_s, MATCH_FDIV_S, MASK_FDIV_S) +DECLARE_INSN(fsgnj_s, MATCH_FSGNJ_S, MASK_FSGNJ_S) +DECLARE_INSN(fsgnjn_s, MATCH_FSGNJN_S, MASK_FSGNJN_S) +DECLARE_INSN(fsgnjx_s, MATCH_FSGNJX_S, MASK_FSGNJX_S) +DECLARE_INSN(fmin_s, MATCH_FMIN_S, MASK_FMIN_S) +DECLARE_INSN(fmax_s, MATCH_FMAX_S, MASK_FMAX_S) +DECLARE_INSN(fsqrt_s, MATCH_FSQRT_S, MASK_FSQRT_S) +DECLARE_INSN(fle_s, MATCH_FLE_S, MASK_FLE_S) +DECLARE_INSN(flt_s, MATCH_FLT_S, MASK_FLT_S) +DECLARE_INSN(feq_s, MATCH_FEQ_S, MASK_FEQ_S) +DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S) +DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S) +DECLARE_INSN(fmv_x_w, MATCH_FMV_X_W, MASK_FMV_X_W) +DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S) +DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W) +DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU) +DECLARE_INSN(fmv_w_x, MATCH_FMV_W_X, MASK_FMV_W_X) +DECLARE_INSN(flw, MATCH_FLW, MASK_FLW) +DECLARE_INSN(fsw, MATCH_FSW, MASK_FSW) +DECLARE_INSN(fmadd_s, MATCH_FMADD_S, MASK_FMADD_S) +DECLARE_INSN(fmsub_s, MATCH_FMSUB_S, MASK_FMSUB_S) +DECLARE_INSN(fnmsub_s, MATCH_FNMSUB_S, MASK_FNMSUB_S) +DECLARE_INSN(fnmadd_s, MATCH_FNMADD_S, MASK_FNMADD_S) +DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S) +DECLARE_INSN(fcvt_lu_s, MATCH_FCVT_LU_S, MASK_FCVT_LU_S) +DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L) +DECLARE_INSN(fcvt_s_lu, MATCH_FCVT_S_LU, MASK_FCVT_S_LU) +DECLARE_INSN(fadd_d, MATCH_FADD_D, MASK_FADD_D) +DECLARE_INSN(fsub_d, MATCH_FSUB_D, MASK_FSUB_D) +DECLARE_INSN(fmul_d, MATCH_FMUL_D, MASK_FMUL_D) +DECLARE_INSN(fdiv_d, MATCH_FDIV_D, MASK_FDIV_D) +DECLARE_INSN(fsgnj_d, MATCH_FSGNJ_D, MASK_FSGNJ_D) +DECLARE_INSN(fsgnjn_d, MATCH_FSGNJN_D, MASK_FSGNJN_D) +DECLARE_INSN(fsgnjx_d, MATCH_FSGNJX_D, MASK_FSGNJX_D) +DECLARE_INSN(fmin_d, MATCH_FMIN_D, MASK_FMIN_D) +DECLARE_INSN(fmax_d, MATCH_FMAX_D, MASK_FMAX_D) +DECLARE_INSN(fcvt_s_d, MATCH_FCVT_S_D, MASK_FCVT_S_D) +DECLARE_INSN(fcvt_d_s, MATCH_FCVT_D_S, MASK_FCVT_D_S) +DECLARE_INSN(fsqrt_d, MATCH_FSQRT_D, MASK_FSQRT_D) +DECLARE_INSN(fle_d, MATCH_FLE_D, MASK_FLE_D) +DECLARE_INSN(flt_d, MATCH_FLT_D, MASK_FLT_D) +DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D) +DECLARE_INSN(fcvt_w_d, MATCH_FCVT_W_D, MASK_FCVT_W_D) +DECLARE_INSN(fcvt_wu_d, MATCH_FCVT_WU_D, MASK_FCVT_WU_D) +DECLARE_INSN(fclass_d, MATCH_FCLASS_D, MASK_FCLASS_D) +DECLARE_INSN(fcvt_d_w, MATCH_FCVT_D_W, MASK_FCVT_D_W) +DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU) +DECLARE_INSN(fld, MATCH_FLD, MASK_FLD) +DECLARE_INSN(fsd, MATCH_FSD, MASK_FSD) +DECLARE_INSN(fmadd_d, MATCH_FMADD_D, MASK_FMADD_D) +DECLARE_INSN(fmsub_d, MATCH_FMSUB_D, MASK_FMSUB_D) +DECLARE_INSN(fnmsub_d, MATCH_FNMSUB_D, MASK_FNMSUB_D) +DECLARE_INSN(fnmadd_d, MATCH_FNMADD_D, MASK_FNMADD_D) +DECLARE_INSN(fcvt_l_d, MATCH_FCVT_L_D, MASK_FCVT_L_D) +DECLARE_INSN(fcvt_lu_d, MATCH_FCVT_LU_D, MASK_FCVT_LU_D) +DECLARE_INSN(fmv_x_d, MATCH_FMV_X_D, MASK_FMV_X_D) +DECLARE_INSN(fcvt_d_l, MATCH_FCVT_D_L, MASK_FCVT_D_L) +DECLARE_INSN(fcvt_d_lu, MATCH_FCVT_D_LU, MASK_FCVT_D_LU) +DECLARE_INSN(fmv_d_x, MATCH_FMV_D_X, MASK_FMV_D_X) +DECLARE_INSN(fadd_q, MATCH_FADD_Q, MASK_FADD_Q) +DECLARE_INSN(fsub_q, MATCH_FSUB_Q, MASK_FSUB_Q) +DECLARE_INSN(fmul_q, MATCH_FMUL_Q, MASK_FMUL_Q) +DECLARE_INSN(fdiv_q, MATCH_FDIV_Q, MASK_FDIV_Q) +DECLARE_INSN(fsgnj_q, MATCH_FSGNJ_Q, MASK_FSGNJ_Q) +DECLARE_INSN(fsgnjn_q, MATCH_FSGNJN_Q, MASK_FSGNJN_Q) +DECLARE_INSN(fsgnjx_q, MATCH_FSGNJX_Q, MASK_FSGNJX_Q) +DECLARE_INSN(fmin_q, MATCH_FMIN_Q, MASK_FMIN_Q) +DECLARE_INSN(fmax_q, MATCH_FMAX_Q, MASK_FMAX_Q) +DECLARE_INSN(fcvt_s_q, MATCH_FCVT_S_Q, MASK_FCVT_S_Q) +DECLARE_INSN(fcvt_q_s, MATCH_FCVT_Q_S, MASK_FCVT_Q_S) +DECLARE_INSN(fcvt_d_q, MATCH_FCVT_D_Q, MASK_FCVT_D_Q) +DECLARE_INSN(fcvt_q_d, MATCH_FCVT_Q_D, MASK_FCVT_Q_D) +DECLARE_INSN(fsqrt_q, MATCH_FSQRT_Q, MASK_FSQRT_Q) +DECLARE_INSN(fle_q, MATCH_FLE_Q, MASK_FLE_Q) +DECLARE_INSN(flt_q, MATCH_FLT_Q, MASK_FLT_Q) +DECLARE_INSN(feq_q, MATCH_FEQ_Q, MASK_FEQ_Q) +DECLARE_INSN(fcvt_w_q, MATCH_FCVT_W_Q, MASK_FCVT_W_Q) +DECLARE_INSN(fcvt_wu_q, MATCH_FCVT_WU_Q, MASK_FCVT_WU_Q) +DECLARE_INSN(fclass_q, MATCH_FCLASS_Q, MASK_FCLASS_Q) +DECLARE_INSN(fcvt_q_w, MATCH_FCVT_Q_W, MASK_FCVT_Q_W) +DECLARE_INSN(fcvt_q_wu, MATCH_FCVT_Q_WU, MASK_FCVT_Q_WU) +DECLARE_INSN(flq, MATCH_FLQ, MASK_FLQ) +DECLARE_INSN(fsq, MATCH_FSQ, MASK_FSQ) +DECLARE_INSN(fmadd_q, MATCH_FMADD_Q, MASK_FMADD_Q) +DECLARE_INSN(fmsub_q, MATCH_FMSUB_Q, MASK_FMSUB_Q) +DECLARE_INSN(fnmsub_q, MATCH_FNMSUB_Q, MASK_FNMSUB_Q) +DECLARE_INSN(fnmadd_q, MATCH_FNMADD_Q, MASK_FNMADD_Q) +DECLARE_INSN(fcvt_l_q, MATCH_FCVT_L_Q, MASK_FCVT_L_Q) +DECLARE_INSN(fcvt_lu_q, MATCH_FCVT_LU_Q, MASK_FCVT_LU_Q) +DECLARE_INSN(fcvt_q_l, MATCH_FCVT_Q_L, MASK_FCVT_Q_L) +DECLARE_INSN(fcvt_q_lu, MATCH_FCVT_Q_LU, MASK_FCVT_Q_LU) +DECLARE_INSN(andn, MATCH_ANDN, MASK_ANDN) +DECLARE_INSN(orn, MATCH_ORN, MASK_ORN) +DECLARE_INSN(xnor, MATCH_XNOR, MASK_XNOR) +DECLARE_INSN(slo, MATCH_SLO, MASK_SLO) +DECLARE_INSN(sro, MATCH_SRO, MASK_SRO) +DECLARE_INSN(rol, MATCH_ROL, MASK_ROL) +DECLARE_INSN(ror, MATCH_ROR, MASK_ROR) +DECLARE_INSN(bclr, MATCH_BCLR, MASK_BCLR) +DECLARE_INSN(bset, MATCH_BSET, MASK_BSET) +DECLARE_INSN(binv, MATCH_BINV, MASK_BINV) +DECLARE_INSN(bext, MATCH_BEXT, MASK_BEXT) +DECLARE_INSN(gorc, MATCH_GORC, MASK_GORC) +DECLARE_INSN(grev, MATCH_GREV, MASK_GREV) +DECLARE_INSN(sloi, MATCH_SLOI, MASK_SLOI) +DECLARE_INSN(sroi, MATCH_SROI, MASK_SROI) +DECLARE_INSN(rori, MATCH_RORI, MASK_RORI) +DECLARE_INSN(bclri, MATCH_BCLRI, MASK_BCLRI) +DECLARE_INSN(bseti, MATCH_BSETI, MASK_BSETI) +DECLARE_INSN(binvi, MATCH_BINVI, MASK_BINVI) +DECLARE_INSN(bexti, MATCH_BEXTI, MASK_BEXTI) +DECLARE_INSN(gorci, MATCH_GORCI, MASK_GORCI) +DECLARE_INSN(grevi, MATCH_GREVI, MASK_GREVI) +DECLARE_INSN(cmix, MATCH_CMIX, MASK_CMIX) +DECLARE_INSN(cmov, MATCH_CMOV, MASK_CMOV) +DECLARE_INSN(fsl, MATCH_FSL, MASK_FSL) +DECLARE_INSN(fsr, MATCH_FSR, MASK_FSR) +DECLARE_INSN(fsri, MATCH_FSRI, MASK_FSRI) +DECLARE_INSN(clz, MATCH_CLZ, MASK_CLZ) +DECLARE_INSN(ctz, MATCH_CTZ, MASK_CTZ) +DECLARE_INSN(cpop, MATCH_CPOP, MASK_CPOP) +DECLARE_INSN(sext_b, MATCH_SEXT_B, MASK_SEXT_B) +DECLARE_INSN(sext_h, MATCH_SEXT_H, MASK_SEXT_H) +DECLARE_INSN(crc32_b, MATCH_CRC32_B, MASK_CRC32_B) +DECLARE_INSN(crc32_h, MATCH_CRC32_H, MASK_CRC32_H) +DECLARE_INSN(crc32_w, MATCH_CRC32_W, MASK_CRC32_W) +DECLARE_INSN(crc32c_b, MATCH_CRC32C_B, MASK_CRC32C_B) +DECLARE_INSN(crc32c_h, MATCH_CRC32C_H, MASK_CRC32C_H) +DECLARE_INSN(crc32c_w, MATCH_CRC32C_W, MASK_CRC32C_W) +DECLARE_INSN(sh1add, MATCH_SH1ADD, MASK_SH1ADD) +DECLARE_INSN(sh2add, MATCH_SH2ADD, MASK_SH2ADD) +DECLARE_INSN(sh3add, MATCH_SH3ADD, MASK_SH3ADD) +DECLARE_INSN(clmul, MATCH_CLMUL, MASK_CLMUL) +DECLARE_INSN(clmulr, MATCH_CLMULR, MASK_CLMULR) +DECLARE_INSN(clmulh, MATCH_CLMULH, MASK_CLMULH) +DECLARE_INSN(min, MATCH_MIN, MASK_MIN) +DECLARE_INSN(minu, MATCH_MINU, MASK_MINU) +DECLARE_INSN(max, MATCH_MAX, MASK_MAX) +DECLARE_INSN(maxu, MATCH_MAXU, MASK_MAXU) +DECLARE_INSN(shfl, MATCH_SHFL, MASK_SHFL) +DECLARE_INSN(unshfl, MATCH_UNSHFL, MASK_UNSHFL) +DECLARE_INSN(bcompress, MATCH_BCOMPRESS, MASK_BCOMPRESS) +DECLARE_INSN(bdecompress, MATCH_BDECOMPRESS, MASK_BDECOMPRESS) +DECLARE_INSN(pack, MATCH_PACK, MASK_PACK) +DECLARE_INSN(packu, MATCH_PACKU, MASK_PACKU) +DECLARE_INSN(packh, MATCH_PACKH, MASK_PACKH) +DECLARE_INSN(bfp, MATCH_BFP, MASK_BFP) +DECLARE_INSN(shfli, MATCH_SHFLI, MASK_SHFLI) +DECLARE_INSN(unshfli, MATCH_UNSHFLI, MASK_UNSHFLI) +DECLARE_INSN(xperm_n, MATCH_XPERM_N, MASK_XPERM_N) +DECLARE_INSN(xperm_b, MATCH_XPERM_B, MASK_XPERM_B) +DECLARE_INSN(xperm_h, MATCH_XPERM_H, MASK_XPERM_H) +DECLARE_INSN(bmatflip, MATCH_BMATFLIP, MASK_BMATFLIP) +DECLARE_INSN(crc32_d, MATCH_CRC32_D, MASK_CRC32_D) +DECLARE_INSN(crc32c_d, MATCH_CRC32C_D, MASK_CRC32C_D) +DECLARE_INSN(bmator, MATCH_BMATOR, MASK_BMATOR) +DECLARE_INSN(bmatxor, MATCH_BMATXOR, MASK_BMATXOR) +DECLARE_INSN(slli_uw, MATCH_SLLI_UW, MASK_SLLI_UW) +DECLARE_INSN(add_uw, MATCH_ADD_UW, MASK_ADD_UW) +DECLARE_INSN(slow, MATCH_SLOW, MASK_SLOW) +DECLARE_INSN(srow, MATCH_SROW, MASK_SROW) +DECLARE_INSN(rolw, MATCH_ROLW, MASK_ROLW) +DECLARE_INSN(rorw, MATCH_RORW, MASK_RORW) +DECLARE_INSN(sbclrw, MATCH_SBCLRW, MASK_SBCLRW) +DECLARE_INSN(sbsetw, MATCH_SBSETW, MASK_SBSETW) +DECLARE_INSN(sbinvw, MATCH_SBINVW, MASK_SBINVW) +DECLARE_INSN(sbextw, MATCH_SBEXTW, MASK_SBEXTW) +DECLARE_INSN(gorcw, MATCH_GORCW, MASK_GORCW) +DECLARE_INSN(grevw, MATCH_GREVW, MASK_GREVW) +DECLARE_INSN(sloiw, MATCH_SLOIW, MASK_SLOIW) +DECLARE_INSN(sroiw, MATCH_SROIW, MASK_SROIW) +DECLARE_INSN(roriw, MATCH_RORIW, MASK_RORIW) +DECLARE_INSN(sbclriw, MATCH_SBCLRIW, MASK_SBCLRIW) +DECLARE_INSN(sbsetiw, MATCH_SBSETIW, MASK_SBSETIW) +DECLARE_INSN(sbinviw, MATCH_SBINVIW, MASK_SBINVIW) +DECLARE_INSN(gorciw, MATCH_GORCIW, MASK_GORCIW) +DECLARE_INSN(greviw, MATCH_GREVIW, MASK_GREVIW) +DECLARE_INSN(fslw, MATCH_FSLW, MASK_FSLW) +DECLARE_INSN(fsrw, MATCH_FSRW, MASK_FSRW) +DECLARE_INSN(fsriw, MATCH_FSRIW, MASK_FSRIW) +DECLARE_INSN(clzw, MATCH_CLZW, MASK_CLZW) +DECLARE_INSN(ctzw, MATCH_CTZW, MASK_CTZW) +DECLARE_INSN(cpopw, MATCH_CPOPW, MASK_CPOPW) +DECLARE_INSN(sh1add_uw, MATCH_SH1ADD_UW, MASK_SH1ADD_UW) +DECLARE_INSN(sh2add_uw, MATCH_SH2ADD_UW, MASK_SH2ADD_UW) +DECLARE_INSN(sh3add_uw, MATCH_SH3ADD_UW, MASK_SH3ADD_UW) +DECLARE_INSN(shflw, MATCH_SHFLW, MASK_SHFLW) +DECLARE_INSN(unshflw, MATCH_UNSHFLW, MASK_UNSHFLW) +DECLARE_INSN(bcompressw, MATCH_BCOMPRESSW, MASK_BCOMPRESSW) +DECLARE_INSN(bdecompressw, MATCH_BDECOMPRESSW, MASK_BDECOMPRESSW) +DECLARE_INSN(packw, MATCH_PACKW, MASK_PACKW) +DECLARE_INSN(packuw, MATCH_PACKUW, MASK_PACKUW) +DECLARE_INSN(bfpw, MATCH_BFPW, MASK_BFPW) +DECLARE_INSN(xperm_w, MATCH_XPERM_W, MASK_XPERM_W) +DECLARE_INSN(ecall, MATCH_ECALL, MASK_ECALL) +DECLARE_INSN(ebreak, MATCH_EBREAK, MASK_EBREAK) +DECLARE_INSN(uret, MATCH_URET, MASK_URET) +DECLARE_INSN(sret, MATCH_SRET, MASK_SRET) +DECLARE_INSN(mret, MATCH_MRET, MASK_MRET) +DECLARE_INSN(dret, MATCH_DRET, MASK_DRET) +DECLARE_INSN(sfence_vma, MATCH_SFENCE_VMA, MASK_SFENCE_VMA) +DECLARE_INSN(wfi, MATCH_WFI, MASK_WFI) +DECLARE_INSN(csrrw, MATCH_CSRRW, MASK_CSRRW) +DECLARE_INSN(csrrs, MATCH_CSRRS, MASK_CSRRS) +DECLARE_INSN(csrrc, MATCH_CSRRC, MASK_CSRRC) +DECLARE_INSN(csrrwi, MATCH_CSRRWI, MASK_CSRRWI) +DECLARE_INSN(csrrsi, MATCH_CSRRSI, MASK_CSRRSI) +DECLARE_INSN(csrrci, MATCH_CSRRCI, MASK_CSRRCI) +DECLARE_INSN(fadd_h, MATCH_FADD_H, MASK_FADD_H) +DECLARE_INSN(fsub_h, MATCH_FSUB_H, MASK_FSUB_H) +DECLARE_INSN(fmul_h, MATCH_FMUL_H, MASK_FMUL_H) +DECLARE_INSN(fdiv_h, MATCH_FDIV_H, MASK_FDIV_H) +DECLARE_INSN(fsgnj_h, MATCH_FSGNJ_H, MASK_FSGNJ_H) +DECLARE_INSN(fsgnjn_h, MATCH_FSGNJN_H, MASK_FSGNJN_H) +DECLARE_INSN(fsgnjx_h, MATCH_FSGNJX_H, MASK_FSGNJX_H) +DECLARE_INSN(fmin_h, MATCH_FMIN_H, MASK_FMIN_H) +DECLARE_INSN(fmax_h, MATCH_FMAX_H, MASK_FMAX_H) +DECLARE_INSN(fcvt_h_s, MATCH_FCVT_H_S, MASK_FCVT_H_S) +DECLARE_INSN(fcvt_s_h, MATCH_FCVT_S_H, MASK_FCVT_S_H) +DECLARE_INSN(fsqrt_h, MATCH_FSQRT_H, MASK_FSQRT_H) +DECLARE_INSN(fle_h, MATCH_FLE_H, MASK_FLE_H) +DECLARE_INSN(flt_h, MATCH_FLT_H, MASK_FLT_H) +DECLARE_INSN(feq_h, MATCH_FEQ_H, MASK_FEQ_H) +DECLARE_INSN(fcvt_w_h, MATCH_FCVT_W_H, MASK_FCVT_W_H) +DECLARE_INSN(fcvt_wu_h, MATCH_FCVT_WU_H, MASK_FCVT_WU_H) +DECLARE_INSN(fmv_x_h, MATCH_FMV_X_H, MASK_FMV_X_H) +DECLARE_INSN(fclass_h, MATCH_FCLASS_H, MASK_FCLASS_H) +DECLARE_INSN(fcvt_h_w, MATCH_FCVT_H_W, MASK_FCVT_H_W) +DECLARE_INSN(fcvt_h_wu, MATCH_FCVT_H_WU, MASK_FCVT_H_WU) +DECLARE_INSN(fmv_h_x, MATCH_FMV_H_X, MASK_FMV_H_X) +DECLARE_INSN(flh, MATCH_FLH, MASK_FLH) +DECLARE_INSN(fsh, MATCH_FSH, MASK_FSH) +DECLARE_INSN(fmadd_h, MATCH_FMADD_H, MASK_FMADD_H) +DECLARE_INSN(fmsub_h, MATCH_FMSUB_H, MASK_FMSUB_H) +DECLARE_INSN(fnmsub_h, MATCH_FNMSUB_H, MASK_FNMSUB_H) +DECLARE_INSN(fnmadd_h, MATCH_FNMADD_H, MASK_FNMADD_H) +DECLARE_INSN(fcvt_h_d, MATCH_FCVT_H_D, MASK_FCVT_H_D) +DECLARE_INSN(fcvt_d_h, MATCH_FCVT_D_H, MASK_FCVT_D_H) +DECLARE_INSN(fcvt_h_q, MATCH_FCVT_H_Q, MASK_FCVT_H_Q) +DECLARE_INSN(fcvt_q_h, MATCH_FCVT_Q_H, MASK_FCVT_Q_H) +DECLARE_INSN(fcvt_l_h, MATCH_FCVT_L_H, MASK_FCVT_L_H) +DECLARE_INSN(fcvt_lu_h, MATCH_FCVT_LU_H, MASK_FCVT_LU_H) +DECLARE_INSN(fcvt_h_l, MATCH_FCVT_H_L, MASK_FCVT_H_L) +DECLARE_INSN(fcvt_h_lu, MATCH_FCVT_H_LU, MASK_FCVT_H_LU) +DECLARE_INSN(pollentropy, MATCH_POLLENTROPY, MASK_POLLENTROPY) +DECLARE_INSN(getnoise, MATCH_GETNOISE, MASK_GETNOISE) +DECLARE_INSN(sm4ed, MATCH_SM4ED, MASK_SM4ED) +DECLARE_INSN(sm4ks, MATCH_SM4KS, MASK_SM4KS) +DECLARE_INSN(sm3p0, MATCH_SM3P0, MASK_SM3P0) +DECLARE_INSN(sm3p1, MATCH_SM3P1, MASK_SM3P1) +DECLARE_INSN(sha256sum0, MATCH_SHA256SUM0, MASK_SHA256SUM0) +DECLARE_INSN(sha256sum1, MATCH_SHA256SUM1, MASK_SHA256SUM1) +DECLARE_INSN(sha256sig0, MATCH_SHA256SIG0, MASK_SHA256SIG0) +DECLARE_INSN(sha256sig1, MATCH_SHA256SIG1, MASK_SHA256SIG1) +DECLARE_INSN(aes32esmi, MATCH_AES32ESMI, MASK_AES32ESMI) +DECLARE_INSN(aes32esi, MATCH_AES32ESI, MASK_AES32ESI) +DECLARE_INSN(aes32dsmi, MATCH_AES32DSMI, MASK_AES32DSMI) +DECLARE_INSN(aes32dsi, MATCH_AES32DSI, MASK_AES32DSI) +DECLARE_INSN(sha512sum0r, MATCH_SHA512SUM0R, MASK_SHA512SUM0R) +DECLARE_INSN(sha512sum1r, MATCH_SHA512SUM1R, MASK_SHA512SUM1R) +DECLARE_INSN(sha512sig0l, MATCH_SHA512SIG0L, MASK_SHA512SIG0L) +DECLARE_INSN(sha512sig0h, MATCH_SHA512SIG0H, MASK_SHA512SIG0H) +DECLARE_INSN(sha512sig1l, MATCH_SHA512SIG1L, MASK_SHA512SIG1L) +DECLARE_INSN(sha512sig1h, MATCH_SHA512SIG1H, MASK_SHA512SIG1H) +DECLARE_INSN(aes64ks1i, MATCH_AES64KS1I, MASK_AES64KS1I) +DECLARE_INSN(aes64im, MATCH_AES64IM, MASK_AES64IM) +DECLARE_INSN(aes64ks2, MATCH_AES64KS2, MASK_AES64KS2) +DECLARE_INSN(aes64esm, MATCH_AES64ESM, MASK_AES64ESM) +DECLARE_INSN(aes64es, MATCH_AES64ES, MASK_AES64ES) +DECLARE_INSN(aes64dsm, MATCH_AES64DSM, MASK_AES64DSM) +DECLARE_INSN(aes64ds, MATCH_AES64DS, MASK_AES64DS) +DECLARE_INSN(sha512sum0, MATCH_SHA512SUM0, MASK_SHA512SUM0) +DECLARE_INSN(sha512sum1, MATCH_SHA512SUM1, MASK_SHA512SUM1) +DECLARE_INSN(sha512sig0, MATCH_SHA512SIG0, MASK_SHA512SIG0) +DECLARE_INSN(sha512sig1, MATCH_SHA512SIG1, MASK_SHA512SIG1) +DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP) +DECLARE_INSN(c_addi16sp, MATCH_C_ADDI16SP, MASK_C_ADDI16SP) +DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR) +DECLARE_INSN(c_jalr, MATCH_C_JALR, MASK_C_JALR) +DECLARE_INSN(c_ebreak, MATCH_C_EBREAK, MASK_C_EBREAK) +DECLARE_INSN(c_addi4spn, MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN) +DECLARE_INSN(c_fld, MATCH_C_FLD, MASK_C_FLD) +DECLARE_INSN(c_lw, MATCH_C_LW, MASK_C_LW) +DECLARE_INSN(c_flw, MATCH_C_FLW, MASK_C_FLW) +DECLARE_INSN(c_fsd, MATCH_C_FSD, MASK_C_FSD) +DECLARE_INSN(c_sw, MATCH_C_SW, MASK_C_SW) +DECLARE_INSN(c_fsw, MATCH_C_FSW, MASK_C_FSW) +DECLARE_INSN(c_addi, MATCH_C_ADDI, MASK_C_ADDI) +DECLARE_INSN(c_jal, MATCH_C_JAL, MASK_C_JAL) +DECLARE_INSN(c_li, MATCH_C_LI, MASK_C_LI) +DECLARE_INSN(c_lui, MATCH_C_LUI, MASK_C_LUI) +DECLARE_INSN(c_srli, MATCH_C_SRLI, MASK_C_SRLI) +DECLARE_INSN(c_srai, MATCH_C_SRAI, MASK_C_SRAI) +DECLARE_INSN(c_andi, MATCH_C_ANDI, MASK_C_ANDI) +DECLARE_INSN(c_sub, MATCH_C_SUB, MASK_C_SUB) +DECLARE_INSN(c_xor, MATCH_C_XOR, MASK_C_XOR) +DECLARE_INSN(c_or, MATCH_C_OR, MASK_C_OR) +DECLARE_INSN(c_and, MATCH_C_AND, MASK_C_AND) +DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J) +DECLARE_INSN(c_beqz, MATCH_C_BEQZ, MASK_C_BEQZ) +DECLARE_INSN(c_bnez, MATCH_C_BNEZ, MASK_C_BNEZ) +DECLARE_INSN(c_slli, MATCH_C_SLLI, MASK_C_SLLI) +DECLARE_INSN(c_fldsp, MATCH_C_FLDSP, MASK_C_FLDSP) +DECLARE_INSN(c_lwsp, MATCH_C_LWSP, MASK_C_LWSP) +DECLARE_INSN(c_flwsp, MATCH_C_FLWSP, MASK_C_FLWSP) +DECLARE_INSN(c_mv, MATCH_C_MV, MASK_C_MV) +DECLARE_INSN(c_add, MATCH_C_ADD, MASK_C_ADD) +DECLARE_INSN(c_fsdsp, MATCH_C_FSDSP, MASK_C_FSDSP) +DECLARE_INSN(c_swsp, MATCH_C_SWSP, MASK_C_SWSP) +DECLARE_INSN(c_fswsp, MATCH_C_FSWSP, MASK_C_FSWSP) +DECLARE_INSN(c_srli_rv32, MATCH_C_SRLI_RV32, MASK_C_SRLI_RV32) +DECLARE_INSN(c_srai_rv32, MATCH_C_SRAI_RV32, MASK_C_SRAI_RV32) +DECLARE_INSN(c_slli_rv32, MATCH_C_SLLI_RV32, MASK_C_SLLI_RV32) +DECLARE_INSN(c_ld, MATCH_C_LD, MASK_C_LD) +DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD) +DECLARE_INSN(c_subw, MATCH_C_SUBW, MASK_C_SUBW) +DECLARE_INSN(c_addw, MATCH_C_ADDW, MASK_C_ADDW) +DECLARE_INSN(c_addiw, MATCH_C_ADDIW, MASK_C_ADDIW) +DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP) +DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP) +DECLARE_INSN(custom0, MATCH_CUSTOM0, MASK_CUSTOM0) +DECLARE_INSN(custom0_rs1, MATCH_CUSTOM0_RS1, MASK_CUSTOM0_RS1) +DECLARE_INSN(custom0_rs1_rs2, MATCH_CUSTOM0_RS1_RS2, MASK_CUSTOM0_RS1_RS2) +DECLARE_INSN(custom0_rd, MATCH_CUSTOM0_RD, MASK_CUSTOM0_RD) +DECLARE_INSN(custom0_rd_rs1, MATCH_CUSTOM0_RD_RS1, MASK_CUSTOM0_RD_RS1) +DECLARE_INSN(custom0_rd_rs1_rs2, MATCH_CUSTOM0_RD_RS1_RS2, MASK_CUSTOM0_RD_RS1_RS2) +DECLARE_INSN(custom1, MATCH_CUSTOM1, MASK_CUSTOM1) +DECLARE_INSN(custom1_rs1, MATCH_CUSTOM1_RS1, MASK_CUSTOM1_RS1) +DECLARE_INSN(custom1_rs1_rs2, MATCH_CUSTOM1_RS1_RS2, MASK_CUSTOM1_RS1_RS2) +DECLARE_INSN(custom1_rd, MATCH_CUSTOM1_RD, MASK_CUSTOM1_RD) +DECLARE_INSN(custom1_rd_rs1, MATCH_CUSTOM1_RD_RS1, MASK_CUSTOM1_RD_RS1) +DECLARE_INSN(custom1_rd_rs1_rs2, MATCH_CUSTOM1_RD_RS1_RS2, MASK_CUSTOM1_RD_RS1_RS2) +DECLARE_INSN(custom2, MATCH_CUSTOM2, MASK_CUSTOM2) +DECLARE_INSN(custom2_rs1, MATCH_CUSTOM2_RS1, MASK_CUSTOM2_RS1) +DECLARE_INSN(custom2_rs1_rs2, MATCH_CUSTOM2_RS1_RS2, MASK_CUSTOM2_RS1_RS2) +DECLARE_INSN(custom2_rd, MATCH_CUSTOM2_RD, MASK_CUSTOM2_RD) +DECLARE_INSN(custom2_rd_rs1, MATCH_CUSTOM2_RD_RS1, MASK_CUSTOM2_RD_RS1) +DECLARE_INSN(custom2_rd_rs1_rs2, MATCH_CUSTOM2_RD_RS1_RS2, MASK_CUSTOM2_RD_RS1_RS2) +DECLARE_INSN(custom3, MATCH_CUSTOM3, MASK_CUSTOM3) +DECLARE_INSN(custom3_rs1, MATCH_CUSTOM3_RS1, MASK_CUSTOM3_RS1) +DECLARE_INSN(custom3_rs1_rs2, MATCH_CUSTOM3_RS1_RS2, MASK_CUSTOM3_RS1_RS2) +DECLARE_INSN(custom3_rd, MATCH_CUSTOM3_RD, MASK_CUSTOM3_RD) +DECLARE_INSN(custom3_rd_rs1, MATCH_CUSTOM3_RD_RS1, MASK_CUSTOM3_RD_RS1) +DECLARE_INSN(custom3_rd_rs1_rs2, MATCH_CUSTOM3_RD_RS1_RS2, MASK_CUSTOM3_RD_RS1_RS2) +DECLARE_INSN(vsetivli, MATCH_VSETIVLI, MASK_VSETIVLI) +DECLARE_INSN(vsetvli, MATCH_VSETVLI, MASK_VSETVLI) +DECLARE_INSN(vsetvl, MATCH_VSETVL, MASK_VSETVL) +DECLARE_INSN(vle1_v, MATCH_VLE1_V, MASK_VLE1_V) +DECLARE_INSN(vse1_v, MATCH_VSE1_V, MASK_VSE1_V) +DECLARE_INSN(vle8_v, MATCH_VLE8_V, MASK_VLE8_V) +DECLARE_INSN(vle16_v, MATCH_VLE16_V, MASK_VLE16_V) +DECLARE_INSN(vle32_v, MATCH_VLE32_V, MASK_VLE32_V) +DECLARE_INSN(vle64_v, MATCH_VLE64_V, MASK_VLE64_V) +DECLARE_INSN(vle128_v, MATCH_VLE128_V, MASK_VLE128_V) +DECLARE_INSN(vle256_v, MATCH_VLE256_V, MASK_VLE256_V) +DECLARE_INSN(vle512_v, MATCH_VLE512_V, MASK_VLE512_V) +DECLARE_INSN(vle1024_v, MATCH_VLE1024_V, MASK_VLE1024_V) +DECLARE_INSN(vse8_v, MATCH_VSE8_V, MASK_VSE8_V) +DECLARE_INSN(vse16_v, MATCH_VSE16_V, MASK_VSE16_V) +DECLARE_INSN(vse32_v, MATCH_VSE32_V, MASK_VSE32_V) +DECLARE_INSN(vse64_v, MATCH_VSE64_V, MASK_VSE64_V) +DECLARE_INSN(vse128_v, MATCH_VSE128_V, MASK_VSE128_V) +DECLARE_INSN(vse256_v, MATCH_VSE256_V, MASK_VSE256_V) +DECLARE_INSN(vse512_v, MATCH_VSE512_V, MASK_VSE512_V) +DECLARE_INSN(vse1024_v, MATCH_VSE1024_V, MASK_VSE1024_V) +DECLARE_INSN(vluxei8_v, MATCH_VLUXEI8_V, MASK_VLUXEI8_V) +DECLARE_INSN(vluxei16_v, MATCH_VLUXEI16_V, MASK_VLUXEI16_V) +DECLARE_INSN(vluxei32_v, MATCH_VLUXEI32_V, MASK_VLUXEI32_V) +DECLARE_INSN(vluxei64_v, MATCH_VLUXEI64_V, MASK_VLUXEI64_V) +DECLARE_INSN(vluxei128_v, MATCH_VLUXEI128_V, MASK_VLUXEI128_V) +DECLARE_INSN(vluxei256_v, MATCH_VLUXEI256_V, MASK_VLUXEI256_V) +DECLARE_INSN(vluxei512_v, MATCH_VLUXEI512_V, MASK_VLUXEI512_V) +DECLARE_INSN(vluxei1024_v, MATCH_VLUXEI1024_V, MASK_VLUXEI1024_V) +DECLARE_INSN(vsuxei8_v, MATCH_VSUXEI8_V, MASK_VSUXEI8_V) +DECLARE_INSN(vsuxei16_v, MATCH_VSUXEI16_V, MASK_VSUXEI16_V) +DECLARE_INSN(vsuxei32_v, MATCH_VSUXEI32_V, MASK_VSUXEI32_V) +DECLARE_INSN(vsuxei64_v, MATCH_VSUXEI64_V, MASK_VSUXEI64_V) +DECLARE_INSN(vsuxei128_v, MATCH_VSUXEI128_V, MASK_VSUXEI128_V) +DECLARE_INSN(vsuxei256_v, MATCH_VSUXEI256_V, MASK_VSUXEI256_V) +DECLARE_INSN(vsuxei512_v, MATCH_VSUXEI512_V, MASK_VSUXEI512_V) +DECLARE_INSN(vsuxei1024_v, MATCH_VSUXEI1024_V, MASK_VSUXEI1024_V) +DECLARE_INSN(vlse8_v, MATCH_VLSE8_V, MASK_VLSE8_V) +DECLARE_INSN(vlse16_v, MATCH_VLSE16_V, MASK_VLSE16_V) +DECLARE_INSN(vlse32_v, MATCH_VLSE32_V, MASK_VLSE32_V) +DECLARE_INSN(vlse64_v, MATCH_VLSE64_V, MASK_VLSE64_V) +DECLARE_INSN(vlse128_v, MATCH_VLSE128_V, MASK_VLSE128_V) +DECLARE_INSN(vlse256_v, MATCH_VLSE256_V, MASK_VLSE256_V) +DECLARE_INSN(vlse512_v, MATCH_VLSE512_V, MASK_VLSE512_V) +DECLARE_INSN(vlse1024_v, MATCH_VLSE1024_V, MASK_VLSE1024_V) +DECLARE_INSN(vsse8_v, MATCH_VSSE8_V, MASK_VSSE8_V) +DECLARE_INSN(vsse16_v, MATCH_VSSE16_V, MASK_VSSE16_V) +DECLARE_INSN(vsse32_v, MATCH_VSSE32_V, MASK_VSSE32_V) +DECLARE_INSN(vsse64_v, MATCH_VSSE64_V, MASK_VSSE64_V) +DECLARE_INSN(vsse128_v, MATCH_VSSE128_V, MASK_VSSE128_V) +DECLARE_INSN(vsse256_v, MATCH_VSSE256_V, MASK_VSSE256_V) +DECLARE_INSN(vsse512_v, MATCH_VSSE512_V, MASK_VSSE512_V) +DECLARE_INSN(vsse1024_v, MATCH_VSSE1024_V, MASK_VSSE1024_V) +DECLARE_INSN(vloxei8_v, MATCH_VLOXEI8_V, MASK_VLOXEI8_V) +DECLARE_INSN(vloxei16_v, MATCH_VLOXEI16_V, MASK_VLOXEI16_V) +DECLARE_INSN(vloxei32_v, MATCH_VLOXEI32_V, MASK_VLOXEI32_V) +DECLARE_INSN(vloxei64_v, MATCH_VLOXEI64_V, MASK_VLOXEI64_V) +DECLARE_INSN(vloxei128_v, MATCH_VLOXEI128_V, MASK_VLOXEI128_V) +DECLARE_INSN(vloxei256_v, MATCH_VLOXEI256_V, MASK_VLOXEI256_V) +DECLARE_INSN(vloxei512_v, MATCH_VLOXEI512_V, MASK_VLOXEI512_V) +DECLARE_INSN(vloxei1024_v, MATCH_VLOXEI1024_V, MASK_VLOXEI1024_V) +DECLARE_INSN(vsoxei8_v, MATCH_VSOXEI8_V, MASK_VSOXEI8_V) +DECLARE_INSN(vsoxei16_v, MATCH_VSOXEI16_V, MASK_VSOXEI16_V) +DECLARE_INSN(vsoxei32_v, MATCH_VSOXEI32_V, MASK_VSOXEI32_V) +DECLARE_INSN(vsoxei64_v, MATCH_VSOXEI64_V, MASK_VSOXEI64_V) +DECLARE_INSN(vsoxei128_v, MATCH_VSOXEI128_V, MASK_VSOXEI128_V) +DECLARE_INSN(vsoxei256_v, MATCH_VSOXEI256_V, MASK_VSOXEI256_V) +DECLARE_INSN(vsoxei512_v, MATCH_VSOXEI512_V, MASK_VSOXEI512_V) +DECLARE_INSN(vsoxei1024_v, MATCH_VSOXEI1024_V, MASK_VSOXEI1024_V) +DECLARE_INSN(vle8ff_v, MATCH_VLE8FF_V, MASK_VLE8FF_V) +DECLARE_INSN(vle16ff_v, MATCH_VLE16FF_V, MASK_VLE16FF_V) +DECLARE_INSN(vle32ff_v, MATCH_VLE32FF_V, MASK_VLE32FF_V) +DECLARE_INSN(vle64ff_v, MATCH_VLE64FF_V, MASK_VLE64FF_V) +DECLARE_INSN(vle128ff_v, MATCH_VLE128FF_V, MASK_VLE128FF_V) +DECLARE_INSN(vle256ff_v, MATCH_VLE256FF_V, MASK_VLE256FF_V) +DECLARE_INSN(vle512ff_v, MATCH_VLE512FF_V, MASK_VLE512FF_V) +DECLARE_INSN(vle1024ff_v, MATCH_VLE1024FF_V, MASK_VLE1024FF_V) +DECLARE_INSN(vl1re8_v, MATCH_VL1RE8_V, MASK_VL1RE8_V) +DECLARE_INSN(vl1re16_v, MATCH_VL1RE16_V, MASK_VL1RE16_V) +DECLARE_INSN(vl1re32_v, MATCH_VL1RE32_V, MASK_VL1RE32_V) +DECLARE_INSN(vl1re64_v, MATCH_VL1RE64_V, MASK_VL1RE64_V) +DECLARE_INSN(vl2re8_v, MATCH_VL2RE8_V, MASK_VL2RE8_V) +DECLARE_INSN(vl2re16_v, MATCH_VL2RE16_V, MASK_VL2RE16_V) +DECLARE_INSN(vl2re32_v, MATCH_VL2RE32_V, MASK_VL2RE32_V) +DECLARE_INSN(vl2re64_v, MATCH_VL2RE64_V, MASK_VL2RE64_V) +DECLARE_INSN(vl4re8_v, MATCH_VL4RE8_V, MASK_VL4RE8_V) +DECLARE_INSN(vl4re16_v, MATCH_VL4RE16_V, MASK_VL4RE16_V) +DECLARE_INSN(vl4re32_v, MATCH_VL4RE32_V, MASK_VL4RE32_V) +DECLARE_INSN(vl4re64_v, MATCH_VL4RE64_V, MASK_VL4RE64_V) +DECLARE_INSN(vl8re8_v, MATCH_VL8RE8_V, MASK_VL8RE8_V) +DECLARE_INSN(vl8re16_v, MATCH_VL8RE16_V, MASK_VL8RE16_V) +DECLARE_INSN(vl8re32_v, MATCH_VL8RE32_V, MASK_VL8RE32_V) +DECLARE_INSN(vl8re64_v, MATCH_VL8RE64_V, MASK_VL8RE64_V) +DECLARE_INSN(vs1r_v, MATCH_VS1R_V, MASK_VS1R_V) +DECLARE_INSN(vs2r_v, MATCH_VS2R_V, MASK_VS2R_V) +DECLARE_INSN(vs4r_v, MATCH_VS4R_V, MASK_VS4R_V) +DECLARE_INSN(vs8r_v, MATCH_VS8R_V, MASK_VS8R_V) +DECLARE_INSN(vfadd_vf, MATCH_VFADD_VF, MASK_VFADD_VF) +DECLARE_INSN(vfsub_vf, MATCH_VFSUB_VF, MASK_VFSUB_VF) +DECLARE_INSN(vfmin_vf, MATCH_VFMIN_VF, MASK_VFMIN_VF) +DECLARE_INSN(vfmax_vf, MATCH_VFMAX_VF, MASK_VFMAX_VF) +DECLARE_INSN(vfsgnj_vf, MATCH_VFSGNJ_VF, MASK_VFSGNJ_VF) +DECLARE_INSN(vfsgnjn_vf, MATCH_VFSGNJN_VF, MASK_VFSGNJN_VF) +DECLARE_INSN(vfsgnjx_vf, MATCH_VFSGNJX_VF, MASK_VFSGNJX_VF) +DECLARE_INSN(vfslide1up_vf, MATCH_VFSLIDE1UP_VF, MASK_VFSLIDE1UP_VF) +DECLARE_INSN(vfslide1down_vf, MATCH_VFSLIDE1DOWN_VF, MASK_VFSLIDE1DOWN_VF) +DECLARE_INSN(vfmv_s_f, MATCH_VFMV_S_F, MASK_VFMV_S_F) +DECLARE_INSN(vfmerge_vfm, MATCH_VFMERGE_VFM, MASK_VFMERGE_VFM) +DECLARE_INSN(vfmv_v_f, MATCH_VFMV_V_F, MASK_VFMV_V_F) +DECLARE_INSN(vmfeq_vf, MATCH_VMFEQ_VF, MASK_VMFEQ_VF) +DECLARE_INSN(vmfle_vf, MATCH_VMFLE_VF, MASK_VMFLE_VF) +DECLARE_INSN(vmflt_vf, MATCH_VMFLT_VF, MASK_VMFLT_VF) +DECLARE_INSN(vmfne_vf, MATCH_VMFNE_VF, MASK_VMFNE_VF) +DECLARE_INSN(vmfgt_vf, MATCH_VMFGT_VF, MASK_VMFGT_VF) +DECLARE_INSN(vmfge_vf, MATCH_VMFGE_VF, MASK_VMFGE_VF) +DECLARE_INSN(vfdiv_vf, MATCH_VFDIV_VF, MASK_VFDIV_VF) +DECLARE_INSN(vfrdiv_vf, MATCH_VFRDIV_VF, MASK_VFRDIV_VF) +DECLARE_INSN(vfmul_vf, MATCH_VFMUL_VF, MASK_VFMUL_VF) +DECLARE_INSN(vfrsub_vf, MATCH_VFRSUB_VF, MASK_VFRSUB_VF) +DECLARE_INSN(vfmadd_vf, MATCH_VFMADD_VF, MASK_VFMADD_VF) +DECLARE_INSN(vfnmadd_vf, MATCH_VFNMADD_VF, MASK_VFNMADD_VF) +DECLARE_INSN(vfmsub_vf, MATCH_VFMSUB_VF, MASK_VFMSUB_VF) +DECLARE_INSN(vfnmsub_vf, MATCH_VFNMSUB_VF, MASK_VFNMSUB_VF) +DECLARE_INSN(vfmacc_vf, MATCH_VFMACC_VF, MASK_VFMACC_VF) +DECLARE_INSN(vfnmacc_vf, MATCH_VFNMACC_VF, MASK_VFNMACC_VF) +DECLARE_INSN(vfmsac_vf, MATCH_VFMSAC_VF, MASK_VFMSAC_VF) +DECLARE_INSN(vfnmsac_vf, MATCH_VFNMSAC_VF, MASK_VFNMSAC_VF) +DECLARE_INSN(vfwadd_vf, MATCH_VFWADD_VF, MASK_VFWADD_VF) +DECLARE_INSN(vfwsub_vf, MATCH_VFWSUB_VF, MASK_VFWSUB_VF) +DECLARE_INSN(vfwadd_wf, MATCH_VFWADD_WF, MASK_VFWADD_WF) +DECLARE_INSN(vfwsub_wf, MATCH_VFWSUB_WF, MASK_VFWSUB_WF) +DECLARE_INSN(vfwmul_vf, MATCH_VFWMUL_VF, MASK_VFWMUL_VF) +DECLARE_INSN(vfwmacc_vf, MATCH_VFWMACC_VF, MASK_VFWMACC_VF) +DECLARE_INSN(vfwnmacc_vf, MATCH_VFWNMACC_VF, MASK_VFWNMACC_VF) +DECLARE_INSN(vfwmsac_vf, MATCH_VFWMSAC_VF, MASK_VFWMSAC_VF) +DECLARE_INSN(vfwnmsac_vf, MATCH_VFWNMSAC_VF, MASK_VFWNMSAC_VF) +DECLARE_INSN(vfadd_vv, MATCH_VFADD_VV, MASK_VFADD_VV) +DECLARE_INSN(vfredsum_vs, MATCH_VFREDSUM_VS, MASK_VFREDSUM_VS) +DECLARE_INSN(vfsub_vv, MATCH_VFSUB_VV, MASK_VFSUB_VV) +DECLARE_INSN(vfredosum_vs, MATCH_VFREDOSUM_VS, MASK_VFREDOSUM_VS) +DECLARE_INSN(vfmin_vv, MATCH_VFMIN_VV, MASK_VFMIN_VV) +DECLARE_INSN(vfredmin_vs, MATCH_VFREDMIN_VS, MASK_VFREDMIN_VS) +DECLARE_INSN(vfmax_vv, MATCH_VFMAX_VV, MASK_VFMAX_VV) +DECLARE_INSN(vfredmax_vs, MATCH_VFREDMAX_VS, MASK_VFREDMAX_VS) +DECLARE_INSN(vfsgnj_vv, MATCH_VFSGNJ_VV, MASK_VFSGNJ_VV) +DECLARE_INSN(vfsgnjn_vv, MATCH_VFSGNJN_VV, MASK_VFSGNJN_VV) +DECLARE_INSN(vfsgnjx_vv, MATCH_VFSGNJX_VV, MASK_VFSGNJX_VV) +DECLARE_INSN(vfmv_f_s, MATCH_VFMV_F_S, MASK_VFMV_F_S) +DECLARE_INSN(vmfeq_vv, MATCH_VMFEQ_VV, MASK_VMFEQ_VV) +DECLARE_INSN(vmfle_vv, MATCH_VMFLE_VV, MASK_VMFLE_VV) +DECLARE_INSN(vmflt_vv, MATCH_VMFLT_VV, MASK_VMFLT_VV) +DECLARE_INSN(vmfne_vv, MATCH_VMFNE_VV, MASK_VMFNE_VV) +DECLARE_INSN(vfdiv_vv, MATCH_VFDIV_VV, MASK_VFDIV_VV) +DECLARE_INSN(vfmul_vv, MATCH_VFMUL_VV, MASK_VFMUL_VV) +DECLARE_INSN(vfmadd_vv, MATCH_VFMADD_VV, MASK_VFMADD_VV) +DECLARE_INSN(vfnmadd_vv, MATCH_VFNMADD_VV, MASK_VFNMADD_VV) +DECLARE_INSN(vfmsub_vv, MATCH_VFMSUB_VV, MASK_VFMSUB_VV) +DECLARE_INSN(vfnmsub_vv, MATCH_VFNMSUB_VV, MASK_VFNMSUB_VV) +DECLARE_INSN(vfmacc_vv, MATCH_VFMACC_VV, MASK_VFMACC_VV) +DECLARE_INSN(vfnmacc_vv, MATCH_VFNMACC_VV, MASK_VFNMACC_VV) +DECLARE_INSN(vfmsac_vv, MATCH_VFMSAC_VV, MASK_VFMSAC_VV) +DECLARE_INSN(vfnmsac_vv, MATCH_VFNMSAC_VV, MASK_VFNMSAC_VV) +DECLARE_INSN(vfcvt_xu_f_v, MATCH_VFCVT_XU_F_V, MASK_VFCVT_XU_F_V) +DECLARE_INSN(vfcvt_x_f_v, MATCH_VFCVT_X_F_V, MASK_VFCVT_X_F_V) +DECLARE_INSN(vfcvt_f_xu_v, MATCH_VFCVT_F_XU_V, MASK_VFCVT_F_XU_V) +DECLARE_INSN(vfcvt_f_x_v, MATCH_VFCVT_F_X_V, MASK_VFCVT_F_X_V) +DECLARE_INSN(vfcvt_rtz_xu_f_v, MATCH_VFCVT_RTZ_XU_F_V, MASK_VFCVT_RTZ_XU_F_V) +DECLARE_INSN(vfcvt_rtz_x_f_v, MATCH_VFCVT_RTZ_X_F_V, MASK_VFCVT_RTZ_X_F_V) +DECLARE_INSN(vfwcvt_xu_f_v, MATCH_VFWCVT_XU_F_V, MASK_VFWCVT_XU_F_V) +DECLARE_INSN(vfwcvt_x_f_v, MATCH_VFWCVT_X_F_V, MASK_VFWCVT_X_F_V) +DECLARE_INSN(vfwcvt_f_xu_v, MATCH_VFWCVT_F_XU_V, MASK_VFWCVT_F_XU_V) +DECLARE_INSN(vfwcvt_f_x_v, MATCH_VFWCVT_F_X_V, MASK_VFWCVT_F_X_V) +DECLARE_INSN(vfwcvt_f_f_v, MATCH_VFWCVT_F_F_V, MASK_VFWCVT_F_F_V) +DECLARE_INSN(vfwcvt_rtz_xu_f_v, MATCH_VFWCVT_RTZ_XU_F_V, MASK_VFWCVT_RTZ_XU_F_V) +DECLARE_INSN(vfwcvt_rtz_x_f_v, MATCH_VFWCVT_RTZ_X_F_V, MASK_VFWCVT_RTZ_X_F_V) +DECLARE_INSN(vfncvt_xu_f_w, MATCH_VFNCVT_XU_F_W, MASK_VFNCVT_XU_F_W) +DECLARE_INSN(vfncvt_x_f_w, MATCH_VFNCVT_X_F_W, MASK_VFNCVT_X_F_W) +DECLARE_INSN(vfncvt_f_xu_w, MATCH_VFNCVT_F_XU_W, MASK_VFNCVT_F_XU_W) +DECLARE_INSN(vfncvt_f_x_w, MATCH_VFNCVT_F_X_W, MASK_VFNCVT_F_X_W) +DECLARE_INSN(vfncvt_f_f_w, MATCH_VFNCVT_F_F_W, MASK_VFNCVT_F_F_W) +DECLARE_INSN(vfncvt_rod_f_f_w, MATCH_VFNCVT_ROD_F_F_W, MASK_VFNCVT_ROD_F_F_W) +DECLARE_INSN(vfncvt_rtz_xu_f_w, MATCH_VFNCVT_RTZ_XU_F_W, MASK_VFNCVT_RTZ_XU_F_W) +DECLARE_INSN(vfncvt_rtz_x_f_w, MATCH_VFNCVT_RTZ_X_F_W, MASK_VFNCVT_RTZ_X_F_W) +DECLARE_INSN(vfsqrt_v, MATCH_VFSQRT_V, MASK_VFSQRT_V) +DECLARE_INSN(vfrsqrt7_v, MATCH_VFRSQRT7_V, MASK_VFRSQRT7_V) +DECLARE_INSN(vfrec7_v, MATCH_VFREC7_V, MASK_VFREC7_V) +DECLARE_INSN(vfclass_v, MATCH_VFCLASS_V, MASK_VFCLASS_V) +DECLARE_INSN(vfwadd_vv, MATCH_VFWADD_VV, MASK_VFWADD_VV) +DECLARE_INSN(vfwredsum_vs, MATCH_VFWREDSUM_VS, MASK_VFWREDSUM_VS) +DECLARE_INSN(vfwsub_vv, MATCH_VFWSUB_VV, MASK_VFWSUB_VV) +DECLARE_INSN(vfwredosum_vs, MATCH_VFWREDOSUM_VS, MASK_VFWREDOSUM_VS) +DECLARE_INSN(vfwadd_wv, MATCH_VFWADD_WV, MASK_VFWADD_WV) +DECLARE_INSN(vfwsub_wv, MATCH_VFWSUB_WV, MASK_VFWSUB_WV) +DECLARE_INSN(vfwmul_vv, MATCH_VFWMUL_VV, MASK_VFWMUL_VV) +DECLARE_INSN(vfdot_vv, MATCH_VFDOT_VV, MASK_VFDOT_VV) +DECLARE_INSN(vfwmacc_vv, MATCH_VFWMACC_VV, MASK_VFWMACC_VV) +DECLARE_INSN(vfwnmacc_vv, MATCH_VFWNMACC_VV, MASK_VFWNMACC_VV) +DECLARE_INSN(vfwmsac_vv, MATCH_VFWMSAC_VV, MASK_VFWMSAC_VV) +DECLARE_INSN(vfwnmsac_vv, MATCH_VFWNMSAC_VV, MASK_VFWNMSAC_VV) +DECLARE_INSN(vadd_vx, MATCH_VADD_VX, MASK_VADD_VX) +DECLARE_INSN(vsub_vx, MATCH_VSUB_VX, MASK_VSUB_VX) +DECLARE_INSN(vrsub_vx, MATCH_VRSUB_VX, MASK_VRSUB_VX) +DECLARE_INSN(vminu_vx, MATCH_VMINU_VX, MASK_VMINU_VX) +DECLARE_INSN(vmin_vx, MATCH_VMIN_VX, MASK_VMIN_VX) +DECLARE_INSN(vmaxu_vx, MATCH_VMAXU_VX, MASK_VMAXU_VX) +DECLARE_INSN(vmax_vx, MATCH_VMAX_VX, MASK_VMAX_VX) +DECLARE_INSN(vand_vx, MATCH_VAND_VX, MASK_VAND_VX) +DECLARE_INSN(vor_vx, MATCH_VOR_VX, MASK_VOR_VX) +DECLARE_INSN(vxor_vx, MATCH_VXOR_VX, MASK_VXOR_VX) +DECLARE_INSN(vrgather_vx, MATCH_VRGATHER_VX, MASK_VRGATHER_VX) +DECLARE_INSN(vslideup_vx, MATCH_VSLIDEUP_VX, MASK_VSLIDEUP_VX) +DECLARE_INSN(vslidedown_vx, MATCH_VSLIDEDOWN_VX, MASK_VSLIDEDOWN_VX) +DECLARE_INSN(vadc_vxm, MATCH_VADC_VXM, MASK_VADC_VXM) +DECLARE_INSN(vmadc_vxm, MATCH_VMADC_VXM, MASK_VMADC_VXM) +DECLARE_INSN(vsbc_vxm, MATCH_VSBC_VXM, MASK_VSBC_VXM) +DECLARE_INSN(vmsbc_vxm, MATCH_VMSBC_VXM, MASK_VMSBC_VXM) +DECLARE_INSN(vmerge_vxm, MATCH_VMERGE_VXM, MASK_VMERGE_VXM) +DECLARE_INSN(vmv_v_x, MATCH_VMV_V_X, MASK_VMV_V_X) +DECLARE_INSN(vmseq_vx, MATCH_VMSEQ_VX, MASK_VMSEQ_VX) +DECLARE_INSN(vmsne_vx, MATCH_VMSNE_VX, MASK_VMSNE_VX) +DECLARE_INSN(vmsltu_vx, MATCH_VMSLTU_VX, MASK_VMSLTU_VX) +DECLARE_INSN(vmslt_vx, MATCH_VMSLT_VX, MASK_VMSLT_VX) +DECLARE_INSN(vmsleu_vx, MATCH_VMSLEU_VX, MASK_VMSLEU_VX) +DECLARE_INSN(vmsle_vx, MATCH_VMSLE_VX, MASK_VMSLE_VX) +DECLARE_INSN(vmsgtu_vx, MATCH_VMSGTU_VX, MASK_VMSGTU_VX) +DECLARE_INSN(vmsgt_vx, MATCH_VMSGT_VX, MASK_VMSGT_VX) +DECLARE_INSN(vsaddu_vx, MATCH_VSADDU_VX, MASK_VSADDU_VX) +DECLARE_INSN(vsadd_vx, MATCH_VSADD_VX, MASK_VSADD_VX) +DECLARE_INSN(vssubu_vx, MATCH_VSSUBU_VX, MASK_VSSUBU_VX) +DECLARE_INSN(vssub_vx, MATCH_VSSUB_VX, MASK_VSSUB_VX) +DECLARE_INSN(vsll_vx, MATCH_VSLL_VX, MASK_VSLL_VX) +DECLARE_INSN(vsmul_vx, MATCH_VSMUL_VX, MASK_VSMUL_VX) +DECLARE_INSN(vsrl_vx, MATCH_VSRL_VX, MASK_VSRL_VX) +DECLARE_INSN(vsra_vx, MATCH_VSRA_VX, MASK_VSRA_VX) +DECLARE_INSN(vssrl_vx, MATCH_VSSRL_VX, MASK_VSSRL_VX) +DECLARE_INSN(vssra_vx, MATCH_VSSRA_VX, MASK_VSSRA_VX) +DECLARE_INSN(vnsrl_wx, MATCH_VNSRL_WX, MASK_VNSRL_WX) +DECLARE_INSN(vnsra_wx, MATCH_VNSRA_WX, MASK_VNSRA_WX) +DECLARE_INSN(vnclipu_wx, MATCH_VNCLIPU_WX, MASK_VNCLIPU_WX) +DECLARE_INSN(vnclip_wx, MATCH_VNCLIP_WX, MASK_VNCLIP_WX) +DECLARE_INSN(vadd_vv, MATCH_VADD_VV, MASK_VADD_VV) +DECLARE_INSN(vsub_vv, MATCH_VSUB_VV, MASK_VSUB_VV) +DECLARE_INSN(vminu_vv, MATCH_VMINU_VV, MASK_VMINU_VV) +DECLARE_INSN(vmin_vv, MATCH_VMIN_VV, MASK_VMIN_VV) +DECLARE_INSN(vmaxu_vv, MATCH_VMAXU_VV, MASK_VMAXU_VV) +DECLARE_INSN(vmax_vv, MATCH_VMAX_VV, MASK_VMAX_VV) +DECLARE_INSN(vand_vv, MATCH_VAND_VV, MASK_VAND_VV) +DECLARE_INSN(vor_vv, MATCH_VOR_VV, MASK_VOR_VV) +DECLARE_INSN(vxor_vv, MATCH_VXOR_VV, MASK_VXOR_VV) +DECLARE_INSN(vrgather_vv, MATCH_VRGATHER_VV, MASK_VRGATHER_VV) +DECLARE_INSN(vrgatherei16_vv, MATCH_VRGATHEREI16_VV, MASK_VRGATHEREI16_VV) +DECLARE_INSN(vadc_vvm, MATCH_VADC_VVM, MASK_VADC_VVM) +DECLARE_INSN(vmadc_vvm, MATCH_VMADC_VVM, MASK_VMADC_VVM) +DECLARE_INSN(vsbc_vvm, MATCH_VSBC_VVM, MASK_VSBC_VVM) +DECLARE_INSN(vmsbc_vvm, MATCH_VMSBC_VVM, MASK_VMSBC_VVM) +DECLARE_INSN(vmerge_vvm, MATCH_VMERGE_VVM, MASK_VMERGE_VVM) +DECLARE_INSN(vmv_v_v, MATCH_VMV_V_V, MASK_VMV_V_V) +DECLARE_INSN(vmseq_vv, MATCH_VMSEQ_VV, MASK_VMSEQ_VV) +DECLARE_INSN(vmsne_vv, MATCH_VMSNE_VV, MASK_VMSNE_VV) +DECLARE_INSN(vmsltu_vv, MATCH_VMSLTU_VV, MASK_VMSLTU_VV) +DECLARE_INSN(vmslt_vv, MATCH_VMSLT_VV, MASK_VMSLT_VV) +DECLARE_INSN(vmsleu_vv, MATCH_VMSLEU_VV, MASK_VMSLEU_VV) +DECLARE_INSN(vmsle_vv, MATCH_VMSLE_VV, MASK_VMSLE_VV) +DECLARE_INSN(vsaddu_vv, MATCH_VSADDU_VV, MASK_VSADDU_VV) +DECLARE_INSN(vsadd_vv, MATCH_VSADD_VV, MASK_VSADD_VV) +DECLARE_INSN(vssubu_vv, MATCH_VSSUBU_VV, MASK_VSSUBU_VV) +DECLARE_INSN(vssub_vv, MATCH_VSSUB_VV, MASK_VSSUB_VV) +DECLARE_INSN(vsll_vv, MATCH_VSLL_VV, MASK_VSLL_VV) +DECLARE_INSN(vsmul_vv, MATCH_VSMUL_VV, MASK_VSMUL_VV) +DECLARE_INSN(vsrl_vv, MATCH_VSRL_VV, MASK_VSRL_VV) +DECLARE_INSN(vsra_vv, MATCH_VSRA_VV, MASK_VSRA_VV) +DECLARE_INSN(vssrl_vv, MATCH_VSSRL_VV, MASK_VSSRL_VV) +DECLARE_INSN(vssra_vv, MATCH_VSSRA_VV, MASK_VSSRA_VV) +DECLARE_INSN(vnsrl_wv, MATCH_VNSRL_WV, MASK_VNSRL_WV) +DECLARE_INSN(vnsra_wv, MATCH_VNSRA_WV, MASK_VNSRA_WV) +DECLARE_INSN(vnclipu_wv, MATCH_VNCLIPU_WV, MASK_VNCLIPU_WV) +DECLARE_INSN(vnclip_wv, MATCH_VNCLIP_WV, MASK_VNCLIP_WV) +DECLARE_INSN(vwredsumu_vs, MATCH_VWREDSUMU_VS, MASK_VWREDSUMU_VS) +DECLARE_INSN(vwredsum_vs, MATCH_VWREDSUM_VS, MASK_VWREDSUM_VS) +DECLARE_INSN(vdotu_vv, MATCH_VDOTU_VV, MASK_VDOTU_VV) +DECLARE_INSN(vdot_vv, MATCH_VDOT_VV, MASK_VDOT_VV) +DECLARE_INSN(vqmaccu_vv, MATCH_VQMACCU_VV, MASK_VQMACCU_VV) +DECLARE_INSN(vqmacc_vv, MATCH_VQMACC_VV, MASK_VQMACC_VV) +DECLARE_INSN(vqmaccsu_vv, MATCH_VQMACCSU_VV, MASK_VQMACCSU_VV) +DECLARE_INSN(vadd_vi, MATCH_VADD_VI, MASK_VADD_VI) +DECLARE_INSN(vrsub_vi, MATCH_VRSUB_VI, MASK_VRSUB_VI) +DECLARE_INSN(vand_vi, MATCH_VAND_VI, MASK_VAND_VI) +DECLARE_INSN(vor_vi, MATCH_VOR_VI, MASK_VOR_VI) +DECLARE_INSN(vxor_vi, MATCH_VXOR_VI, MASK_VXOR_VI) +DECLARE_INSN(vrgather_vi, MATCH_VRGATHER_VI, MASK_VRGATHER_VI) +DECLARE_INSN(vslideup_vi, MATCH_VSLIDEUP_VI, MASK_VSLIDEUP_VI) +DECLARE_INSN(vslidedown_vi, MATCH_VSLIDEDOWN_VI, MASK_VSLIDEDOWN_VI) +DECLARE_INSN(vadc_vim, MATCH_VADC_VIM, MASK_VADC_VIM) +DECLARE_INSN(vmadc_vim, MATCH_VMADC_VIM, MASK_VMADC_VIM) +DECLARE_INSN(vmerge_vim, MATCH_VMERGE_VIM, MASK_VMERGE_VIM) +DECLARE_INSN(vmv_v_i, MATCH_VMV_V_I, MASK_VMV_V_I) +DECLARE_INSN(vmseq_vi, MATCH_VMSEQ_VI, MASK_VMSEQ_VI) +DECLARE_INSN(vmsne_vi, MATCH_VMSNE_VI, MASK_VMSNE_VI) +DECLARE_INSN(vmsleu_vi, MATCH_VMSLEU_VI, MASK_VMSLEU_VI) +DECLARE_INSN(vmsle_vi, MATCH_VMSLE_VI, MASK_VMSLE_VI) +DECLARE_INSN(vmsgtu_vi, MATCH_VMSGTU_VI, MASK_VMSGTU_VI) +DECLARE_INSN(vmsgt_vi, MATCH_VMSGT_VI, MASK_VMSGT_VI) +DECLARE_INSN(vsaddu_vi, MATCH_VSADDU_VI, MASK_VSADDU_VI) +DECLARE_INSN(vsadd_vi, MATCH_VSADD_VI, MASK_VSADD_VI) +DECLARE_INSN(vsll_vi, MATCH_VSLL_VI, MASK_VSLL_VI) +DECLARE_INSN(vmv1r_v, MATCH_VMV1R_V, MASK_VMV1R_V) +DECLARE_INSN(vmv2r_v, MATCH_VMV2R_V, MASK_VMV2R_V) +DECLARE_INSN(vmv4r_v, MATCH_VMV4R_V, MASK_VMV4R_V) +DECLARE_INSN(vmv8r_v, MATCH_VMV8R_V, MASK_VMV8R_V) +DECLARE_INSN(vsrl_vi, MATCH_VSRL_VI, MASK_VSRL_VI) +DECLARE_INSN(vsra_vi, MATCH_VSRA_VI, MASK_VSRA_VI) +DECLARE_INSN(vssrl_vi, MATCH_VSSRL_VI, MASK_VSSRL_VI) +DECLARE_INSN(vssra_vi, MATCH_VSSRA_VI, MASK_VSSRA_VI) +DECLARE_INSN(vnsrl_wi, MATCH_VNSRL_WI, MASK_VNSRL_WI) +DECLARE_INSN(vnsra_wi, MATCH_VNSRA_WI, MASK_VNSRA_WI) +DECLARE_INSN(vnclipu_wi, MATCH_VNCLIPU_WI, MASK_VNCLIPU_WI) +DECLARE_INSN(vnclip_wi, MATCH_VNCLIP_WI, MASK_VNCLIP_WI) +DECLARE_INSN(vredsum_vs, MATCH_VREDSUM_VS, MASK_VREDSUM_VS) +DECLARE_INSN(vredand_vs, MATCH_VREDAND_VS, MASK_VREDAND_VS) +DECLARE_INSN(vredor_vs, MATCH_VREDOR_VS, MASK_VREDOR_VS) +DECLARE_INSN(vredxor_vs, MATCH_VREDXOR_VS, MASK_VREDXOR_VS) +DECLARE_INSN(vredminu_vs, MATCH_VREDMINU_VS, MASK_VREDMINU_VS) +DECLARE_INSN(vredmin_vs, MATCH_VREDMIN_VS, MASK_VREDMIN_VS) +DECLARE_INSN(vredmaxu_vs, MATCH_VREDMAXU_VS, MASK_VREDMAXU_VS) +DECLARE_INSN(vredmax_vs, MATCH_VREDMAX_VS, MASK_VREDMAX_VS) +DECLARE_INSN(vaaddu_vv, MATCH_VAADDU_VV, MASK_VAADDU_VV) +DECLARE_INSN(vaadd_vv, MATCH_VAADD_VV, MASK_VAADD_VV) +DECLARE_INSN(vasubu_vv, MATCH_VASUBU_VV, MASK_VASUBU_VV) +DECLARE_INSN(vasub_vv, MATCH_VASUB_VV, MASK_VASUB_VV) +DECLARE_INSN(vmv_x_s, MATCH_VMV_X_S, MASK_VMV_X_S) +DECLARE_INSN(vzext_vf8, MATCH_VZEXT_VF8, MASK_VZEXT_VF8) +DECLARE_INSN(vsext_vf8, MATCH_VSEXT_VF8, MASK_VSEXT_VF8) +DECLARE_INSN(vzext_vf4, MATCH_VZEXT_VF4, MASK_VZEXT_VF4) +DECLARE_INSN(vsext_vf4, MATCH_VSEXT_VF4, MASK_VSEXT_VF4) +DECLARE_INSN(vzext_vf2, MATCH_VZEXT_VF2, MASK_VZEXT_VF2) +DECLARE_INSN(vsext_vf2, MATCH_VSEXT_VF2, MASK_VSEXT_VF2) +DECLARE_INSN(vcompress_vm, MATCH_VCOMPRESS_VM, MASK_VCOMPRESS_VM) +DECLARE_INSN(vmandnot_mm, MATCH_VMANDNOT_MM, MASK_VMANDNOT_MM) +DECLARE_INSN(vmand_mm, MATCH_VMAND_MM, MASK_VMAND_MM) +DECLARE_INSN(vmor_mm, MATCH_VMOR_MM, MASK_VMOR_MM) +DECLARE_INSN(vmxor_mm, MATCH_VMXOR_MM, MASK_VMXOR_MM) +DECLARE_INSN(vmornot_mm, MATCH_VMORNOT_MM, MASK_VMORNOT_MM) +DECLARE_INSN(vmnand_mm, MATCH_VMNAND_MM, MASK_VMNAND_MM) +DECLARE_INSN(vmnor_mm, MATCH_VMNOR_MM, MASK_VMNOR_MM) +DECLARE_INSN(vmxnor_mm, MATCH_VMXNOR_MM, MASK_VMXNOR_MM) +DECLARE_INSN(vmsbf_m, MATCH_VMSBF_M, MASK_VMSBF_M) +DECLARE_INSN(vmsof_m, MATCH_VMSOF_M, MASK_VMSOF_M) +DECLARE_INSN(vmsif_m, MATCH_VMSIF_M, MASK_VMSIF_M) +DECLARE_INSN(viota_m, MATCH_VIOTA_M, MASK_VIOTA_M) +DECLARE_INSN(vid_v, MATCH_VID_V, MASK_VID_V) +DECLARE_INSN(vpopc_m, MATCH_VPOPC_M, MASK_VPOPC_M) +DECLARE_INSN(vfirst_m, MATCH_VFIRST_M, MASK_VFIRST_M) +DECLARE_INSN(vdivu_vv, MATCH_VDIVU_VV, MASK_VDIVU_VV) +DECLARE_INSN(vdiv_vv, MATCH_VDIV_VV, MASK_VDIV_VV) +DECLARE_INSN(vremu_vv, MATCH_VREMU_VV, MASK_VREMU_VV) +DECLARE_INSN(vrem_vv, MATCH_VREM_VV, MASK_VREM_VV) +DECLARE_INSN(vmulhu_vv, MATCH_VMULHU_VV, MASK_VMULHU_VV) +DECLARE_INSN(vmul_vv, MATCH_VMUL_VV, MASK_VMUL_VV) +DECLARE_INSN(vmulhsu_vv, MATCH_VMULHSU_VV, MASK_VMULHSU_VV) +DECLARE_INSN(vmulh_vv, MATCH_VMULH_VV, MASK_VMULH_VV) +DECLARE_INSN(vmadd_vv, MATCH_VMADD_VV, MASK_VMADD_VV) +DECLARE_INSN(vnmsub_vv, MATCH_VNMSUB_VV, MASK_VNMSUB_VV) +DECLARE_INSN(vmacc_vv, MATCH_VMACC_VV, MASK_VMACC_VV) +DECLARE_INSN(vnmsac_vv, MATCH_VNMSAC_VV, MASK_VNMSAC_VV) +DECLARE_INSN(vwaddu_vv, MATCH_VWADDU_VV, MASK_VWADDU_VV) +DECLARE_INSN(vwadd_vv, MATCH_VWADD_VV, MASK_VWADD_VV) +DECLARE_INSN(vwsubu_vv, MATCH_VWSUBU_VV, MASK_VWSUBU_VV) +DECLARE_INSN(vwsub_vv, MATCH_VWSUB_VV, MASK_VWSUB_VV) +DECLARE_INSN(vwaddu_wv, MATCH_VWADDU_WV, MASK_VWADDU_WV) +DECLARE_INSN(vwadd_wv, MATCH_VWADD_WV, MASK_VWADD_WV) +DECLARE_INSN(vwsubu_wv, MATCH_VWSUBU_WV, MASK_VWSUBU_WV) +DECLARE_INSN(vwsub_wv, MATCH_VWSUB_WV, MASK_VWSUB_WV) +DECLARE_INSN(vwmulu_vv, MATCH_VWMULU_VV, MASK_VWMULU_VV) +DECLARE_INSN(vwmulsu_vv, MATCH_VWMULSU_VV, MASK_VWMULSU_VV) +DECLARE_INSN(vwmul_vv, MATCH_VWMUL_VV, MASK_VWMUL_VV) +DECLARE_INSN(vwmaccu_vv, MATCH_VWMACCU_VV, MASK_VWMACCU_VV) +DECLARE_INSN(vwmacc_vv, MATCH_VWMACC_VV, MASK_VWMACC_VV) +DECLARE_INSN(vwmaccsu_vv, MATCH_VWMACCSU_VV, MASK_VWMACCSU_VV) +DECLARE_INSN(vaaddu_vx, MATCH_VAADDU_VX, MASK_VAADDU_VX) +DECLARE_INSN(vaadd_vx, MATCH_VAADD_VX, MASK_VAADD_VX) +DECLARE_INSN(vasubu_vx, MATCH_VASUBU_VX, MASK_VASUBU_VX) +DECLARE_INSN(vasub_vx, MATCH_VASUB_VX, MASK_VASUB_VX) +DECLARE_INSN(vmv_s_x, MATCH_VMV_S_X, MASK_VMV_S_X) +DECLARE_INSN(vslide1up_vx, MATCH_VSLIDE1UP_VX, MASK_VSLIDE1UP_VX) +DECLARE_INSN(vslide1down_vx, MATCH_VSLIDE1DOWN_VX, MASK_VSLIDE1DOWN_VX) +DECLARE_INSN(vdivu_vx, MATCH_VDIVU_VX, MASK_VDIVU_VX) +DECLARE_INSN(vdiv_vx, MATCH_VDIV_VX, MASK_VDIV_VX) +DECLARE_INSN(vremu_vx, MATCH_VREMU_VX, MASK_VREMU_VX) +DECLARE_INSN(vrem_vx, MATCH_VREM_VX, MASK_VREM_VX) +DECLARE_INSN(vmulhu_vx, MATCH_VMULHU_VX, MASK_VMULHU_VX) +DECLARE_INSN(vmul_vx, MATCH_VMUL_VX, MASK_VMUL_VX) +DECLARE_INSN(vmulhsu_vx, MATCH_VMULHSU_VX, MASK_VMULHSU_VX) +DECLARE_INSN(vmulh_vx, MATCH_VMULH_VX, MASK_VMULH_VX) +DECLARE_INSN(vmadd_vx, MATCH_VMADD_VX, MASK_VMADD_VX) +DECLARE_INSN(vnmsub_vx, MATCH_VNMSUB_VX, MASK_VNMSUB_VX) +DECLARE_INSN(vmacc_vx, MATCH_VMACC_VX, MASK_VMACC_VX) +DECLARE_INSN(vnmsac_vx, MATCH_VNMSAC_VX, MASK_VNMSAC_VX) +DECLARE_INSN(vwaddu_vx, MATCH_VWADDU_VX, MASK_VWADDU_VX) +DECLARE_INSN(vwadd_vx, MATCH_VWADD_VX, MASK_VWADD_VX) +DECLARE_INSN(vwsubu_vx, MATCH_VWSUBU_VX, MASK_VWSUBU_VX) +DECLARE_INSN(vwsub_vx, MATCH_VWSUB_VX, MASK_VWSUB_VX) +DECLARE_INSN(vwaddu_wx, MATCH_VWADDU_WX, MASK_VWADDU_WX) +DECLARE_INSN(vwadd_wx, MATCH_VWADD_WX, MASK_VWADD_WX) +DECLARE_INSN(vwsubu_wx, MATCH_VWSUBU_WX, MASK_VWSUBU_WX) +DECLARE_INSN(vwsub_wx, MATCH_VWSUB_WX, MASK_VWSUB_WX) +DECLARE_INSN(vwmulu_vx, MATCH_VWMULU_VX, MASK_VWMULU_VX) +DECLARE_INSN(vwmulsu_vx, MATCH_VWMULSU_VX, MASK_VWMULSU_VX) +DECLARE_INSN(vwmul_vx, MATCH_VWMUL_VX, MASK_VWMUL_VX) +DECLARE_INSN(vwmaccu_vx, MATCH_VWMACCU_VX, MASK_VWMACCU_VX) +DECLARE_INSN(vwmacc_vx, MATCH_VWMACC_VX, MASK_VWMACC_VX) +DECLARE_INSN(vwmaccus_vx, MATCH_VWMACCUS_VX, MASK_VWMACCUS_VX) +DECLARE_INSN(vwmaccsu_vx, MATCH_VWMACCSU_VX, MASK_VWMACCSU_VX) +DECLARE_INSN(vamoswapei8_v, MATCH_VAMOSWAPEI8_V, MASK_VAMOSWAPEI8_V) +DECLARE_INSN(vamoaddei8_v, MATCH_VAMOADDEI8_V, MASK_VAMOADDEI8_V) +DECLARE_INSN(vamoxorei8_v, MATCH_VAMOXOREI8_V, MASK_VAMOXOREI8_V) +DECLARE_INSN(vamoandei8_v, MATCH_VAMOANDEI8_V, MASK_VAMOANDEI8_V) +DECLARE_INSN(vamoorei8_v, MATCH_VAMOOREI8_V, MASK_VAMOOREI8_V) +DECLARE_INSN(vamominei8_v, MATCH_VAMOMINEI8_V, MASK_VAMOMINEI8_V) +DECLARE_INSN(vamomaxei8_v, MATCH_VAMOMAXEI8_V, MASK_VAMOMAXEI8_V) +DECLARE_INSN(vamominuei8_v, MATCH_VAMOMINUEI8_V, MASK_VAMOMINUEI8_V) +DECLARE_INSN(vamomaxuei8_v, MATCH_VAMOMAXUEI8_V, MASK_VAMOMAXUEI8_V) +DECLARE_INSN(vamoswapei16_v, MATCH_VAMOSWAPEI16_V, MASK_VAMOSWAPEI16_V) +DECLARE_INSN(vamoaddei16_v, MATCH_VAMOADDEI16_V, MASK_VAMOADDEI16_V) +DECLARE_INSN(vamoxorei16_v, MATCH_VAMOXOREI16_V, MASK_VAMOXOREI16_V) +DECLARE_INSN(vamoandei16_v, MATCH_VAMOANDEI16_V, MASK_VAMOANDEI16_V) +DECLARE_INSN(vamoorei16_v, MATCH_VAMOOREI16_V, MASK_VAMOOREI16_V) +DECLARE_INSN(vamominei16_v, MATCH_VAMOMINEI16_V, MASK_VAMOMINEI16_V) +DECLARE_INSN(vamomaxei16_v, MATCH_VAMOMAXEI16_V, MASK_VAMOMAXEI16_V) +DECLARE_INSN(vamominuei16_v, MATCH_VAMOMINUEI16_V, MASK_VAMOMINUEI16_V) +DECLARE_INSN(vamomaxuei16_v, MATCH_VAMOMAXUEI16_V, MASK_VAMOMAXUEI16_V) +DECLARE_INSN(vamoswapei32_v, MATCH_VAMOSWAPEI32_V, MASK_VAMOSWAPEI32_V) +DECLARE_INSN(vamoaddei32_v, MATCH_VAMOADDEI32_V, MASK_VAMOADDEI32_V) +DECLARE_INSN(vamoxorei32_v, MATCH_VAMOXOREI32_V, MASK_VAMOXOREI32_V) +DECLARE_INSN(vamoandei32_v, MATCH_VAMOANDEI32_V, MASK_VAMOANDEI32_V) +DECLARE_INSN(vamoorei32_v, MATCH_VAMOOREI32_V, MASK_VAMOOREI32_V) +DECLARE_INSN(vamominei32_v, MATCH_VAMOMINEI32_V, MASK_VAMOMINEI32_V) +DECLARE_INSN(vamomaxei32_v, MATCH_VAMOMAXEI32_V, MASK_VAMOMAXEI32_V) +DECLARE_INSN(vamominuei32_v, MATCH_VAMOMINUEI32_V, MASK_VAMOMINUEI32_V) +DECLARE_INSN(vamomaxuei32_v, MATCH_VAMOMAXUEI32_V, MASK_VAMOMAXUEI32_V) +DECLARE_INSN(vamoswapei64_v, MATCH_VAMOSWAPEI64_V, MASK_VAMOSWAPEI64_V) +DECLARE_INSN(vamoaddei64_v, MATCH_VAMOADDEI64_V, MASK_VAMOADDEI64_V) +DECLARE_INSN(vamoxorei64_v, MATCH_VAMOXOREI64_V, MASK_VAMOXOREI64_V) +DECLARE_INSN(vamoandei64_v, MATCH_VAMOANDEI64_V, MASK_VAMOANDEI64_V) +DECLARE_INSN(vamoorei64_v, MATCH_VAMOOREI64_V, MASK_VAMOOREI64_V) +DECLARE_INSN(vamominei64_v, MATCH_VAMOMINEI64_V, MASK_VAMOMINEI64_V) +DECLARE_INSN(vamomaxei64_v, MATCH_VAMOMAXEI64_V, MASK_VAMOMAXEI64_V) +DECLARE_INSN(vamominuei64_v, MATCH_VAMOMINUEI64_V, MASK_VAMOMINUEI64_V) +DECLARE_INSN(vamomaxuei64_v, MATCH_VAMOMAXUEI64_V, MASK_VAMOMAXUEI64_V) +DECLARE_INSN(vmvnfr_v, MATCH_VMVNFR_V, MASK_VMVNFR_V) +DECLARE_INSN(vl1r_v, MATCH_VL1R_V, MASK_VL1R_V) +DECLARE_INSN(vl2r_v, MATCH_VL2R_V, MASK_VL2R_V) +DECLARE_INSN(vl4r_v, MATCH_VL4R_V, MASK_VL4R_V) +DECLARE_INSN(vl8r_v, MATCH_VL8R_V, MASK_VL8R_V) +#ifdef DECLARE_RV32_ONLY +DECLARE_RV32_ONLY(aes32esmi) +DECLARE_RV32_ONLY(aes32esi) +DECLARE_RV32_ONLY(aes32dsmi) +DECLARE_RV32_ONLY(aes32dsi) +DECLARE_RV32_ONLY(sha512sum0r) +DECLARE_RV32_ONLY(sha512sum1r) +DECLARE_RV32_ONLY(sha512sig0l) +DECLARE_RV32_ONLY(sha512sig0h) +DECLARE_RV32_ONLY(sha512sig1l) +DECLARE_RV32_ONLY(sha512sig1h) +#endif +#ifdef DECLARE_RV64_ONLY +DECLARE_RV64_ONLY(aes64ks1i) +DECLARE_RV64_ONLY(aes64im) +DECLARE_RV64_ONLY(aes64ks2) +DECLARE_RV64_ONLY(aes64esm) +DECLARE_RV64_ONLY(aes64es) +DECLARE_RV64_ONLY(aes64dsm) +DECLARE_RV64_ONLY(aes64ds) +DECLARE_RV64_ONLY(sha512sum0) +DECLARE_RV64_ONLY(sha512sum1) +DECLARE_RV64_ONLY(sha512sig0) +DECLARE_RV64_ONLY(sha512sig1) +#endif +#endif +#ifdef DECLARE_CSR +DECLARE_CSR(fflags, CSR_FFLAGS) +DECLARE_CSR(frm, CSR_FRM) +DECLARE_CSR(fcsr, CSR_FCSR) +DECLARE_CSR(ustatus, CSR_USTATUS) +DECLARE_CSR(uie, CSR_UIE) +DECLARE_CSR(utvec, CSR_UTVEC) +DECLARE_CSR(vstart, CSR_VSTART) +DECLARE_CSR(vxsat, CSR_VXSAT) +DECLARE_CSR(vxrm, CSR_VXRM) +DECLARE_CSR(vcsr, CSR_VCSR) +DECLARE_CSR(uscratch, CSR_USCRATCH) +DECLARE_CSR(uepc, CSR_UEPC) +DECLARE_CSR(ucause, CSR_UCAUSE) +DECLARE_CSR(utval, CSR_UTVAL) +DECLARE_CSR(uip, CSR_UIP) +DECLARE_CSR(cycle, CSR_CYCLE) +DECLARE_CSR(time, CSR_TIME) +DECLARE_CSR(instret, CSR_INSTRET) +DECLARE_CSR(hpmcounter3, CSR_HPMCOUNTER3) +DECLARE_CSR(hpmcounter4, CSR_HPMCOUNTER4) +DECLARE_CSR(hpmcounter5, CSR_HPMCOUNTER5) +DECLARE_CSR(hpmcounter6, CSR_HPMCOUNTER6) +DECLARE_CSR(hpmcounter7, CSR_HPMCOUNTER7) +DECLARE_CSR(hpmcounter8, CSR_HPMCOUNTER8) +DECLARE_CSR(hpmcounter9, CSR_HPMCOUNTER9) +DECLARE_CSR(hpmcounter10, CSR_HPMCOUNTER10) +DECLARE_CSR(hpmcounter11, CSR_HPMCOUNTER11) +DECLARE_CSR(hpmcounter12, CSR_HPMCOUNTER12) +DECLARE_CSR(hpmcounter13, CSR_HPMCOUNTER13) +DECLARE_CSR(hpmcounter14, CSR_HPMCOUNTER14) +DECLARE_CSR(hpmcounter15, CSR_HPMCOUNTER15) +DECLARE_CSR(hpmcounter16, CSR_HPMCOUNTER16) +DECLARE_CSR(hpmcounter17, CSR_HPMCOUNTER17) +DECLARE_CSR(hpmcounter18, CSR_HPMCOUNTER18) +DECLARE_CSR(hpmcounter19, CSR_HPMCOUNTER19) +DECLARE_CSR(hpmcounter20, CSR_HPMCOUNTER20) +DECLARE_CSR(hpmcounter21, CSR_HPMCOUNTER21) +DECLARE_CSR(hpmcounter22, CSR_HPMCOUNTER22) +DECLARE_CSR(hpmcounter23, CSR_HPMCOUNTER23) +DECLARE_CSR(hpmcounter24, CSR_HPMCOUNTER24) +DECLARE_CSR(hpmcounter25, CSR_HPMCOUNTER25) +DECLARE_CSR(hpmcounter26, CSR_HPMCOUNTER26) +DECLARE_CSR(hpmcounter27, CSR_HPMCOUNTER27) +DECLARE_CSR(hpmcounter28, CSR_HPMCOUNTER28) +DECLARE_CSR(hpmcounter29, CSR_HPMCOUNTER29) +DECLARE_CSR(hpmcounter30, CSR_HPMCOUNTER30) +DECLARE_CSR(hpmcounter31, CSR_HPMCOUNTER31) +DECLARE_CSR(vl, CSR_VL) +DECLARE_CSR(vtype, CSR_VTYPE) +DECLARE_CSR(vlenb, CSR_VLENB) +DECLARE_CSR(sstatus, CSR_SSTATUS) +DECLARE_CSR(sedeleg, CSR_SEDELEG) +DECLARE_CSR(sideleg, CSR_SIDELEG) +DECLARE_CSR(sie, CSR_SIE) +DECLARE_CSR(stvec, CSR_STVEC) +DECLARE_CSR(scounteren, CSR_SCOUNTEREN) +DECLARE_CSR(sscratch, CSR_SSCRATCH) +DECLARE_CSR(sepc, CSR_SEPC) +DECLARE_CSR(scause, CSR_SCAUSE) +DECLARE_CSR(stval, CSR_STVAL) +DECLARE_CSR(sip, CSR_SIP) +DECLARE_CSR(satp, CSR_SATP) +DECLARE_CSR(vsstatus, CSR_VSSTATUS) +DECLARE_CSR(vsie, CSR_VSIE) +DECLARE_CSR(vstvec, CSR_VSTVEC) +DECLARE_CSR(vsscratch, CSR_VSSCRATCH) +DECLARE_CSR(vsepc, CSR_VSEPC) +DECLARE_CSR(vscause, CSR_VSCAUSE) +DECLARE_CSR(vstval, CSR_VSTVAL) +DECLARE_CSR(vsip, CSR_VSIP) +DECLARE_CSR(vsatp, CSR_VSATP) +DECLARE_CSR(hstatus, CSR_HSTATUS) +DECLARE_CSR(hedeleg, CSR_HEDELEG) +DECLARE_CSR(hideleg, CSR_HIDELEG) +DECLARE_CSR(hie, CSR_HIE) +DECLARE_CSR(htimedelta, CSR_HTIMEDELTA) +DECLARE_CSR(hcounteren, CSR_HCOUNTEREN) +DECLARE_CSR(hgeie, CSR_HGEIE) +DECLARE_CSR(htval, CSR_HTVAL) +DECLARE_CSR(hip, CSR_HIP) +DECLARE_CSR(hvip, CSR_HVIP) +DECLARE_CSR(htinst, CSR_HTINST) +DECLARE_CSR(hgatp, CSR_HGATP) +DECLARE_CSR(hgeip, CSR_HGEIP) +DECLARE_CSR(utvt, CSR_UTVT) +DECLARE_CSR(unxti, CSR_UNXTI) +DECLARE_CSR(uintstatus, CSR_UINTSTATUS) +DECLARE_CSR(uscratchcsw, CSR_USCRATCHCSW) +DECLARE_CSR(uscratchcswl, CSR_USCRATCHCSWL) +DECLARE_CSR(stvt, CSR_STVT) +DECLARE_CSR(snxti, CSR_SNXTI) +DECLARE_CSR(sintstatus, CSR_SINTSTATUS) +DECLARE_CSR(sscratchcsw, CSR_SSCRATCHCSW) +DECLARE_CSR(sscratchcswl, CSR_SSCRATCHCSWL) +DECLARE_CSR(mtvt, CSR_MTVT) +DECLARE_CSR(mnxti, CSR_MNXTI) +DECLARE_CSR(mintstatus, CSR_MINTSTATUS) +DECLARE_CSR(mscratchcsw, CSR_MSCRATCHCSW) +DECLARE_CSR(mscratchcswl, CSR_MSCRATCHCSWL) +DECLARE_CSR(mstatus, CSR_MSTATUS) +DECLARE_CSR(misa, CSR_MISA) +DECLARE_CSR(medeleg, CSR_MEDELEG) +DECLARE_CSR(mideleg, CSR_MIDELEG) +DECLARE_CSR(mie, CSR_MIE) +DECLARE_CSR(mtvec, CSR_MTVEC) +DECLARE_CSR(mcounteren, CSR_MCOUNTEREN) +DECLARE_CSR(mcountinhibit, CSR_MCOUNTINHIBIT) +DECLARE_CSR(mscratch, CSR_MSCRATCH) +DECLARE_CSR(mepc, CSR_MEPC) +DECLARE_CSR(mcause, CSR_MCAUSE) +DECLARE_CSR(mtval, CSR_MTVAL) +DECLARE_CSR(mip, CSR_MIP) +DECLARE_CSR(mtinst, CSR_MTINST) +DECLARE_CSR(mtval2, CSR_MTVAL2) +DECLARE_CSR(pmpcfg0, CSR_PMPCFG0) +DECLARE_CSR(pmpcfg1, CSR_PMPCFG1) +DECLARE_CSR(pmpcfg2, CSR_PMPCFG2) +DECLARE_CSR(pmpcfg3, CSR_PMPCFG3) +DECLARE_CSR(pmpaddr0, CSR_PMPADDR0) +DECLARE_CSR(pmpaddr1, CSR_PMPADDR1) +DECLARE_CSR(pmpaddr2, CSR_PMPADDR2) +DECLARE_CSR(pmpaddr3, CSR_PMPADDR3) +DECLARE_CSR(pmpaddr4, CSR_PMPADDR4) +DECLARE_CSR(pmpaddr5, CSR_PMPADDR5) +DECLARE_CSR(pmpaddr6, CSR_PMPADDR6) +DECLARE_CSR(pmpaddr7, CSR_PMPADDR7) +DECLARE_CSR(pmpaddr8, CSR_PMPADDR8) +DECLARE_CSR(pmpaddr9, CSR_PMPADDR9) +DECLARE_CSR(pmpaddr10, CSR_PMPADDR10) +DECLARE_CSR(pmpaddr11, CSR_PMPADDR11) +DECLARE_CSR(pmpaddr12, CSR_PMPADDR12) +DECLARE_CSR(pmpaddr13, CSR_PMPADDR13) +DECLARE_CSR(pmpaddr14, CSR_PMPADDR14) +DECLARE_CSR(pmpaddr15, CSR_PMPADDR15) +DECLARE_CSR(tselect, CSR_TSELECT) +DECLARE_CSR(tdata1, CSR_TDATA1) +DECLARE_CSR(tdata2, CSR_TDATA2) +DECLARE_CSR(tdata3, CSR_TDATA3) +DECLARE_CSR(tinfo, CSR_TINFO) +DECLARE_CSR(tcontrol, CSR_TCONTROL) +DECLARE_CSR(mcontext, CSR_MCONTEXT) +DECLARE_CSR(scontext, CSR_SCONTEXT) +DECLARE_CSR(dcsr, CSR_DCSR) +DECLARE_CSR(dpc, CSR_DPC) +DECLARE_CSR(dscratch0, CSR_DSCRATCH0) +DECLARE_CSR(dscratch1, CSR_DSCRATCH1) +DECLARE_CSR(mcycle, CSR_MCYCLE) +DECLARE_CSR(minstret, CSR_MINSTRET) +DECLARE_CSR(mhpmcounter3, CSR_MHPMCOUNTER3) +DECLARE_CSR(mhpmcounter4, CSR_MHPMCOUNTER4) +DECLARE_CSR(mhpmcounter5, CSR_MHPMCOUNTER5) +DECLARE_CSR(mhpmcounter6, CSR_MHPMCOUNTER6) +DECLARE_CSR(mhpmcounter7, CSR_MHPMCOUNTER7) +DECLARE_CSR(mhpmcounter8, CSR_MHPMCOUNTER8) +DECLARE_CSR(mhpmcounter9, CSR_MHPMCOUNTER9) +DECLARE_CSR(mhpmcounter10, CSR_MHPMCOUNTER10) +DECLARE_CSR(mhpmcounter11, CSR_MHPMCOUNTER11) +DECLARE_CSR(mhpmcounter12, CSR_MHPMCOUNTER12) +DECLARE_CSR(mhpmcounter13, CSR_MHPMCOUNTER13) +DECLARE_CSR(mhpmcounter14, CSR_MHPMCOUNTER14) +DECLARE_CSR(mhpmcounter15, CSR_MHPMCOUNTER15) +DECLARE_CSR(mhpmcounter16, CSR_MHPMCOUNTER16) +DECLARE_CSR(mhpmcounter17, CSR_MHPMCOUNTER17) +DECLARE_CSR(mhpmcounter18, CSR_MHPMCOUNTER18) +DECLARE_CSR(mhpmcounter19, CSR_MHPMCOUNTER19) +DECLARE_CSR(mhpmcounter20, CSR_MHPMCOUNTER20) +DECLARE_CSR(mhpmcounter21, CSR_MHPMCOUNTER21) +DECLARE_CSR(mhpmcounter22, CSR_MHPMCOUNTER22) +DECLARE_CSR(mhpmcounter23, CSR_MHPMCOUNTER23) +DECLARE_CSR(mhpmcounter24, CSR_MHPMCOUNTER24) +DECLARE_CSR(mhpmcounter25, CSR_MHPMCOUNTER25) +DECLARE_CSR(mhpmcounter26, CSR_MHPMCOUNTER26) +DECLARE_CSR(mhpmcounter27, CSR_MHPMCOUNTER27) +DECLARE_CSR(mhpmcounter28, CSR_MHPMCOUNTER28) +DECLARE_CSR(mhpmcounter29, CSR_MHPMCOUNTER29) +DECLARE_CSR(mhpmcounter30, CSR_MHPMCOUNTER30) +DECLARE_CSR(mhpmcounter31, CSR_MHPMCOUNTER31) +DECLARE_CSR(mhpmevent3, CSR_MHPMEVENT3) +DECLARE_CSR(mhpmevent4, CSR_MHPMEVENT4) +DECLARE_CSR(mhpmevent5, CSR_MHPMEVENT5) +DECLARE_CSR(mhpmevent6, CSR_MHPMEVENT6) +DECLARE_CSR(mhpmevent7, CSR_MHPMEVENT7) +DECLARE_CSR(mhpmevent8, CSR_MHPMEVENT8) +DECLARE_CSR(mhpmevent9, CSR_MHPMEVENT9) +DECLARE_CSR(mhpmevent10, CSR_MHPMEVENT10) +DECLARE_CSR(mhpmevent11, CSR_MHPMEVENT11) +DECLARE_CSR(mhpmevent12, CSR_MHPMEVENT12) +DECLARE_CSR(mhpmevent13, CSR_MHPMEVENT13) +DECLARE_CSR(mhpmevent14, CSR_MHPMEVENT14) +DECLARE_CSR(mhpmevent15, CSR_MHPMEVENT15) +DECLARE_CSR(mhpmevent16, CSR_MHPMEVENT16) +DECLARE_CSR(mhpmevent17, CSR_MHPMEVENT17) +DECLARE_CSR(mhpmevent18, CSR_MHPMEVENT18) +DECLARE_CSR(mhpmevent19, CSR_MHPMEVENT19) +DECLARE_CSR(mhpmevent20, CSR_MHPMEVENT20) +DECLARE_CSR(mhpmevent21, CSR_MHPMEVENT21) +DECLARE_CSR(mhpmevent22, CSR_MHPMEVENT22) +DECLARE_CSR(mhpmevent23, CSR_MHPMEVENT23) +DECLARE_CSR(mhpmevent24, CSR_MHPMEVENT24) +DECLARE_CSR(mhpmevent25, CSR_MHPMEVENT25) +DECLARE_CSR(mhpmevent26, CSR_MHPMEVENT26) +DECLARE_CSR(mhpmevent27, CSR_MHPMEVENT27) +DECLARE_CSR(mhpmevent28, CSR_MHPMEVENT28) +DECLARE_CSR(mhpmevent29, CSR_MHPMEVENT29) +DECLARE_CSR(mhpmevent30, CSR_MHPMEVENT30) +DECLARE_CSR(mhpmevent31, CSR_MHPMEVENT31) +DECLARE_CSR(mvendorid, CSR_MVENDORID) +DECLARE_CSR(marchid, CSR_MARCHID) +DECLARE_CSR(mimpid, CSR_MIMPID) +DECLARE_CSR(mhartid, CSR_MHARTID) +DECLARE_CSR(mentropy, CSR_MENTROPY) +DECLARE_CSR(mnoise, CSR_MNOISE) +DECLARE_CSR(htimedeltah, CSR_HTIMEDELTAH) +DECLARE_CSR(cycleh, CSR_CYCLEH) +DECLARE_CSR(timeh, CSR_TIMEH) +DECLARE_CSR(instreth, CSR_INSTRETH) +DECLARE_CSR(hpmcounter3h, CSR_HPMCOUNTER3H) +DECLARE_CSR(hpmcounter4h, CSR_HPMCOUNTER4H) +DECLARE_CSR(hpmcounter5h, CSR_HPMCOUNTER5H) +DECLARE_CSR(hpmcounter6h, CSR_HPMCOUNTER6H) +DECLARE_CSR(hpmcounter7h, CSR_HPMCOUNTER7H) +DECLARE_CSR(hpmcounter8h, CSR_HPMCOUNTER8H) +DECLARE_CSR(hpmcounter9h, CSR_HPMCOUNTER9H) +DECLARE_CSR(hpmcounter10h, CSR_HPMCOUNTER10H) +DECLARE_CSR(hpmcounter11h, CSR_HPMCOUNTER11H) +DECLARE_CSR(hpmcounter12h, CSR_HPMCOUNTER12H) +DECLARE_CSR(hpmcounter13h, CSR_HPMCOUNTER13H) +DECLARE_CSR(hpmcounter14h, CSR_HPMCOUNTER14H) +DECLARE_CSR(hpmcounter15h, CSR_HPMCOUNTER15H) +DECLARE_CSR(hpmcounter16h, CSR_HPMCOUNTER16H) +DECLARE_CSR(hpmcounter17h, CSR_HPMCOUNTER17H) +DECLARE_CSR(hpmcounter18h, CSR_HPMCOUNTER18H) +DECLARE_CSR(hpmcounter19h, CSR_HPMCOUNTER19H) +DECLARE_CSR(hpmcounter20h, CSR_HPMCOUNTER20H) +DECLARE_CSR(hpmcounter21h, CSR_HPMCOUNTER21H) +DECLARE_CSR(hpmcounter22h, CSR_HPMCOUNTER22H) +DECLARE_CSR(hpmcounter23h, CSR_HPMCOUNTER23H) +DECLARE_CSR(hpmcounter24h, CSR_HPMCOUNTER24H) +DECLARE_CSR(hpmcounter25h, CSR_HPMCOUNTER25H) +DECLARE_CSR(hpmcounter26h, CSR_HPMCOUNTER26H) +DECLARE_CSR(hpmcounter27h, CSR_HPMCOUNTER27H) +DECLARE_CSR(hpmcounter28h, CSR_HPMCOUNTER28H) +DECLARE_CSR(hpmcounter29h, CSR_HPMCOUNTER29H) +DECLARE_CSR(hpmcounter30h, CSR_HPMCOUNTER30H) +DECLARE_CSR(hpmcounter31h, CSR_HPMCOUNTER31H) +DECLARE_CSR(mstatush, CSR_MSTATUSH) +DECLARE_CSR(mcycleh, CSR_MCYCLEH) +DECLARE_CSR(minstreth, CSR_MINSTRETH) +DECLARE_CSR(mhpmcounter3h, CSR_MHPMCOUNTER3H) +DECLARE_CSR(mhpmcounter4h, CSR_MHPMCOUNTER4H) +DECLARE_CSR(mhpmcounter5h, CSR_MHPMCOUNTER5H) +DECLARE_CSR(mhpmcounter6h, CSR_MHPMCOUNTER6H) +DECLARE_CSR(mhpmcounter7h, CSR_MHPMCOUNTER7H) +DECLARE_CSR(mhpmcounter8h, CSR_MHPMCOUNTER8H) +DECLARE_CSR(mhpmcounter9h, CSR_MHPMCOUNTER9H) +DECLARE_CSR(mhpmcounter10h, CSR_MHPMCOUNTER10H) +DECLARE_CSR(mhpmcounter11h, CSR_MHPMCOUNTER11H) +DECLARE_CSR(mhpmcounter12h, CSR_MHPMCOUNTER12H) +DECLARE_CSR(mhpmcounter13h, CSR_MHPMCOUNTER13H) +DECLARE_CSR(mhpmcounter14h, CSR_MHPMCOUNTER14H) +DECLARE_CSR(mhpmcounter15h, CSR_MHPMCOUNTER15H) +DECLARE_CSR(mhpmcounter16h, CSR_MHPMCOUNTER16H) +DECLARE_CSR(mhpmcounter17h, CSR_MHPMCOUNTER17H) +DECLARE_CSR(mhpmcounter18h, CSR_MHPMCOUNTER18H) +DECLARE_CSR(mhpmcounter19h, CSR_MHPMCOUNTER19H) +DECLARE_CSR(mhpmcounter20h, CSR_MHPMCOUNTER20H) +DECLARE_CSR(mhpmcounter21h, CSR_MHPMCOUNTER21H) +DECLARE_CSR(mhpmcounter22h, CSR_MHPMCOUNTER22H) +DECLARE_CSR(mhpmcounter23h, CSR_MHPMCOUNTER23H) +DECLARE_CSR(mhpmcounter24h, CSR_MHPMCOUNTER24H) +DECLARE_CSR(mhpmcounter25h, CSR_MHPMCOUNTER25H) +DECLARE_CSR(mhpmcounter26h, CSR_MHPMCOUNTER26H) +DECLARE_CSR(mhpmcounter27h, CSR_MHPMCOUNTER27H) +DECLARE_CSR(mhpmcounter28h, CSR_MHPMCOUNTER28H) +DECLARE_CSR(mhpmcounter29h, CSR_MHPMCOUNTER29H) +DECLARE_CSR(mhpmcounter30h, CSR_MHPMCOUNTER30H) +DECLARE_CSR(mhpmcounter31h, CSR_MHPMCOUNTER31H) +#endif +#ifdef DECLARE_CAUSE +DECLARE_CAUSE("misaligned fetch", CAUSE_MISALIGNED_FETCH) +DECLARE_CAUSE("fetch access", CAUSE_FETCH_ACCESS) +DECLARE_CAUSE("illegal instruction", CAUSE_ILLEGAL_INSTRUCTION) +DECLARE_CAUSE("breakpoint", CAUSE_BREAKPOINT) +DECLARE_CAUSE("misaligned load", CAUSE_MISALIGNED_LOAD) +DECLARE_CAUSE("load access", CAUSE_LOAD_ACCESS) +DECLARE_CAUSE("misaligned store", CAUSE_MISALIGNED_STORE) +DECLARE_CAUSE("store access", CAUSE_STORE_ACCESS) +DECLARE_CAUSE("user_ecall", CAUSE_USER_ECALL) +DECLARE_CAUSE("supervisor_ecall", CAUSE_SUPERVISOR_ECALL) +DECLARE_CAUSE("virtual_supervisor_ecall", CAUSE_VIRTUAL_SUPERVISOR_ECALL) +DECLARE_CAUSE("machine_ecall", CAUSE_MACHINE_ECALL) +DECLARE_CAUSE("fetch page fault", CAUSE_FETCH_PAGE_FAULT) +DECLARE_CAUSE("load page fault", CAUSE_LOAD_PAGE_FAULT) +DECLARE_CAUSE("store page fault", CAUSE_STORE_PAGE_FAULT) +DECLARE_CAUSE("fetch guest page fault", CAUSE_FETCH_GUEST_PAGE_FAULT) +DECLARE_CAUSE("load guest page fault", CAUSE_LOAD_GUEST_PAGE_FAULT) +DECLARE_CAUSE("virtual instruction", CAUSE_VIRTUAL_INSTRUCTION) +DECLARE_CAUSE("store guest page fault", CAUSE_STORE_GUEST_PAGE_FAULT) +#endif diff --git sys/arch/loongarch64/loongarch64/db_interface.c sys/arch/loongarch64/loongarch64/db_interface.c new file mode 100644 index 00000000000..db767f0f0f5 --- /dev/null +++ sys/arch/loongarch64/loongarch64/db_interface.c @@ -0,0 +1,459 @@ +/* $OpenBSD: db_interface.c,v 1.10 2024/10/17 01:57:18 jsg Exp $ */ + +/* + * Copyright (c) 1996 Scott K. Stevens + * + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + * + * From: db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU) + */ + +/* + * Interface to new debugger. + */ +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +struct db_variable db_regs[] = { + { "ra", (long *)&DDB_REGS->tf_ra, FCN_NULL, }, /* x1 */ + { "sp", (long *)&DDB_REGS->tf_sp, FCN_NULL, }, /* x2 */ + { "gp", (long *)&DDB_REGS->tf_gp, FCN_NULL, }, /* x3 */ + { "tp", (long *)&DDB_REGS->tf_tp, FCN_NULL, }, /* x4 */ + { "t0", (long *)&DDB_REGS->tf_t[0], FCN_NULL, }, /* x5 */ + { "t1", (long *)&DDB_REGS->tf_t[1], FCN_NULL, }, /* x6 */ + { "t2", (long *)&DDB_REGS->tf_t[2], FCN_NULL, }, /* x7 */ + { "s0", (long *)&DDB_REGS->tf_s[0], FCN_NULL, }, /* x8 */ + { "s1", (long *)&DDB_REGS->tf_s[1], FCN_NULL, }, /* x9 */ + { "a0", (long *)&DDB_REGS->tf_a[0], FCN_NULL, }, /* x10 */ + { "a1", (long *)&DDB_REGS->tf_a[1], FCN_NULL, }, /* x11 */ + { "a2", (long *)&DDB_REGS->tf_a[2], FCN_NULL, }, /* x12 */ + { "a3", (long *)&DDB_REGS->tf_a[3], FCN_NULL, }, /* x13 */ + { "a4", (long *)&DDB_REGS->tf_a[4], FCN_NULL, }, /* x14 */ + { "a5", (long *)&DDB_REGS->tf_a[5], FCN_NULL, }, /* x15 */ + { "a6", (long *)&DDB_REGS->tf_a[6], FCN_NULL, }, /* x16 */ + { "a7", (long *)&DDB_REGS->tf_a[7], FCN_NULL, }, /* x17 */ + { "s2", (long *)&DDB_REGS->tf_s[2], FCN_NULL, }, /* x18 */ + { "s3", (long *)&DDB_REGS->tf_s[3], FCN_NULL, }, /* x19 */ + { "s4", (long *)&DDB_REGS->tf_s[4], FCN_NULL, }, /* x20 */ + { "s5", (long *)&DDB_REGS->tf_s[5], FCN_NULL, }, /* x21 */ + { "s6", (long *)&DDB_REGS->tf_s[6], FCN_NULL, }, /* x22 */ + { "s7", (long *)&DDB_REGS->tf_s[7], FCN_NULL, }, /* x23 */ + { "s8", (long *)&DDB_REGS->tf_s[8], FCN_NULL, }, /* x24 */ + { "s9", (long *)&DDB_REGS->tf_s[9], FCN_NULL, }, /* x25 */ + { "s10", (long *)&DDB_REGS->tf_s[10], FCN_NULL, }, /* x26 */ + { "s11", (long *)&DDB_REGS->tf_s[11], FCN_NULL, }, /* x27 */ + { "t3", (long *)&DDB_REGS->tf_t[3], FCN_NULL, }, /* x28 */ + { "t4", (long *)&DDB_REGS->tf_t[4], FCN_NULL, }, /* x29 */ + { "t5", (long *)&DDB_REGS->tf_t[5], FCN_NULL, }, /* x30 */ + { "t6", (long *)&DDB_REGS->tf_t[6], FCN_NULL, } /* x31 */ +}; + +#ifdef MULTIPROCESSOR +struct db_mutex ddb_mp_mutex = DB_MUTEX_INITIALIZER; +volatile int ddb_state = DDB_STATE_NOT_RUNNING; +volatile cpuid_t ddb_active_cpu; +int db_switch_cpu; +long db_switch_to_cpu; + +void db_cpuinfo_cmd(db_expr_t, int, db_expr_t, char *); +void db_startproc_cmd(db_expr_t, int, db_expr_t, char *); +void db_stopproc_cmd(db_expr_t, int, db_expr_t, char *); +void db_ddbproc_cmd(db_expr_t, int, db_expr_t, char *); +void db_stopcpu(int cpu); +void db_startcpu(int cpu); +int db_enter_ddb(void); +#endif + +extern label_t *db_recover; + +struct db_variable *db_eregs = db_regs + nitems(db_regs); + +#ifdef DDB +/* + * kdb_trap - field a TRACE or BPT trap + */ +int +kdb_trap(int type, db_regs_t *regs) +{ + int s; + +#ifdef MULTIPROCESSOR + db_mtx_enter(&ddb_mp_mutex); + if (ddb_state == DDB_STATE_EXITING) + ddb_state = DDB_STATE_NOT_RUNNING; + db_mtx_leave(&ddb_mp_mutex); + while (db_enter_ddb()) { +#endif + + switch (type) { + case T_BREAKPOINT: /* breakpoint */ + case -1: /* keyboard interrupt */ + break; + default: + if (db_recover != 0) { + db_error("Faulted in DDB; continuing...\n"); + /* NOTREACHED */ + } + } + + ddb_regs = *regs; + + s = splhigh(); + db_active++; + cnpollc(1); + db_trap(type, 0/*code*/); + cnpollc(0); + db_active--; + splx(s); + + *regs = ddb_regs; + +#ifdef MULTIPROCESSOR + if (!db_switch_cpu) + ddb_state = DDB_STATE_EXITING; + } +#endif + return (1); +} +#endif + +#define INKERNEL(va) (((vaddr_t)(va)) & (1ULL << 63)) + +static int db_validate_address(vaddr_t addr); + +static int +db_validate_address(vaddr_t addr) +{ + struct proc *p = curproc; + struct pmap *pmap; + + if (!p || !p->p_vmspace || !p->p_vmspace->vm_map.pmap || + INKERNEL(addr)) + pmap = pmap_kernel(); + else + pmap = p->p_vmspace->vm_map.pmap; + + return (pmap_extract(pmap, addr, NULL) == FALSE); +} + +/* + * Read bytes from kernel address space for debugger. + */ +void +db_read_bytes(vaddr_t addr, size_t size, void *datap) +{ + char *data = datap, *src = (char *)addr; + + if (db_validate_address((vaddr_t)src)) { + db_printf("address %p is invalid\n", src); + return; + } + + if (size == 8 && (addr & 7) == 0 && ((vaddr_t)data & 7) == 0) { + *((uint64_t*)data) = *((uint64_t*)src); + return; + } + + if (size == 4 && (addr & 3) == 0 && ((vaddr_t)data & 3) == 0) { + *((int*)data) = *((int*)src); + return; + } + + if (size == 2 && (addr & 1) == 0 && ((vaddr_t)data & 1) == 0) { + *((short*)data) = *((short*)src); + return; + } + + while (size-- > 0) { + if (db_validate_address((vaddr_t)src)) { + db_printf("address %p is invalid\n", src); + return; + } + *data++ = *src++; + } +} + + +/* + * Write bytes to kernel address space for debugger. + */ +void +db_write_bytes(vaddr_t addr, size_t size, void *datap) +{ + // XXX +} + +void +db_enter(void) +{ + asm("break 0"); +} + + +#ifdef MULTIPROCESSOR +void +db_cpuinfo_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) +{ + int i; + + for (i = 0; i < MAXCPUS; i++) { + if (cpu_info[i] != NULL) { + db_printf("%c%4d: ", (i == cpu_number()) ? '*' : ' ', + CPU_INFO_UNIT(cpu_info[i])); + switch(cpu_info[i]->ci_ddb_paused) { + case CI_DDB_RUNNING: + db_printf("running\n"); + break; + case CI_DDB_SHOULDSTOP: + db_printf("stopping\n"); + break; + case CI_DDB_STOPPED: + db_printf("stopped\n"); + break; + case CI_DDB_ENTERDDB: + db_printf("entering ddb\n"); + break; + case CI_DDB_INDDB: + db_printf("ddb\n"); + break; + default: + db_printf("? (%d)\n", + cpu_info[i]->ci_ddb_paused); + break; + } + } + } +} + +void +db_startproc_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) +{ + int i; + + if (have_addr) { + if (addr >= 0 && addr < MAXCPUS && + cpu_info[addr] != NULL && addr != cpu_number()) + db_startcpu(addr); + else + db_printf("Invalid cpu %d\n", (int)addr); + } else { + for (i = 0; i < MAXCPUS; i++) { + if (cpu_info[i] != NULL && i != cpu_number()) + db_startcpu(i); + } + } +} + +void +db_stopproc_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) +{ + int i; + + if (have_addr) { + if (addr >= 0 && addr < MAXCPUS && + cpu_info[addr] != NULL && addr != cpu_number()) + db_stopcpu(addr); + else + db_printf("Invalid cpu %d\n", (int)addr); + } else { + for (i = 0; i < MAXCPUS; i++) { + if (cpu_info[i] != NULL && i != cpu_number()) + db_stopcpu(i); + } + } +} + +void +db_ddbproc_cmd(db_expr_t addr, int have_addr, db_expr_t count, char *modif) +{ + if (have_addr) { + if (addr >= 0 && addr < MAXCPUS && + cpu_info[addr] != NULL && addr != cpu_number()) { + db_stopcpu(addr); + db_switch_to_cpu = addr; + db_switch_cpu = 1; + db_cmd_loop_done = 1; + } else { + db_printf("Invalid cpu %d\n", (int)addr); + } + } else { + db_printf("CPU not specified\n"); + } +} + +int +db_enter_ddb(void) +{ + int i; + + db_mtx_enter(&ddb_mp_mutex); + + /* If we are first in, grab ddb and stop all other CPUs */ + if (ddb_state == DDB_STATE_NOT_RUNNING) { + ddb_active_cpu = cpu_number(); + ddb_state = DDB_STATE_RUNNING; + curcpu()->ci_ddb_paused = CI_DDB_INDDB; + db_mtx_leave(&ddb_mp_mutex); + for (i = 0; i < MAXCPUS; i++) { + if (cpu_info[i] != NULL && i != cpu_number() && + cpu_info[i]->ci_ddb_paused != CI_DDB_STOPPED) { + cpu_info[i]->ci_ddb_paused = CI_DDB_SHOULDSTOP; + intr_send_ipi(cpu_info[i], IPI_DDB); + } + } + return (1); + } + + /* Leaving ddb completely. Start all other CPUs and return 0 */ + if (ddb_active_cpu == cpu_number() && ddb_state == DDB_STATE_EXITING) { + for (i = 0; i < MAXCPUS; i++) { + if (cpu_info[i] != NULL) { + cpu_info[i]->ci_ddb_paused = CI_DDB_RUNNING; + } + } + db_mtx_leave(&ddb_mp_mutex); + return (0); + } + + /* We're switching to another CPU. db_ddbproc_cmd() has made sure + * it is waiting for ddb, we just have to set ddb_active_cpu. */ + if (ddb_active_cpu == cpu_number() && db_switch_cpu) { + curcpu()->ci_ddb_paused = CI_DDB_SHOULDSTOP; + db_switch_cpu = 0; + ddb_active_cpu = db_switch_to_cpu; + cpu_info[db_switch_to_cpu]->ci_ddb_paused = CI_DDB_ENTERDDB; + } + + /* Wait until we should enter ddb or resume */ + while (ddb_active_cpu != cpu_number() && + curcpu()->ci_ddb_paused != CI_DDB_RUNNING) { + if (curcpu()->ci_ddb_paused == CI_DDB_SHOULDSTOP) + curcpu()->ci_ddb_paused = CI_DDB_STOPPED; + db_mtx_leave(&ddb_mp_mutex); + + /* Busy wait without locking, we'll confirm with lock later */ + while (ddb_active_cpu != cpu_number() && + curcpu()->ci_ddb_paused != CI_DDB_RUNNING) + CPU_BUSY_CYCLE(); + + db_mtx_enter(&ddb_mp_mutex); + } + + /* Either enter ddb or exit */ + if (ddb_active_cpu == cpu_number() && ddb_state == DDB_STATE_RUNNING) { + curcpu()->ci_ddb_paused = CI_DDB_INDDB; + db_mtx_leave(&ddb_mp_mutex); + return (1); + } else { + db_mtx_leave(&ddb_mp_mutex); + return (0); + } +} + +void +db_startcpu(int cpu) +{ + if (cpu != cpu_number() && cpu_info[cpu] != NULL) { + db_mtx_enter(&ddb_mp_mutex); + cpu_info[cpu]->ci_ddb_paused = CI_DDB_RUNNING; + db_mtx_leave(&ddb_mp_mutex); + } +} + +void +db_stopcpu(int cpu) +{ + db_mtx_enter(&ddb_mp_mutex); + if (cpu != cpu_number() && cpu_info[cpu] != NULL && + cpu_info[cpu]->ci_ddb_paused != CI_DDB_STOPPED) { + cpu_info[cpu]->ci_ddb_paused = CI_DDB_SHOULDSTOP; + db_mtx_leave(&ddb_mp_mutex); + intr_send_ipi(cpu_info[cpu], IPI_DDB); + } else { + db_mtx_leave(&ddb_mp_mutex); + } +} +#endif + +const struct db_command db_machine_command_table[] = { +#ifdef MULTIPROCESSOR + { "cpuinfo", db_cpuinfo_cmd, 0, NULL }, + { "startcpu", db_startproc_cmd, 0, NULL }, + { "stopcpu", db_stopproc_cmd, 0, NULL }, + { "ddbcpu", db_ddbproc_cmd, 0, NULL }, +#endif + { NULL, NULL, 0, NULL } +}; + +int +db_trapper(vaddr_t addr, u_int inst, trapframe_t *frame, int fault_code) +{ + + if (fault_code == EXCP_BRK) { + kdb_trap(T_BREAKPOINT, frame); + frame->tf_sepc += 4; + } else + kdb_trap(-1, frame); + + return (0); +} + + +extern vaddr_t esym; +extern vaddr_t end; + +void +db_machine_init(void) +{ +#ifdef MULTIPROCESSOR + int i; + + for (i = 0; i < MAXCPUS; i++) { + if (cpu_info[i] != NULL) + cpu_info[i]->ci_ddb_paused = CI_DDB_RUNNING; + } +#endif +} + +vaddr_t +db_branch_taken(u_int insn, vaddr_t pc, db_regs_t *db_regs) +{ + // XXX + return pc + 4; +} diff --git sys/arch/loongarch64/loongarch64/db_trace.c sys/arch/loongarch64/loongarch64/db_trace.c new file mode 100644 index 00000000000..a84898e9326 --- /dev/null +++ sys/arch/loongarch64/loongarch64/db_trace.c @@ -0,0 +1,139 @@ +/* $OpenBSD: db_trace.c,v 1.7 2024/11/07 16:02:29 miod Exp $ */ + +/* + * Copyright (c) 2000, 2001 Ben Harris + * Copyright (c) 1996 Scott K. Stevens + * + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include +#include + +#include + +#include +#include +#include +#include + +extern unsigned char cpu_exception_handler_supervisor[]; +extern unsigned char cpu_exception_handler_user[]; + +db_regs_t ddb_regs; + +#define INKERNEL(va) (((vaddr_t)(va)) & (1ULL << 63)) + +void +db_stack_trace_print(db_expr_t addr, int have_addr, db_expr_t count, + char *modif, int (*pr)(const char *, ...)) +{ + vaddr_t frame, lastframe, ra, subr; + char c, *cp = modif; + db_expr_t offset; + Elf_Sym * sym; + const char *name; + int kernel_only = 1; + + while ((c = *cp++) != 0) { + if (c == 'u') + kernel_only = 0; + if (c == 't') { + db_printf("tracing threads not yet supported\n"); + return; + } + } + + if (!have_addr) { + ra = ddb_regs.tf_ra; + frame = ddb_regs.tf_s[0]; + } else { + db_read_bytes(addr - 16, sizeof(vaddr_t), (char *)&frame); + db_read_bytes(addr - 8, sizeof(vaddr_t), (char *)&ra); + } + + while (count != 0 && frame != 0) { + if (INKERNEL(frame)) { + sym = db_search_symbol(ra, DB_STGY_ANY, &offset); + db_symbol_values(sym, &name, NULL); + } else { + sym = NULL; + name = NULL; + } + + if (name == NULL || strcmp(name, "end") == 0) { + (*pr)("%llx() at 0x%lx", ra, ra); + } else { + (*pr)("%s() at ", name); + db_printsym(ra, DB_STGY_PROC, pr); + } + (*pr)("\n"); + + if ((frame & 0x7) != 0) { + (*pr)("bad frame pointer: 0x%lx\n", frame); + break; + } + + subr = 0; + if (sym != NULL) + subr = ra - (vaddr_t)offset; + + lastframe = frame; + if (subr == (vaddr_t)cpu_exception_handler_supervisor || + subr == (vaddr_t)cpu_exception_handler_user) { + struct trapframe *tf = (struct trapframe *)frame; + + db_read_bytes((vaddr_t)&tf->tf_ra, sizeof(ra), + (char *)&ra); + db_read_bytes((vaddr_t)&tf->tf_s[0], sizeof(frame), + (char *)&frame); + } else { + db_read_bytes(frame - 16, sizeof(frame), + (char *)&frame); + if (frame == 0) + break; + if ((frame & 0x7) != 0) { + (*pr)("bad frame pointer: 0x%lx\n", frame); + break; + } + db_read_bytes(frame - 8, sizeof(ra), (char *)&ra); + } + + if (INKERNEL(frame)) { + if (frame <= lastframe) { + (*pr)("bad frame pointer: 0x%lx\n", frame); + break; + } + } else { + if (kernel_only) { + (*pr)("end of kernel\n"); + break; + } + } + + --count; + } + (*pr)("end trace frame: 0x%lx, count: %d\n", frame, count); +} diff --git sys/arch/loongarch64/loongarch64/disksubr.c sys/arch/loongarch64/loongarch64/disksubr.c new file mode 100644 index 00000000000..dfcba3ed144 --- /dev/null +++ sys/arch/loongarch64/loongarch64/disksubr.c @@ -0,0 +1,131 @@ +/* $OpenBSD: disksubr.c,v 1.2 2021/05/12 01:20:52 jsg Exp $ */ + +/* + * Copyright (c) 1996 Theo de Raadt + * Copyright (c) 1982, 1986, 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +/* + * Attempt to read a disk label from a device + * using the indicated strategy routine. + * The label must be partly set up before this: + * secpercyl, secsize and anything required for a block i/o read + * operation in the driver's strategy/start routines + * must be filled in before calling us. + * + * If dos partition table requested, attempt to load it and + * find disklabel inside a DOS partition. + * + * We would like to check if each MBR has a valid DOSMBR_SIGNATURE, but + * we cannot because it doesn't always exist. So.. we assume the + * MBR is valid. + */ +int +readdisklabel(dev_t dev, void (*strat)(struct buf *), + struct disklabel *lp, int spoofonly) +{ + struct buf *bp = NULL; + int error; + + if ((error = initdisklabel(lp))) + goto done; + + /* get a buffer and initialize it */ + bp = geteblk(lp->d_secsize); + bp->b_dev = dev; + + error = readdoslabel(bp, strat, lp, NULL, spoofonly); + if (error == 0) + goto done; + +#if defined(CD9660) + error = iso_disklabelspoof(dev, strat, lp); + if (error == 0) + goto done; +#endif +#if defined(UDF) + error = udf_disklabelspoof(dev, strat, lp); + if (error == 0) + goto done; +#endif + +done: + if (bp) { + bp->b_flags |= B_INVAL; + brelse(bp); + } + disk_change = 1; + return (error); +} + +/* + * Write disk label back to device after modification. + */ +int +writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp) +{ + daddr_t partoff = -1; + int error = EIO; + int offset; + struct disklabel *dlp; + struct buf *bp = NULL; + + /* get a buffer and initialize it */ + bp = geteblk(lp->d_secsize); + bp->b_dev = dev; + + if (readdoslabel(bp, strat, lp, &partoff, 1) != 0) + goto done; + + /* Read it in, slap the new label in, and write it back out */ + error = readdisksector(bp, strat, lp, DL_BLKTOSEC(lp, partoff + + DOS_LABELSECTOR)); + if (error) + goto done; + offset = DL_BLKOFFSET(lp, partoff + DOS_LABELSECTOR); + + dlp = (struct disklabel *)(bp->b_data + offset); + *dlp = *lp; + CLR(bp->b_flags, B_READ | B_WRITE | B_DONE); + SET(bp->b_flags, B_BUSY | B_WRITE | B_RAW); + (*strat)(bp); + error = biowait(bp); + +done: + if (bp) { + bp->b_flags |= B_INVAL; + brelse(bp); + } + disk_change = 1; + return (error); +} diff --git sys/arch/loongarch64/loongarch64/exception.S sys/arch/loongarch64/loongarch64/exception.S new file mode 100644 index 00000000000..939bad58a8d --- /dev/null +++ sys/arch/loongarch64/loongarch64/exception.S @@ -0,0 +1,237 @@ +/* $OpenBSD: exception.S,v 1.11 2026/05/26 14:12:34 kettenis Exp $ */ + +/*- + * Copyright (c) 2015-2018 Ruslan Bukin + * All rights reserved. + * + * Portions of this software were developed by SRI International and the + * University of Cambridge Computer Laboratory under DARPA/AFRL contract + * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. + * + * Portions of this software were developed by the University of Cambridge + * Computer Laboratory as part of the CTSRD Project, with support from the + * UK Higher Education Innovation Fund (HEIF). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "assym.h" +#include +#include + +.macro save_registers mode + addi.d $sp, $sp, -(TRAPFRAME_SIZEOF) + + st.d $ra, $sp, TF_RA + +.if \mode == 0 /* We came from userspace. */ + st.d $a0, $sp, TF_GP + + /* Load our pcpu */ + st.d $tp, $sp, TF_TP + ld.d $tp, $sp, TRAPFRAME_SIZEOF +.endif + + st.d $t0, $sp, (TF_T + 0 * 8) + st.d $t1, $sp, (TF_T + 1 * 8) + st.d $t2, $sp, (TF_T + 2 * 8) + st.d $t3, $sp, (TF_T + 3 * 8) + st.d $t4, $sp, (TF_T + 4 * 8) + st.d $t5, $sp, (TF_T + 5 * 8) + st.d $t6, $sp, (TF_T + 6 * 8) + + st.d $s0, $sp, (TF_S + 0 * 8) + st.d $s1, $sp, (TF_S + 1 * 8) + st.d $s2, $sp, (TF_S + 2 * 8) + st.d $s3, $sp, (TF_S + 3 * 8) + st.d $s4, $sp, (TF_S + 4 * 8) + st.d $s5, $sp, (TF_S + 5 * 8) + st.d $s6, $sp, (TF_S + 6 * 8) + st.d $s7, $sp, (TF_S + 7 * 8) + st.d $s8, $sp, (TF_S + 8 * 8) + + st.d $a0, $sp, (TF_A + 0 * 8) + st.d $a1, $sp, (TF_A + 1 * 8) + st.d $a2, $sp, (TF_A + 2 * 8) + st.d $a3, $sp, (TF_A + 3 * 8) + st.d $a4, $sp, (TF_A + 4 * 8) + st.d $a5, $sp, (TF_A + 5 * 8) + st.d $a6, $sp, (TF_A + 6 * 8) + st.d $a7, $sp, (TF_A + 7 * 8) + +.if \mode == 1 + /* Store kernel sp */ + li.d $t1, TRAPFRAME_SIZEOF + add.d $t0, $sp, $t1 + st.d $t0, $sp, TF_SP +.else + /* Store user sp */ + csrrd $t0, 0x30 + st.d $t0, $sp, TF_SP +.endif + li.d $t0, 0 + csrwr $t0, 0x30 + csrrd $t0, 0x6 + st.d $t0, $sp, TF_SEPC + csrrd $t0, 0x0 + st.d $t0, $sp, TF_SSTATUS +.if \mode == 1 + /* Disable user address access for supervisor mode exceptions. */ +.endif + csrrd $t0, 0x07 + st.d $t0, $sp, TF_STVAL + csrrd $t0, 0x05 + st.d $t0, $sp, TF_SCAUSE +.endm + +.macro restore_registers mode + ld.d $t0, $sp, TF_SSTATUS +.if \mode == 0 + /* Ensure user interrupts will be enabled on eret */ + li.d $t1, (1 << 2) + or $t0, $t0, $t1 +.else + /* + * Disable interrupts for supervisor mode exceptions. + * For user mode exceptions we have already done this + * in do_ast. + */ + li.d $t1, ~(1 << 2) + and $t0, $t0, $t1 +.endif + + ld.d $t0, $sp, TF_SEPC + csrwr $t0, 0x6 + ertn + +.if \mode == 0 + /* We go to userspace. Load user sp */ + ld.d $t0, $sp, TF_SP + csrwr $t0, 0x30 + + /* Store our pcpu */ + st.d $tp, $sp, TRAPFRAME_SIZEOF + ld.d $tp, $sp, TF_TP + + /* And restore the user's global pointer */ + ld.d $a0, $sp, TF_GP +.endif + + ld.d $ra, $sp, TF_RA + + ld.d $t0, $sp, (TF_T + 0 * 8) + ld.d $t1, $sp, (TF_T + 1 * 8) + ld.d $t2, $sp, (TF_T + 2 * 8) + ld.d $t3, $sp, (TF_T + 3 * 8) + ld.d $t4, $sp, (TF_T + 4 * 8) + ld.d $t5, $sp, (TF_T + 5 * 8) + ld.d $t6, $sp, (TF_T + 6 * 8) + + ld.d $s0, $sp, (TF_S + 0 * 8) + ld.d $s1, $sp, (TF_S + 1 * 8) + ld.d $s2, $sp, (TF_S + 2 * 8) + ld.d $s3, $sp, (TF_S + 3 * 8) + ld.d $s4, $sp, (TF_S + 4 * 8) + ld.d $s5, $sp, (TF_S + 5 * 8) + ld.d $s6, $sp, (TF_S + 6 * 8) + ld.d $s7, $sp, (TF_S + 7 * 8) + ld.d $s8, $sp, (TF_S + 8 * 8) + + ld.d $a0, $sp, (TF_A + 0 * 8) + ld.d $a1, $sp, (TF_A + 1 * 8) + ld.d $a2, $sp, (TF_A + 2 * 8) + ld.d $a3, $sp, (TF_A + 3 * 8) + ld.d $a4, $sp, (TF_A + 4 * 8) + ld.d $a5, $sp, (TF_A + 5 * 8) + ld.d $a6, $sp, (TF_A + 6 * 8) + ld.d $a7, $sp, (TF_A + 7 * 8) + + addi.d $sp, $sp, TRAPFRAME_SIZEOF +.endm + +.macro do_ast +1: + /* Disable interrupts */ + li.d $t0, 0x4 + or $t1, $zero, $zero + csrxchg $t1, $t0, 0x0 + + /* Check for astpending */ + ld.d $a1, $tp, CI_CURPROC + beqz $a1, 2f + ld.w $a2, $a1, P_ASTPENDING + beqz $a2, 2f + + st.w $zero, $a1, P_ASTPENDING + + /* Enable interrupts */ + li.d $t0, 0x4 + csrxchg $t0, $t0, 0x0 + + /* handle the ast */ + move $a0, $sp + bl ast + b 1b +2: +.endm + + /* + * cpu_exception_handler needs to be aligned to a 32-bit + * boundary, but ENTRY() only enforces 16-bit alignment. + */ + .text + .p2align 2 +ENTRY(cpu_exception_handler) + csrrd $sp, 0x30 + beqz $sp, 1f + /* User mode detected */ + b cpu_exception_handler_user +1: + /* Supervisor mode detected */ + csrrd $sp, 0x30 + b cpu_exception_handler_supervisor +END(cpu_exception_handler) + +ENTRY(cpu_exception_handler_supervisor) + save_registers 1 + move $a0, $sp + bl do_trap_supervisor + restore_registers 1 + ertn +END(cpu_exception_handler_supervisor) + +ENTRY(cpu_exception_handler_user) + save_registers 0 + move $a0, $sp + bl do_trap_user + do_ast + restore_registers 0 + csrrd $sp, 0x30 + ertn +END(cpu_exception_handler_user) + +ENTRY(syscall_return) + do_ast + restore_registers 0 + csrrd $sp, 0x30 + ertn +END(syscall_return) diff --git sys/arch/loongarch64/loongarch64/fpu.c sys/arch/loongarch64/loongarch64/fpu.c new file mode 100644 index 00000000000..b4f2780e22e --- /dev/null +++ sys/arch/loongarch64/loongarch64/fpu.c @@ -0,0 +1,42 @@ +/* $OpenBSD: fpu.c,v 1.12 2024/10/17 01:57:18 jsg Exp $ */ + +/* + * Copyright (c) 2020 Dale Rahn + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +void +fpu_disable(void) +{ +} + +void +fpu_enable_clean(void) +{ +} + +void +fpu_save(struct proc *p, struct trapframe *tf) +{ +} + +void +fpu_load(struct proc *p) +{ +} diff --git sys/arch/loongarch64/loongarch64/genassym.cf sys/arch/loongarch64/loongarch64/genassym.cf new file mode 100644 index 00000000000..5b24fad48d3 --- /dev/null +++ sys/arch/loongarch64/loongarch64/genassym.cf @@ -0,0 +1,72 @@ +# $OpenBSD: genassym.cf,v 1.8 2024/04/06 18:33:54 kettenis Exp $ +# +# Copyright (c) 2020 Brian Bamsch +# All rights reserved. +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +include +include + +include +include +include +include +include + +struct trapframe +member tf_ra +member tf_sp +member tf_gp +member tf_tp +member tf_t +member tf_s +member tf_a +member tf_sepc +member tf_sstatus +member tf_stval +member tf_scause + +struct switchframe +member sf_s +member sf_ra + +struct proc +member p_stat +member p_cpu +member p_addr +member p_astpending p_md.md_astpending + +export SONPROC + +struct sigframe +member sf_sc + +struct pcb +member pcb_sp +member pcb_onfault + +struct cpu_info +member ci_self +member ci_curproc +member ci_curpcb +ifdef MULTIPROCESSOR +member ci_satp +member ci_initstack_end +endif + +struct loongarch_bootparams +member LOONGARCH_BOOTPARAMS_KERN_L1PT kern_l1pt +member LOONGARCH_BOOTPARAMS_KERN_PHYS kern_phys +member LOONGARCH_BOOTPARAMS_KERN_STACK kern_stack +member LOONGARCH_BOOTPARAMS_DTBP_PHYS dtbp_phys diff --git sys/arch/loongarch64/loongarch64/intr.c sys/arch/loongarch64/loongarch64/intr.c new file mode 100644 index 00000000000..9e03345bf81 --- /dev/null +++ sys/arch/loongarch64/loongarch64/intr.c @@ -0,0 +1,769 @@ +/* $OpenBSD: intr.c,v 1.17 2026/03/08 17:07:31 deraadt Exp $ */ + +/* + * Copyright (c) 2011 Dale Rahn + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +int loongarch_intr_get_parent(int); +uint32_t loongarch_intr_map_msi(int, uint64_t *); + +void *loongarch_intr_prereg_establish_fdt(void *, int *, int, struct cpu_info *, + int (*)(void *), void *, char *); +void loongarch_intr_prereg_disestablish_fdt(void *); +void loongarch_intr_prereg_barrier_fdt(void *); + +int loongarch_dflt_splraise(int); +int loongarch_dflt_spllower(int); +void loongarch_dflt_splx(int); +void loongarch_dflt_setipl(int); + +void loongarch_dflt_intr(void *); +void loongarch_cpu_intr(void *); + +#define SI_TO_IRQBIT(x) (1 << (x)) +uint32_t loongarch_smask[NIPL]; + +struct loongarch_intr_func loongarch_intr_func = { + loongarch_dflt_splraise, + loongarch_dflt_spllower, + loongarch_dflt_splx, + loongarch_dflt_setipl +}; + +void +loongarch_dflt_intr(void *frame) +{ + panic("%s", __func__); +} + +void (*loongarch_intr_dispatch)(void *) = loongarch_dflt_intr; + +void +loongarch_cpu_intr(void *frame) +{ + struct cpu_info *ci = curcpu(); + + atomic_inc_int(&uvmexp.intrs); + ci->ci_idepth++; + (*loongarch_intr_dispatch)(frame); + ci->ci_idepth--; +} + +/* + * Find the interrupt parent by walking up the tree. + */ +int +loongarch_intr_get_parent(int node) +{ + uint32_t phandle; + + while (node) { + phandle = OF_getpropint(node, "interrupt-parent", 0); + if (phandle) + return OF_getnodebyphandle(phandle); + node = OF_parent(node); + if (OF_getpropbool(node, "interrupt-controller")) + return node; + } + + return 0; +} + +uint32_t +loongarch_intr_map_msi(int node, uint64_t *data) +{ + uint64_t msi_base; + uint32_t phandle = 0; + uint32_t *cell; + uint32_t *map; + uint32_t mask, rid_base, rid; + int i, len, length, mcells, ncells; + + len = OF_getproplen(node, "msi-map"); + if (len <= 0) { + while (node && !phandle) { + phandle = OF_getpropint(node, "msi-parent", 0); + node = OF_parent(node); + } + + return phandle; + } + + map = malloc(len, M_TEMP, M_WAITOK); + OF_getpropintarray(node, "msi-map", map, len); + + mask = OF_getpropint(node, "msi-map-mask", 0xffff); + rid = *data & mask; + + cell = map; + ncells = len / sizeof(uint32_t); + while (ncells > 1) { + node = OF_getnodebyphandle(cell[1]); + if (node == 0) + goto out; + + /* + * Some device trees (e.g. those for the Rockchip + * RK3399 boards) are missing a #msi-cells property. + * Assume the msi-specifier uses a single cell in that + * case. + */ + mcells = OF_getpropint(node, "#msi-cells", 1); + if (ncells < mcells + 3) + goto out; + + rid_base = cell[0]; + length = cell[2 + mcells]; + msi_base = cell[2]; + for (i = 1; i < mcells; i++) { + msi_base <<= 32; + msi_base |= cell[2 + i]; + } + if (rid >= rid_base && rid < rid_base + length) { + *data = msi_base + (rid - rid_base); + phandle = cell[1]; + break; + } + + cell += (3 + mcells); + ncells -= (3 + mcells); + } + +out: + free(map, M_TEMP, len); + return phandle; +} + +/* + * Interrupt pre-registration. + * + * To allow device drivers to establish interrupt handlers before all + * relevant interrupt controllers have been attached, we support + * pre-registration of interrupt handlers. For each node in the + * device tree that has an "interrupt-controller" property, we + * register a dummy interrupt controller that simply stashes away all + * relevant details of the interrupt handler being established. + * Later, when the real interrupt controller registers itself, we + * establish those interrupt handlers based on that information. + */ + +#define MAX_INTERRUPT_CELLS 4 + +struct intr_prereg { + LIST_ENTRY(intr_prereg) ip_list; + uint32_t ip_phandle; + uint32_t ip_cell[MAX_INTERRUPT_CELLS]; + + int ip_level; + struct cpu_info *ip_ci; + int (*ip_func)(void *); + void *ip_arg; + char *ip_name; + + struct interrupt_controller *ip_ic; + void *ip_ih; +}; + +LIST_HEAD(, intr_prereg) prereg_interrupts = + LIST_HEAD_INITIALIZER(prereg_interrupts); + +void * +loongarch_intr_prereg_establish_fdt(void *cookie, int *cell, int level, + struct cpu_info *ci, int (*func)(void *), void *arg, char *name) +{ + struct interrupt_controller *ic = cookie; + struct intr_prereg *ip; + int i; + + ip = malloc(sizeof(struct intr_prereg), M_DEVBUF, M_ZERO | M_WAITOK); + ip->ip_phandle = ic->ic_phandle; + for (i = 0; i < ic->ic_cells; i++) + ip->ip_cell[i] = cell[i]; + ip->ip_level = level; + ip->ip_ci = ci; + ip->ip_func = func; + ip->ip_arg = arg; + ip->ip_name = name; + LIST_INSERT_HEAD(&prereg_interrupts, ip, ip_list); + + return ip; +} + +void +loongarch_intr_prereg_disestablish_fdt(void *cookie) +{ + struct intr_prereg *ip = cookie; + struct interrupt_controller *ic = ip->ip_ic; + + if (ic != NULL && ip->ip_ih != NULL) + ic->ic_disestablish(ip->ip_ih); + + if (ic == NULL) + LIST_REMOVE(ip, ip_list); + + free(ip, M_DEVBUF, sizeof(*ip)); +} + +void +loongarch_intr_prereg_barrier_fdt(void *cookie) +{ + struct intr_prereg *ip = cookie; + struct interrupt_controller *ic = ip->ip_ic; + + if (ip->ip_ic != NULL && ip->ip_ih != NULL) + ic->ic_barrier(ip->ip_ih); +} + +void +loongarch_intr_init_fdt_recurse(int node) +{ + struct interrupt_controller *ic; + + if (OF_getproplen(node, "interrupt-controller") >= 0) { + ic = malloc(sizeof(struct interrupt_controller), + M_DEVBUF, M_ZERO | M_WAITOK); + ic->ic_node = node; + ic->ic_cookie = ic; + ic->ic_establish = loongarch_intr_prereg_establish_fdt; + ic->ic_disestablish = loongarch_intr_prereg_disestablish_fdt; + ic->ic_barrier = loongarch_intr_prereg_barrier_fdt; + loongarch_intr_register_fdt(ic); + } + + for (node = OF_child(node); node; node = OF_peer(node)) + loongarch_intr_init_fdt_recurse(node); +} + +void +loongarch_intr_init_fdt(void) +{ + int node = OF_peer(0); + + if (node) + loongarch_intr_init_fdt_recurse(node); +} + +LIST_HEAD(, interrupt_controller) interrupt_controllers = + LIST_HEAD_INITIALIZER(interrupt_controllers); + +void +loongarch_intr_register_fdt(struct interrupt_controller *ic) +{ + struct intr_prereg *ip, *tip; + + ic->ic_cells = OF_getpropint(ic->ic_node, "#interrupt-cells", 0); + ic->ic_phandle = OF_getpropint(ic->ic_node, "phandle", 0); + KASSERT(ic->ic_cells <= MAX_INTERRUPT_CELLS); + + LIST_INSERT_HEAD(&interrupt_controllers, ic, ic_list); + + /* Establish pre-registered interrupt handlers. */ + LIST_FOREACH_SAFE(ip, &prereg_interrupts, ip_list, tip) { + if (ip->ip_phandle != ic->ic_phandle) + continue; + + ip->ip_ic = ic; + if (ic->ic_establish)/* loongarch_cpu_intc sets this to NULL */ + { + ip->ip_ih = ic->ic_establish(ic->ic_cookie, ip->ip_cell, + ip->ip_level, ip->ip_ci, ip->ip_func, ip->ip_arg, ip->ip_name); + if (ip->ip_ih == NULL) + printf("can't establish interrupt %s\n", ip->ip_name); + } + + LIST_REMOVE(ip, ip_list); + } +} + +void * +loongarch_intr_establish_fdt(int node, int level, int (*func)(void *), + void *cookie, char *name) +{ + return loongarch_intr_establish_fdt_idx(node, 0, level, func, cookie, name); +} + +void * +loongarch_intr_establish_fdt_cpu(int node, int level, struct cpu_info *ci, + int (*func)(void *), void *cookie, char *name) +{ + return loongarch_intr_establish_fdt_idx_cpu(node, 0, level, ci, func, + cookie, name); +} + +void * +loongarch_intr_establish_fdt_idx(int node, int idx, int level, int (*func)(void *), + void *cookie, char *name) +{ + return loongarch_intr_establish_fdt_idx_cpu(node, idx, level, NULL, func, + cookie, name); +} + +void * +loongarch_intr_establish_fdt_idx_cpu(int node, int idx, int level, + struct cpu_info *ci, int (*func)(void *), void *cookie, char *name) +{ + struct interrupt_controller *ic; + int i, len, ncells, parent; + int extended = 1; + uint32_t *cell, *cells, phandle; + struct machine_intr_handle *ih; + void *val = NULL; + + len = OF_getproplen(node, "interrupts-extended"); + if (len <= 0) { + len = OF_getproplen(node, "interrupts"); + extended = 0; + } + if (len <= 0 || (len % sizeof(uint32_t) != 0)) + return NULL; + + /* Old style. */ + if (!extended) { + parent = loongarch_intr_get_parent(node); + LIST_FOREACH(ic, &interrupt_controllers, ic_list) { + if (ic->ic_node == parent) + break; + } + + if (ic == NULL) + return NULL; + } + + cell = cells = malloc(len, M_TEMP, M_WAITOK); + if (extended) + OF_getpropintarray(node, "interrupts-extended", cells, len); + else + OF_getpropintarray(node, "interrupts", cells, len); + ncells = len / sizeof(uint32_t); + + for (i = 0; i <= idx && ncells > 0; i++) { + if (extended) { + phandle = cell[0]; + + /* Handle "empty" phandle reference. */ + if (phandle == 0) { + cell++; + ncells--; + continue; + } + + LIST_FOREACH(ic, &interrupt_controllers, ic_list) { + if (ic->ic_phandle == phandle) + break; + } + + if (ic == NULL) + break; + + cell++; + ncells--; + } + + if (i == idx && ncells >= ic->ic_cells && ic->ic_establish) { + val = ic->ic_establish(ic->ic_cookie, cell, level, + ci, func, cookie, name); + break; + } + + cell += ic->ic_cells; + ncells -= ic->ic_cells; + } + + free(cells, M_TEMP, len); + + if (val == NULL) + return NULL; + + ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK); + ih->ih_ic = ic; + ih->ih_ih = val; + + return ih; +} + +void * +loongarch_intr_establish_fdt_imap_cpu(int node, int *reg, int nreg, int level, + struct cpu_info *ci, int (*func)(void *), void *cookie, char *name) +{ + struct interrupt_controller *ic; + struct machine_intr_handle *ih; + uint32_t *cell; + uint32_t map_mask[4], *map; + int len, acells, ncells; + void *val = NULL; + + if (nreg != sizeof(map_mask)) + return NULL; + + if (OF_getpropintarray(node, "interrupt-map-mask", map_mask, + sizeof(map_mask)) != sizeof(map_mask)) + return NULL; + + len = OF_getproplen(node, "interrupt-map"); + if (len <= 0) + return NULL; + + map = malloc(len, M_DEVBUF, M_WAITOK); + OF_getpropintarray(node, "interrupt-map", map, len); + + cell = map; + ncells = len / sizeof(uint32_t); + while (ncells > 5) { + LIST_FOREACH(ic, &interrupt_controllers, ic_list) { + if (ic->ic_phandle == cell[4]) + break; + } + + if (ic == NULL) + break; + + acells = OF_getpropint(ic->ic_node, "#address-cells", 0); + if (ncells >= (5 + acells + ic->ic_cells) && + (reg[0] & map_mask[0]) == cell[0] && + (reg[1] & map_mask[1]) == cell[1] && + (reg[2] & map_mask[2]) == cell[2] && + (reg[3] & map_mask[3]) == cell[3] && + ic->ic_establish) { + val = ic->ic_establish(ic->ic_cookie, &cell[5 + acells], + level, ci, func, cookie, name); + break; + } + + cell += (5 + acells + ic->ic_cells); + ncells -= (5 + acells + ic->ic_cells); + } + + if (val == NULL) { + free(map, M_DEVBUF, len); + return NULL; + } + + ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK); + ih->ih_ic = ic; + ih->ih_ih = val; + + free(map, M_DEVBUF, len); + return ih; +} + +void * +loongarch_intr_establish_fdt_msi_cpu(int node, uint64_t *addr, uint64_t *data, + int level, struct cpu_info *ci, int (*func)(void *), void *cookie, + char *name) +{ + struct interrupt_controller *ic; + struct machine_intr_handle *ih; + uint32_t phandle; + void *val = NULL; + + phandle = loongarch_intr_map_msi(node, data); + LIST_FOREACH(ic, &interrupt_controllers, ic_list) { + if (ic->ic_phandle == phandle) + break; + } + + if (ic == NULL || ic->ic_establish_msi == NULL) + return NULL; + + val = ic->ic_establish_msi(ic->ic_cookie, addr, data, + level, ci, func, cookie, name); + if (val == NULL) + return NULL; + + ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK); + ih->ih_ic = ic; + ih->ih_ih = val; + + return ih; +} + +void +loongarch_intr_disestablish_fdt(void *cookie) +{ + struct machine_intr_handle *ih = cookie; + struct interrupt_controller *ic = ih->ih_ic; + + ic->ic_disestablish(ih->ih_ih); + free(ih, M_DEVBUF, sizeof(*ih)); +} + +void +loongarch_intr_enable(void *cookie) +{ + struct machine_intr_handle *ih = cookie; + struct interrupt_controller *ic = ih->ih_ic; + + KASSERT(ic->ic_enable != NULL); + ic->ic_enable(ih->ih_ih); +} + +void +loongarch_intr_disable(void *cookie) +{ + struct machine_intr_handle *ih = cookie; + struct interrupt_controller *ic = ih->ih_ic; + + KASSERT(ic->ic_disable != NULL); + ic->ic_disable(ih->ih_ih); +} + +void +loongarch_intr_route(void *cookie, int enable, struct cpu_info *ci) +{ + struct machine_intr_handle *ih = cookie; + struct interrupt_controller *ic = ih->ih_ic; + + if (ic->ic_route) + ic->ic_route(ih->ih_ih, enable, ci); +} + +void +loongarch_intr_cpu_enable(void) +{ + struct interrupt_controller *ic; + + LIST_FOREACH(ic, &interrupt_controllers, ic_list) + if (ic->ic_cpu_enable) + ic->ic_cpu_enable(); +} + +int +loongarch_dflt_splraise(int newcpl) +{ + struct cpu_info *ci = curcpu(); + int oldcpl; + + oldcpl = ci->ci_cpl; + + if (newcpl < oldcpl) + newcpl = oldcpl; + + ci->ci_cpl = newcpl; + + return oldcpl; +} + +int +loongarch_dflt_spllower(int newcpl) +{ + struct cpu_info *ci = curcpu(); + int oldcpl; + + oldcpl = ci->ci_cpl; + + splx(newcpl); + + return oldcpl; +} + +void +loongarch_dflt_splx(int newcpl) +{ + struct cpu_info *ci = curcpu(); + + if (ci->ci_ipending & loongarch_smask[newcpl]) + loongarch_do_pending_intr(newcpl); + ci->ci_cpl = newcpl; +} + +void +loongarch_dflt_setipl(int newcpl) +{ + struct cpu_info *ci = curcpu(); + + ci->ci_cpl = newcpl; +} + +void +loongarch_do_pending_intr(int pcpl) +{ + struct cpu_info *ci = curcpu(); + u_long sie; + + sie = intr_disable(); + +#define DO_SOFTINT(si, ipl) \ + if ((ci->ci_ipending & loongarch_smask[pcpl]) & \ + SI_TO_IRQBIT(si)) { \ + ci->ci_ipending &= ~SI_TO_IRQBIT(si); \ + loongarch_intr_func.setipl(ipl); \ + intr_restore(sie); \ + softintr_dispatch(si); \ + sie = intr_disable(); \ + } + + do { + DO_SOFTINT(SOFTINTR_TTY, IPL_SOFTTTY); + DO_SOFTINT(SOFTINTR_NET, IPL_SOFTNET); + DO_SOFTINT(SOFTINTR_CLOCK, IPL_SOFTCLOCK); + } while (ci->ci_ipending & loongarch_smask[pcpl]); + + /* Don't use splx... we are here already! */ + loongarch_intr_func.setipl(pcpl); + intr_restore(sie); +} + +void +loongarch_set_intr_func(int (*raise)(int), int (*lower)(int), void (*x)(int), + void (*setipl)(int)) +{ + loongarch_intr_func.raise = raise; + loongarch_intr_func.lower = lower; + loongarch_intr_func.x = x; + loongarch_intr_func.setipl = setipl; +} + +void +loongarch_set_intr_handler(void (*intr_handle)(void *)) +{ + loongarch_intr_dispatch = intr_handle; +} + +void +loongarch_init_smask(void) +{ + static int inited = 0; + int i; + + if (inited) + return; + inited = 1; + + for (i = IPL_NONE; i <= IPL_HIGH; i++) { + loongarch_smask[i] = 0; + if (i < IPL_SOFTCLOCK) + loongarch_smask[i] |= SI_TO_IRQBIT(SOFTINTR_CLOCK); + if (i < IPL_SOFTNET) + loongarch_smask[i] |= SI_TO_IRQBIT(SOFTINTR_NET); + if (i < IPL_SOFTTTY) + loongarch_smask[i] |= SI_TO_IRQBIT(SOFTINTR_TTY); + } +} + +/* provide functions for asm */ +#undef splraise +#undef spllower +#undef splx + +int +splraise(int ipl) +{ + return loongarch_intr_func.raise(ipl); +} + +int _spllower(int ipl); /* XXX - called from asm? */ +int +_spllower(int ipl) +{ + return loongarch_intr_func.lower(ipl); +} +int +spllower(int ipl) +{ + return loongarch_intr_func.lower(ipl); +} + +void +splx(int ipl) +{ + loongarch_intr_func.x(ipl); +} + +void +softintr(int si) +{ + curcpu()->ci_ipending |= SI_TO_IRQBIT(si); +} + +#ifdef DIAGNOSTIC +void +loongarch_splassert_check(int wantipl, const char *func) +{ + int oldipl = curcpu()->ci_cpl; + + if (oldipl < wantipl) { + splassert_fail(wantipl, oldipl, func); + /* + * If the splassert_ctl is set to not panic, raise the ipl + * in a feeble attempt to reduce damage. + */ + loongarch_intr_func.setipl(wantipl); + } + + if (wantipl == IPL_NONE && curcpu()->ci_idepth != 0) { + splassert_fail(-1, curcpu()->ci_idepth, func); + } +} +#endif + +void +intr_barrier(void *cookie) +{ + struct machine_intr_handle *ih = cookie; + struct interrupt_controller *ic = ih->ih_ic; + + ic->ic_barrier(ih->ih_ih); +} + +/* + * IPI implementation + */ + +#ifdef MULTIPROCESSOR + +void +intr_send_ipi(struct cpu_info *ci, int reason) +{ + unsigned long hart_mask; + + if (ci == curcpu() && reason == IPI_NOP) + return; + + if (reason != IPI_NOP) + atomic_setbits_int(&ci->ci_ipi_reason, reason); + + hart_mask = (1UL << ci->ci_hartid); + sbi_send_ipi(&hart_mask); +} + +int +ipi_intr(void *frame) +{ + struct cpu_info *ci = curcpu(); + int pending; + + csr_clear(sip, SIP_SSIP); + pending = atomic_swap_uint(&ci->ci_ipi_reason, IPI_NOP); + + if (pending & IPI_DDB) + db_enter(); + + return 1; +} + +#endif diff --git sys/arch/loongarch64/loongarch64/locore.S sys/arch/loongarch64/loongarch64/locore.S new file mode 100644 index 00000000000..4b955b6ad7e --- /dev/null +++ sys/arch/loongarch64/loongarch64/locore.S @@ -0,0 +1,270 @@ +/* $OpenBSD: locore.S,v 1.22 2026/05/26 14:12:34 kettenis Exp $ */ + +/*- + * Copyright (c) 2015-2018 Ruslan Bukin + * All rights reserved. + * + * Portions of this software were developed by SRI International and the + * University of Cambridge Computer Laboratory under DARPA/AFRL contract + * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. + * + * Portions of this software were developed by the University of Cambridge + * Computer Laboratory as part of the CTSRD Project, with support from the + * UK Higher Education Innovation Fund (HEIF). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "assym.h" + +#include +#include +#include +#include +#include +#include + + .globl kernbase + .set kernbase, KERNBASE + + .text +/* + * Main entry point. Arguments are as follows: + * - a0 = esym + * - a2 = dtbp + * + * It is expected that only a single CPU will enter here. + */ + .globl _start_kern_bootstrap +_start_kern_bootstrap: + + /* + * Page tables setup + */ + + /* Get the kernel's load address */ + bl get_physmem + or $s3, $a0, $zero + + /* Add L1 entry for kernel */ + la.local $s1, pagetable_l1 + la.local $s2, pagetable_l2 /* Link to next level PN */ + srli.d $s2, $s2, PAGE_SHIFT + + li.d $a5, KERNBASE + srli.d $a5, $a5, L1_SHIFT /* >> L1_SHIFT */ + andi $a5, $a5, 0x1ff /* & 0x1ff */ + li.d $t4, PTE_V + slli.d $t5, $s2, PTE_PPN0_S /* (s2 << PTE_PPN0_S) */ + or $t6, $t4, $t5 + + /* Store L1 PTE entry to position */ + li.d $a6, PTE_SIZE + mul.w $a5, $a5, $a6 + add.d $t0, $s1, $a5 + st.d $t6, $t0, 0 + + /* Level 2 superpages (512 x 2MiB) */ + la.local $s1, pagetable_l2 + srli.d $t4, $s9, L2_SHIFT /* Div physmem base by 2 MiB */ + li.d $t2, 512 /* Build 512 entries */ + add.d $t3, $t4, $t2 + li.d $t0, (PTE_KERN | PTE_X) +1: + slli.d $t2, $t4, PTE_PPN1_S /* << PTE_PPN1_S */ + or $t5, $t0, $t2 + st.d $t5, $s1, 0 /* Store PTE entry to position */ + addi.d $s1, $s1, PTE_SIZE + + addi.d $t4, $t4, 1 + bltu $t4, $t3, 1b + + /* Page tables END */ + + /* Setup supervisor trap vector */ + la.local $t0, va + sub.d $t0, $t0, $s3 + li.d $t1, KERNBASE + add.d $t0, $t0, $t1 + csrwr $t0, 0xC + + /* Set page tables base register */ + la.local $s2, pagetable_l1 + srli.d $s2, $s2, PAGE_SHIFT + or $s2, $s2, $t0 + invtlb 0, $zero, $zero + or $t0, $s2, $zero + csrwr $t0, 0x19 + + .align 2 +va: + invtlb 0, $zero, $zero + + + /* Setup supervisor trap vector */ + la $t0, cpu_exception_handler + csrwr $t0, 0xC + + /* Ensure sscratch is zero */ + li.d $t0, 0 + csrwr $t0, 0x30 + + /* Initialize stack pointer */ + la $sp, initstack_end + + /* Clear frame pointer */ + move $s0, $zero + + /* Allocate space for LOONGARCH_bootparams */ + addi.d $sp, $sp, -LOONGARCH_BOOTPARAMS_SIZEOF + bstrins.d $sp, $zero, 3, 0 + + /* Clear BSS */ + la $t0, __bss_start + la $t1, _end +1: + st.d $zero, $t0, 0 + addi.d $t0, $t0, 8 + bltu $t0, $t1, 1b + + /* Fill LOONGARCH_bootparams */ + la $t0, pagetable_l1 + st.d $t0, $sp, LOONGARCH_BOOTPARAMS_KERN_L1PT + st.d $s3, $sp, LOONGARCH_BOOTPARAMS_KERN_PHYS + la $t0, initstack + st.d $t0, $sp, LOONGARCH_BOOTPARAMS_KERN_STACK + st.d $a1, $sp, LOONGARCH_BOOTPARAMS_DTBP_PHYS + + /* Set esym to virtual address of symbol table end */ + la.local $t0, esym + sub.d $t1, $a0, $s3 + li.d $t2, KERNBASE + add.d $t1, $t1, $t2 + st.d $t1, $t0, 0 + + move $a0, $sp + call initloongarch /* Off we go */ + call main + +/* + * Get the physical address the kernel is loaded to. Returned in s9. + */ +get_physmem: + la.local $t0, virt_map /* physical address of virt_map */ + ld.d $t1, $t0, 0 /* virtual address of virt_map */ + sub.d $t1, $t1, $t0 /* calculate phys->virt delta */ + li.d $t2, KERNBASE + sub.d $s3, $t2, $t1 /* s9 = physmem base */ + ret + + .data + .align 4 +initstack: + .space USPACE +initstack_end: + + .rodata +ENTRY(sigcode) + move $a0, $sp + addi.d $a0, $a0, SF_SC + li.d $t0, SYS_sigreturn + .globl sigcodecall +sigcodecall: + syscall 0 + .globl sigcoderet +sigcoderet: + break 0 +END(sigcode) + .globl esigcode +esigcode: + + .globl sigfill +sigfill: + break 0 +esigfill: + .globl sigfillsiz +sigfillsiz: + .word esigfill - sigfill + + .data + .global esym +esym: + .quad end + + .align 12 +pagetable_l1: + .space PAGE_SIZE +pagetable_l2: + .space PAGE_SIZE + + .align 3 +virt_map: + .quad virt_map + +#ifdef MULTIPROCESSOR + + .text + .globl cpu_hatch +cpu_hatch: + ld.d $tp, $a1, CI_SELF + ld.d $a2, $a1, CI_SATP + + /* Setup stack pointer */ + ld.d $sp, $a1, CI_INITSTACK_END + + /* Get the kernel's load address */ + bl get_physmem + + /* Setup supervisor trap vector */ + la.local $t0, mpva + sub.d $t0, $t0, $s3 + li.d $t1, KERNBASE + add.d $t0, $t0, $t1 + csrwr stvec, $t0 + + /* Set page tables base register */ + la.d $s2, pagetable_l1 + srli.d $s2, $s2, PAGE_SHIFT + or $s2, $s2, $t0 + invtlb 0, $zero, $zero + or $t0, $s2, $zero + csrwr $t0, 0x19 + + .align 2 +mpva: + invtlb 0, $zero, $zero + + /* Setup supervisor trap vector */ + la $t0, cpu_exception_handler + csrwr stvec, $t0 + + /* Ensure sscratch is zero */ + li.d $t0, 0 + csrwr $t0, 0x30 + + /* Switch to real kernel page tables */ + or $t0, $s2, $zero + csrwr $t0, 0x19 + invtlb 0, $zero, $zero + call cpu_start_secondary + +#endif diff --git sys/arch/loongarch64/loongarch64/locore0.S sys/arch/loongarch64/loongarch64/locore0.S new file mode 100644 index 00000000000..834622197ce --- /dev/null +++ sys/arch/loongarch64/loongarch64/locore0.S @@ -0,0 +1,47 @@ +/* $OpenBSD: locore0.S,v 1.3 2021/07/02 10:42:22 kettenis Exp $ */ + +/*- + * Copyright (c) 2012-2014 Andrew Turner + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: head/sys/arm64/arm64/locore.S 282867 2015-05-13 18:57:03Z zbb $ + */ + +#include +#include + + .text +/* + * Main entry point. EFIBOOT passes the following arguments: + * - a0 = esym + * - a1 = 0 + * - a2 = dtbp + */ + .globl _start +_start: + move $a1, $a2 + + /* jump to locore.S _start_kern_bootstrap*/ + la.local $t0, _start_kern_bootstrap + jirl $ra, $t0, 0 diff --git sys/arch/loongarch64/loongarch64/machdep.c sys/arch/loongarch64/loongarch64/machdep.c new file mode 100644 index 00000000000..f21f83471b1 --- /dev/null +++ sys/arch/loongarch64/loongarch64/machdep.c @@ -0,0 +1,1076 @@ +/* $OpenBSD: machdep.c,v 1.45 2026/07/07 12:12:44 kettenis Exp $ */ + +/* + * Copyright (c) 2014 Patrick Wildt + * Copyright (c) 2021 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "softraid.h" +#if NSOFTRAID > 0 +#include +#endif + +extern vaddr_t virtual_avail; +extern uint64_t esym; + +extern char _start[]; + +char *boot_args = NULL; +uint8_t *bootmac = NULL; + +int stdout_node; +int stdout_speed; + +void (*cpuresetfn)(void); +void (*powerdownfn)(void); + +int cold = 1; + +struct vm_map *exec_map = NULL; +struct vm_map *phys_map = NULL; + +int physmem; + +caddr_t msgbufaddr; +paddr_t msgbufphys; + +struct user *proc0paddr; + +struct uvm_constraint_range dma_constraint = { 0x0, (paddr_t)-1 }; +struct uvm_constraint_range *uvm_md_constraints[] = { + &dma_constraint, + NULL, +}; + +void blink_led_timeout(void *); +int led_blink = 1; + +/* the following is used externally (sysctl_hw) */ +char machine[] = MACHINE; /* from */ + +int safepri = 0; + +uint32_t boot_hart; /* The hart we booted on. */ +struct cpu_info cpu_info_primary; +struct cpu_info *cpu_info[MAXCPUS] = { &cpu_info_primary }; + +uint64_t tb_freq = 1000000; + +struct fdt_reg memreg[VM_PHYSSEG_MAX]; +int nmemreg; + +void memreg_add(const struct fdt_reg *); +void memreg_remove(const struct fdt_reg *); + +static int +atoi(const char *s) +{ + int n, neg; + + n = 0; + neg = 0; + + while (*s == '-') { + s++; + neg = !neg; + } + + while (*s != '\0') { + if (*s < '0' || *s > '9') + break; + + n = (10 * n) + (*s - '0'); + s++; + } + + return (neg ? -n : n); +} + +void * +fdt_find_cons(const char *name) +{ + char *alias = "serial0"; + char buf[128]; + char *stdout = NULL; + char *p; + void *node; + + /* First check if "stdout-path" is set. */ + node = fdt_find_node("/chosen"); + if (node) { + if (fdt_node_property(node, "stdout-path", &stdout) > 0) { + if (strchr(stdout, ':') != NULL) { + strlcpy(buf, stdout, sizeof(buf)); + if ((p = strchr(buf, ':')) != NULL) { + *p++ = '\0'; + stdout_speed = atoi(p); + } + stdout = buf; + } + if (stdout[0] != '/') { + /* It's an alias. */ + alias = stdout; + stdout = NULL; + } + } + } + + /* Perform alias lookup if necessary. */ + if (stdout == NULL) { + node = fdt_find_node("/aliases"); + if (node) + fdt_node_property(node, alias, &stdout); + } + + /* Lookup the physical address of the interface. */ + if (stdout) { + node = fdt_find_node(stdout); + if (node && fdt_is_compatible(node, name)) { + stdout_node = OF_finddevice(stdout); + return (node); + } + } + + return (NULL); +} + +void com_fdt_init_cons(void); + +void +consinit(void) +{ + static int consinit_called = 0; + + if (consinit_called != 0) + return; + + consinit_called = 1; + + com_fdt_init_cons(); +} + +void +cpu_idle_cycle(void) +{ + // Enable interrupts + intr_enable(); + // XXX Data Sync Barrier? (Maybe SFENCE???) + __asm volatile("idle 0"); +} + +/* Dummy trapframe for proc0. */ +struct trapframe proc0tf; + +void +cpu_startup(void) +{ + u_int loop; + paddr_t minaddr; + paddr_t maxaddr; + + proc0.p_addr = proc0paddr; + + /* + * Give pmap a chance to set up a few more things now the vm + * is initialised + */ + pmap_postinit(); + + /* + * Initialize error message buffer (at end of core). + */ + + /* msgbufphys was setup during the secondary boot strap */ + for (loop = 0; loop < atop(MSGBUFSIZE); ++loop) + pmap_kenter_pa((vaddr_t)msgbufaddr + loop * PAGE_SIZE, + msgbufphys + loop * PAGE_SIZE, PROT_READ | PROT_WRITE); + pmap_update(pmap_kernel()); + initmsgbuf(msgbufaddr, round_page(MSGBUFSIZE)); + + /* + * Identify ourselves for the msgbuf (everything printed earlier will + * not be buffered). + */ + printf("%s", version); + + printf("real mem = %lu (%luMB)\n", ptoa(physmem), + ptoa(physmem) / 1024 / 1024); + + /* + * Allocate a submap for exec arguments. This map effectively + * limits the number of processes exec'ing at any time. + */ + minaddr = vm_map_min(kernel_map); + exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, + 16 * NCARGS, VM_MAP_PAGEABLE, FALSE, NULL); + + /* + * Allocate a submap for physio + */ + phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, + VM_PHYS_SIZE, 0, FALSE, NULL); + + /* + * Set up buffers, so they can be used to read disk labels. + */ + bufinit(); + + printf("avail mem = %lu (%luMB)\n", ptoa(uvmexp.free), + ptoa(uvmexp.free) / 1024 / 1024); + + sbi_print_version(); + + curpcb = &proc0.p_addr->u_pcb; + curpcb->pcb_flags = 0; + curpcb->pcb_tf = &proc0tf; + + if (boothowto & RB_CONFIG) { +#ifdef BOOT_CONFIG + user_config(); +#else + printf("kernel does not support -c; continuing..\n"); +#endif + } +} + +/* + * Move parts of cpu_switchto into C, too difficult in asm + */ + +void cpu_switchto_asm(struct proc *, struct proc *); + +void +cpu_switchto(struct proc *old, struct proc *new) +{ + if (old) { + struct pcb *pcb = &old->p_addr->u_pcb; + struct trapframe *tf = pcb->pcb_tf; + + if (pcb->pcb_flags & PCB_FPU) + fpu_save(old, tf); + if (pcb->pcb_flags & PCB_VECTOR) + vector_save(old, tf); + + /* Drop FPU and vector state */ + } + + cpu_switchto_asm(old, new); +} + +/* + * machine dependent system variables. + */ + +int +cpu_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, + size_t newlen, struct proc *p) +{ + char *compatible; + int node, len, error; + int oldval; + + /* all sysctl names at this level are terminal */ + if (namelen != 1) + return (ENOTDIR); /* overloaded */ + + switch (name[0]) { + case CPU_COMPATIBLE: + node = OF_finddevice("/"); + len = OF_getproplen(node, "compatible"); + if (len <= 0) + return (EOPNOTSUPP); + compatible = malloc(len, M_TEMP, M_WAITOK | M_ZERO); + OF_getprop(node, "compatible", compatible, len); + compatible[len - 1] = 0; + error = sysctl_rdstring(oldp, oldlenp, newp, compatible); + free(compatible, M_TEMP, len); + return error; + case CPU_LED_BLINK: + oldval = led_blink; + error = sysctl_int(oldp, oldlenp, newp, newlen, &led_blink); + /* + * If we were false and are now true, start the timer. + */ + if (!oldval && led_blink > oldval) + blink_led_timeout(NULL); + return error; + default: + return (EOPNOTSUPP); + } + /* NOTREACHED */ +} + +int waittime = -1; + +__dead void +boot(int howto) +{ + if ((howto & RB_RESET) != 0) + goto doreset; + + if (cold) { + if ((howto & RB_USERREQ) == 0) + howto |= RB_HALT; + goto haltsys; + } + + boothowto = howto; + if ((howto & RB_NOSYNC) == 0 && waittime < 0) { + waittime = 0; + vfs_shutdown(curproc); + + if ((howto & RB_TIMEBAD) == 0) { + resettodr(); + } else { + printf("WARNING: not updating battery clock\n"); + } + } + if_downall(); + + uvm_shutdown(); + splhigh(); + cold = 1; + + if ((howto & RB_DUMP) != 0) + printf("no dump so far\n"); + +haltsys: + config_suspend_all(DVACT_POWERDOWN); + + if ((howto & RB_HALT) != 0) { + if ((howto & RB_POWERDOWN) != 0) { + printf("\nAttempting to power down...\n"); + delay(500000); + if (powerdownfn) + (*powerdownfn)(); + } + + printf("\n"); + printf("The operating system has halted.\n"); + printf("Please press any key to reboot.\n\n"); + cngetc(); + } + +doreset: + printf("rebooting...\n"); + delay(500000); + if (cpuresetfn) + (*cpuresetfn)(); + printf("reboot failed; spinning\n"); + for (;;) + continue; + /* NOTREACHED */ +} + +void +setregs(struct proc *p, struct exec_package *pack, u_long stack, + struct ps_strings *arginfo) +{ + struct trapframe *tf = p->p_addr->u_pcb.pcb_tf; + struct pcb *pcb = &p->p_addr->u_pcb; + + /* If we were using the FPU or vector, forget about it. */ + if (pcb->pcb_flags & PCB_VECTOR) { + free(pcb->pcb_vstate, M_SUBPROC, + sizeof(struct vreg) + 32 * loongarch_vlenb); + pcb->pcb_vstate = NULL; + } + pcb->pcb_flags &= ~(PCB_FPU | PCB_VECTOR); + + memset(tf, 0, sizeof *tf); + tf->tf_sp = STACKALIGN(stack); + tf->tf_ra = pack->ep_entry; + tf->tf_sepc = pack->ep_entry; +} + +void +need_resched(struct cpu_info *ci) +{ + ci->ci_want_resched = 1; + + /* There's a risk we'll be called before the idle threads start */ + if (ci->ci_curproc) { + aston(ci->ci_curproc); + cpu_kick(ci); + } +} + + +/* + * Size of memory segments, before any memory is stolen. + */ +phys_ram_seg_t mem_clusters[VM_PHYSSEG_MAX]; +int mem_cluster_cnt; + +/* + * cpu_dumpsize: calculate size of machine-dependent kernel core dump headers. + */ +int +cpu_dumpsize(void) +{ + int size; + + size = ALIGN(sizeof(kcore_seg_t)) + + ALIGN(mem_cluster_cnt * sizeof(phys_ram_seg_t)); + if (roundup(size, dbtob(1)) != dbtob(1)) + return (-1); + + return (1); +} + +u_long +cpu_dump_mempagecnt(void) +{ + return 0; +} + +/* + * These variables are needed by /sbin/savecore + */ +u_long dumpmag = 0x8fca0101; /* magic number */ +int dumpsize = 0; /* pages */ +long dumplo = 0; /* blocks */ + +/* + * This is called by main to set dumplo and dumpsize. + * Dumps always skip the first PAGE_SIZE of disk space + * in case there might be a disk label stored there. + * If there is extra space, put dump at the end to + * reduce the chance that swapping trashes it. + */ +void +dumpconf(void) +{ + int nblks, dumpblks; /* size of dump area */ + + if (dumpdev == NODEV || + (nblks = (bdevsw[major(dumpdev)].d_psize)(dumpdev)) == 0) + return; + if (nblks <= ctod(1)) + return; + + dumpblks = cpu_dumpsize(); + if (dumpblks < 0) + return; + dumpblks += ctod(cpu_dump_mempagecnt()); + + /* If dump won't fit (incl. room for possible label), punt. */ + if (dumpblks > (nblks - ctod(1))) + return; + + /* Put dump at end of partition */ + dumplo = nblks - dumpblks; + + /* dumpsize is in page units, and doesn't include headers. */ + dumpsize = cpu_dump_mempagecnt(); +} + +int +sys_sysarch(struct proc *p, void *v, register_t *retval) +{ + struct sys_sysarch_args /* { + syscallarg(int) op; + syscallarg(void *) parms; + } */ *uap = v; + struct loongarch_sync_icache_args args; + int error = 0; + int op = SCARG(uap, op); + + if ((p->p_p->ps_flags & PS_PLEDGE) && op != LOONGARCH_SYNC_ICACHE) + return pledge_fail(p, EINVAL, 0); + + switch (op) { + case LOONGARCH_SYNC_ICACHE: + if (SCARG(uap, parms) != NULL) + error = copyin(SCARG(uap, parms), &args, sizeof(args)); + if (error) + break; + /* + * XXX Validate args.addr and args.len before using them. + */ + pmap_proc_iflush(p->p_p, (vaddr_t)args.addr, args.len); + break; + default: + error = EINVAL; + break; + } + + return (error); +} + +uint64_t mmap_start; +uint32_t mmap_size; +uint32_t mmap_desc_size; +uint32_t mmap_desc_ver; + +EFI_MEMORY_DESCRIPTOR *mmap; + +void collect_kernel_args(const char *); +void process_kernel_args(void); + +int pmap_bootstrap_bs_map(bus_space_tag_t, bus_addr_t, + bus_size_t, int, bus_space_handle_t *); + +void +initloongarch(struct loongarch_bootparams *rbp) +{ + paddr_t memstart, memend; + paddr_t startpa, endpa, pa; + vaddr_t vstart, va; + struct fdt_head *fh; + void *config = (void *)rbp->dtbp_phys; + void *fdt = NULL; + struct fdt_reg reg; + void *node; + EFI_PHYSICAL_ADDRESS system_table = 0; + int (*map_func_save)(bus_space_tag_t, bus_addr_t, bus_size_t, int, + bus_space_handle_t *); + int i; + + /* Set the per-CPU pointer. */ + __asm volatile("move $tp, %0" :: "r"(&cpu_info_primary)); + + sbi_init(); + + /* The bootloader has loaded us into a 64MB block. */ + memstart = rbp->kern_phys; + memend = memstart + 64 * 1024 * 1024; + + /* Bootstrap enough of pmap to enter the kernel proper. */ + vstart = pmap_bootstrap(rbp->kern_phys - KERNBASE, rbp->kern_l1pt, + KERNBASE, esym, memstart, memend); + + /* Map the FDT header to determine its size. */ + va = vstart; + startpa = trunc_page((paddr_t)config); + endpa = round_page((paddr_t)config + sizeof(struct fdt_head)); + for (pa = startpa; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE) + pmap_kenter_cache(va, pa, PROT_READ | PROT_WRITE, PMAP_CACHE_WB); + fh = (void *)(vstart + ((paddr_t)config - startpa)); + if (betoh32(fh->fh_magic) != FDT_MAGIC || betoh32(fh->fh_size) == 0) + panic("%s: no FDT", __func__); + + /* Map the remainder of the FDT. */ + endpa = round_page((paddr_t)config + betoh32(fh->fh_size)); + for (; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE) + pmap_kenter_cache(va, pa, PROT_READ | PROT_WRITE, PMAP_CACHE_WB); + config = (void *)(vstart + ((paddr_t)config - startpa)); + vstart = va; + + if (!fdt_init(config)) + panic("%s: corrupt FDT", __func__); + + node = fdt_find_node("/cpus"); + if (node != NULL) { + char *prop; + int len; + + len = fdt_node_property(node, "timebase-frequency", &prop); + if (len == sizeof(uint32_t)) + tb_freq = bemtoh32((uint32_t *)prop); + } + + node = fdt_find_node("/chosen"); + if (node != NULL) { + char *prop; + int len; + static uint8_t lladdr[6]; + + len = fdt_node_property(node, "boot-hartid", &prop); + if (len == sizeof(boot_hart)) + boot_hart = bemtoh32((uint32_t *)prop); + + len = fdt_node_property(node, "bootargs", &prop); + if (len > 0) + collect_kernel_args(prop); + + len = fdt_node_property(node, "openbsd,boothowto", &prop); + if (len == sizeof(boothowto)) + boothowto = bemtoh32((uint32_t *)prop); + + len = fdt_node_property(node, "openbsd,bootduid", &prop); + if (len == sizeof(bootduid)) + memcpy(bootduid, prop, sizeof(bootduid)); + + len = fdt_node_property(node, "openbsd,bootmac", &prop); + if (len == sizeof(lladdr)) { + memcpy(lladdr, prop, sizeof(lladdr)); + bootmac = lladdr; + } + + len = fdt_node_property(node, "openbsd,sr-bootuuid", &prop); +#if NSOFTRAID > 0 + if (len == sizeof(sr_bootuuid)) + memcpy(&sr_bootuuid, prop, sizeof(sr_bootuuid)); +#endif + if (len > 0) + explicit_bzero(prop, len); + + len = fdt_node_property(node, "openbsd,sr-bootkey", &prop); +#if NSOFTRAID > 0 + if (len == sizeof(sr_bootkey)) + memcpy(&sr_bootkey, prop, sizeof(sr_bootkey)); +#endif + if (len > 0) + explicit_bzero(prop, len); + + len = fdt_node_property(node, "openbsd,uefi-mmap-start", &prop); + if (len == sizeof(mmap_start)) + mmap_start = bemtoh64((uint64_t *)prop); + len = fdt_node_property(node, "openbsd,uefi-mmap-size", &prop); + if (len == sizeof(mmap_size)) + mmap_size = bemtoh32((uint32_t *)prop); + len = fdt_node_property(node, "openbsd,uefi-mmap-desc-size", &prop); + if (len == sizeof(mmap_desc_size)) + mmap_desc_size = bemtoh32((uint32_t *)prop); + len = fdt_node_property(node, "openbsd,uefi-mmap-desc-ver", &prop); + if (len == sizeof(mmap_desc_ver)) + mmap_desc_ver = bemtoh32((uint32_t *)prop); + + len = fdt_node_property(node, "openbsd,uefi-system-table", &prop); + if (len == sizeof(system_table)) + system_table = bemtoh64((uint64_t *)prop); + + len = fdt_node_property(node, "openbsd,dma-constraint", &prop); + if (len == sizeof(dma_constraint)) { + dma_constraint.ucr_low = bemtoh64((uint64_t *)prop); + dma_constraint.ucr_high = bemtoh64((uint64_t *)prop + 1); + } + } + + process_kernel_args(); + + proc0paddr = (struct user *)rbp->kern_stack; + + msgbufaddr = (caddr_t)vstart; + msgbufphys = pmap_steal_avail(round_page(MSGBUFSIZE), PAGE_SIZE, NULL); + vstart += round_page(MSGBUFSIZE); + + zero_page = vstart; + vstart += MAXCPUS * PAGE_SIZE; + copy_src_page = vstart; + vstart += MAXCPUS * PAGE_SIZE; + copy_dst_page = vstart; + vstart += MAXCPUS * PAGE_SIZE; + + /* Relocate the FDT to safe memory. */ + if (fdt_get_size(config) != 0) { + uint32_t csize, size = round_page(fdt_get_size(config)); + paddr_t pa; + vaddr_t va; + + pa = pmap_steal_avail(size, PAGE_SIZE, NULL); + memcpy((void *)PHYS_TO_DMAP(pa), config, size); + for (va = vstart, csize = size; csize > 0; + csize -= PAGE_SIZE, va += PAGE_SIZE, pa += PAGE_SIZE) + pmap_kenter_cache(va, pa, PROT_READ, PMAP_CACHE_WB); + + fdt = (void *)vstart; + vstart += size; + } + + /* Relocate the EFI memory map too. */ + if (mmap_start != 0) { + uint32_t csize, size = round_page(mmap_size); + paddr_t pa, startpa, endpa; + vaddr_t va; + + startpa = trunc_page(mmap_start); + endpa = round_page(mmap_start + mmap_size); + for (pa = startpa, va = vstart; pa < endpa; + pa += PAGE_SIZE, va += PAGE_SIZE) + pmap_kenter_cache(va, pa, PROT_READ, PMAP_CACHE_WB); + pa = pmap_steal_avail(size, PAGE_SIZE, NULL); + memcpy((void *)PHYS_TO_DMAP(pa), + (caddr_t)vstart + (mmap_start - startpa), mmap_size); + pmap_kremove(vstart, endpa - startpa); + + for (va = vstart, csize = size; csize > 0; + csize -= PAGE_SIZE, va += PAGE_SIZE, pa += PAGE_SIZE) + pmap_kenter_cache(va, pa, PROT_READ | PROT_WRITE, PMAP_CACHE_WB); + + mmap = (void *)vstart; + vstart += size; + } + + /* No more KVA stealing after this point. */ + virtual_avail = vstart; + + /* Now we can reinit the FDT, using the virtual address. */ + if (fdt) + fdt_init(fdt); + + map_func_save = loongarch64_bs_tag._space_map; + loongarch64_bs_tag._space_map = pmap_bootstrap_bs_map; + + consinit(); + + loongarch64_bs_tag._space_map = map_func_save; + + pmap_avail_fixup(); + + uvmexp.pagesize = PAGE_SIZE; + uvm_setpagesize(); + + /* Make what's left of the initial 64MB block available to UVM. */ + pmap_physload_avail(); + + /* Make all other physical memory available to UVM. */ + if (mmap && mmap_desc_ver == EFI_MEMORY_DESCRIPTOR_VERSION) { + EFI_MEMORY_DESCRIPTOR *desc = mmap; + + /* + * Load all memory marked as EfiConventionalMemory, + * EfiBootServicesCode or EfiBootServicesData. + * Don't bother with blocks smaller than 64KB. The + * initial 64MB memory block should be marked as + * EfiLoaderData so it won't be added here. + */ + for (i = 0; i < mmap_size / mmap_desc_size; i++) { + printf("type 0x%x pa 0x%llx va 0x%llx pages 0x%llx attr 0x%llx\n", + desc->Type, desc->PhysicalStart, + desc->VirtualStart, desc->NumberOfPages, + desc->Attribute); + if ((desc->Type == EfiConventionalMemory || + desc->Type == EfiBootServicesCode || + desc->Type == EfiBootServicesData) && + desc->NumberOfPages >= 16) { + reg.addr = desc->PhysicalStart; + reg.size = ptoa(desc->NumberOfPages); + memreg_add(®); + } + desc = NextMemoryDescriptor(desc, mmap_desc_size); + } + } else { + node = fdt_find_node("/memory"); + if (node == NULL) + panic("%s: no memory specified", __func__); + + for (i = 0; nmemreg < nitems(memreg); i++) { + if (fdt_get_reg(node, i, ®)) + break; + if (reg.size == 0) + continue; + memreg_add(®); + } + } + + /* Remove reserved memory. */ + node = fdt_find_node("/reserved-memory"); + if (node) { + for (node = fdt_child_node(node); node; + node = fdt_next_node(node)) { + if (fdt_get_reg(node, 0, ®)) + continue; + if (reg.size == 0) + continue; + memreg_remove(®); + } + } + + /* Remove the initial 64MB block. */ + reg.addr = memstart; + reg.size = memend - memstart; + memreg_remove(®); + + for (i = 0; i < nmemreg; i++) { + paddr_t start = memreg[i].addr; + paddr_t end = start + memreg[i].size; + + uvm_page_physload(atop(start), atop(end), + atop(start), atop(end), 0); + } + + /* + * Determine physical RAM size from the /memory nodes in the + * FDT. There can be multiple nodes and each node can contain + * multiple ranges. If there are no /memory nodes, use + * information from the EFI memory map instead. + */ + node = fdt_find_node("/memory"); + if (node) { + while (node) { + const char *s = fdt_node_name(node); + if (strncmp(s, "memory", 6) == 0 && + (s[6] == '\0' || s[6] == '@')) { + for (i = 0; i < VM_PHYSSEG_MAX; i++) { + if (fdt_get_reg(node, i, ®)) + break; + if (reg.size == 0) + continue; + physmem += atop(reg.size); + } + } + + node = fdt_next_node(node); + } + } else { + for (i = 0; i < nmemreg; i++) + physmem += atop(memreg[i].size); + } + + kmeminit_nkmempages(); + + /* + * Make sure that we have enough KVA to initialize UVM. In + * particular, we need enough KVA to be able to allocate the + * vm_page structures and nkmempages for malloc(9). + */ + pmap_growkernel(VM_MIN_KERNEL_ADDRESS + 1024 * 1024 * 1024 + + physmem * sizeof(struct vm_page) + ptoa(nkmempages)); + +#ifdef DDB + db_machine_init(); + + /* Firmware doesn't load symbols. */ + ddb_init(); + + if (boothowto & RB_KDB) + db_enter(); +#endif + + softintr_init(); + splraise(IPL_IPI); +} + +char bootargs[256]; + +void +collect_kernel_args(const char *args) +{ + /* Make a local copy of the bootargs */ + strlcpy(bootargs, args, sizeof(bootargs)); +} + +void +process_kernel_args(void) +{ + char *cp = bootargs; + + if (*cp == 0) + return; + + /* Skip the kernel image filename */ + while (*cp != ' ' && *cp != 0) + cp++; + + if (*cp != 0) + *cp++ = 0; + + while (*cp == ' ') + cp++; + + boot_args = cp; + + printf("bootargs: %s\n", boot_args); + + /* Setup pointer to boot flags */ + while (*cp != '-') + if (*cp++ == '\0') + return; + + while (*++cp != 0) { + switch (*cp) { + case 'a': + boothowto |= RB_ASKNAME; + break; + case 'c': + boothowto |= RB_CONFIG; + break; + case 'd': + boothowto |= RB_KDB; + break; + case 's': + boothowto |= RB_SINGLE; + break; + default: + printf("unknown option `%c'\n", *cp); + break; + } + } +} + +/* + * Allow bootstrap to steal KVA after machdep has given it back to pmap. + */ +int +pmap_bootstrap_bs_map(bus_space_tag_t t, bus_addr_t bpa, bus_size_t size, + int flags, bus_space_handle_t *bshp) +{ + u_long startpa, pa, endpa; + vaddr_t va; + + va = virtual_avail; /* steal memory from virtual avail. */ + + startpa = trunc_page(bpa); + endpa = round_page((bpa + size)); + + *bshp = (bus_space_handle_t)(va + (bpa - startpa)); + + for (pa = startpa; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE) + pmap_kenter_cache(va, pa, PROT_READ | PROT_WRITE, + PMAP_CACHE_DEV); + + virtual_avail = va; + + return 0; +} + +void +memreg_add(const struct fdt_reg *reg) +{ + int i; + + for (i = 0; i < nmemreg; i++) { + if (reg->addr == memreg[i].addr + memreg[i].size) { + memreg[i].size += reg->size; + return; + } + if (reg->addr + reg->size == memreg[i].addr) { + memreg[i].addr = reg->addr; + memreg[i].size += reg->size; + return; + } + } + + if (nmemreg >= nitems(memreg)) + return; + + memreg[nmemreg++] = *reg; +} + +void +memreg_remove(const struct fdt_reg *reg) +{ + uint64_t start = reg->addr; + uint64_t end = reg->addr + reg->size; + int i, j; + + for (i = 0; i < nmemreg; i++) { + uint64_t memstart = memreg[i].addr; + uint64_t memend = memreg[i].addr + memreg[i].size; + + if (end <= memstart) + continue; + if (start >= memend) + continue; + + if (start <= memstart) + memstart = MIN(end, memend); + if (end >= memend) + memend = MAX(start, memstart); + + if (start > memstart && end < memend) { + if (nmemreg < nitems(memreg)) { + memreg[nmemreg].addr = end; + memreg[nmemreg].size = memend - end; + nmemreg++; + } + memend = start; + } + memreg[i].addr = memstart; + memreg[i].size = memend - memstart; + } + + /* Remove empty slots. */ + for (i = nmemreg - 1; i >= 0; i--) { + if (memreg[i].size == 0) { + for (j = i; (j + 1) < nmemreg; j++) + memreg[j] = memreg[j + 1]; + nmemreg--; + } + } +} + +struct blink_led_softc { + SLIST_HEAD(, blink_led) bls_head; + int bls_on; + struct timeout bls_to; +} blink_sc = { SLIST_HEAD_INITIALIZER(blink_sc.bls_head), 0 }; + +void +blink_led_register(struct blink_led *l) +{ + if (SLIST_EMPTY(&blink_sc.bls_head)) { + timeout_set(&blink_sc.bls_to, blink_led_timeout, &blink_sc); + blink_sc.bls_on = 0; + if (led_blink) + timeout_add(&blink_sc.bls_to, 1); + } + SLIST_INSERT_HEAD(&blink_sc.bls_head, l, bl_next); +} + +void +blink_led_timeout(void *vsc) +{ + struct blink_led_softc *sc = &blink_sc; + struct blink_led *l; + int t; + + if (SLIST_EMPTY(&sc->bls_head)) + return; + + SLIST_FOREACH(l, &sc->bls_head, bl_next) { + (*l->bl_func)(l->bl_arg, sc->bls_on); + } + sc->bls_on = !sc->bls_on; + + if (!led_blink) + return; + + /* + * Blink rate is: + * full cycle every second if completely idle (loadav = 0) + * full cycle every 2 seconds if loadav = 1 + * full cycle every 3 seconds if loadav = 2 + * etc. + */ + t = (((averunnable.ldavg[0] + FSCALE) * hz) >> (FSHIFT + 1)); + timeout_add(&sc->bls_to, t); +} diff --git sys/arch/loongarch64/loongarch64/mem.c sys/arch/loongarch64/loongarch64/mem.c new file mode 100644 index 00000000000..3120997cd1f --- /dev/null +++ sys/arch/loongarch64/loongarch64/mem.c @@ -0,0 +1,254 @@ +/* $OpenBSD: mem.c,v 1.9 2024/12/30 02:46:00 guenther Exp $ */ + +/* + * Copyright (c) 1982, 1986, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Copyright (c) 1988 University of Utah. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Memory special file + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +caddr_t zeropage; + +/* open counter for aperture */ +#ifdef APERTURE +static int ap_open_count = 0; +extern int allowaperture; +#endif + +static struct rwlock physlock = RWLOCK_INITIALIZER("mmrw"); + +int +mmopen(dev_t dev, int flag, int mode, struct proc *p) +{ + extern int allowkmem; + + switch (minor(dev)) { + case 0: + case 1: + if ((int)atomic_load_int(&securelevel) <= 0 || + atomic_load_int(&allowkmem)) + break; + return (EPERM); + case 2: + case 12: + break; +#ifdef APERTURE + case 4: + if (suser(p) != 0 || !allowaperture) + return (EPERM); + + /* authorize only one simultaneous open() unless + * allowaperture=3 */ + if (ap_open_count > 0 && allowaperture < 3) + return (EPERM); + ap_open_count++; + break; +#endif + default: + return (ENXIO); + } + return (0); +} + +int +mmclose(dev_t dev, int flag, int mode, struct proc *p) +{ +#ifdef APERTURE + if (minor(dev) == 4) + ap_open_count = 0; +#endif + return (0); +} + +int +mmrw(dev_t dev, struct uio *uio, int flags) +{ + vaddr_t o, v; + size_t c; + struct iovec *iov; + int error = 0; + vm_prot_t prot; + extern caddr_t vmmap; + + if (minor(dev) == 0) { + /* lock against other uses of shared vmmap */ + error = rw_enter(&physlock, RW_WRITE | RW_INTR); + if (error) + return (error); + } + while (uio->uio_resid > 0 && error == 0) { + iov = uio->uio_iov; + if (iov->iov_len == 0) { + uio->uio_iov++; + uio->uio_iovcnt--; + if (uio->uio_iovcnt < 0) + panic("mmrw"); + continue; + } + switch (minor(dev)) { + + case 0: + v = uio->uio_offset; + prot = uio->uio_rw == UIO_READ ? PROT_READ : + PROT_WRITE; + pmap_enter(pmap_kernel(), (vaddr_t)vmmap, + trunc_page(v), prot, prot|PMAP_WIRED); + pmap_update(pmap_kernel()); + o = uio->uio_offset & PGOFSET; + c = ulmin(uio->uio_resid, PAGE_SIZE - o); + error = uiomove((caddr_t)vmmap + o, c, uio); + pmap_remove(pmap_kernel(), (vaddr_t)vmmap, + (vaddr_t)vmmap + PAGE_SIZE); + pmap_update(pmap_kernel()); + break; + + case 1: + v = uio->uio_offset; + c = ulmin(iov->iov_len, MAXPHYS); + if (!uvm_kernacc((caddr_t)v, c, + uio->uio_rw == UIO_READ ? B_READ : B_WRITE)) + return (EFAULT); + error = uiomove((caddr_t)v, c, uio); + break; + + case 2: + if (uio->uio_rw == UIO_WRITE) + uio->uio_resid = 0; + return (0); + + case 12: + if (uio->uio_rw == UIO_WRITE) { + uio->uio_resid = 0; + return (0); + } + if (zeropage == NULL) + zeropage = malloc(PAGE_SIZE, M_TEMP, + M_WAITOK | M_ZERO); + c = ulmin(iov->iov_len, PAGE_SIZE); + error = uiomove(zeropage, c, uio); + break; + + default: + return (ENXIO); + } + } + if (minor(dev) == 0) { + rw_exit(&physlock); + } + return (error); +} + +paddr_t +mmmmap(dev_t dev, off_t off, int prot) +{ + struct proc *p = curproc; /* XXX */ + + /* + * /dev/mem is the only one that makes sense through this + * interface. For /dev/kmem any physaddr we return here + * could be transient and hence incorrect or invalid at + * a later time. /dev/null just doesn't make any sense + * and /dev/zero is a hack that is handled via the default + * pager in mmap(). + */ + if (minor(dev) != 0) + return (-1); + + /* minor device 0 is physical memory */ + + if ((paddr_t)off >= ptoa((paddr_t)physmem) && + suser(p) != 0) + return -1; + return off; +} + +int +mmioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) +{ + switch (cmd) { + case FIOASYNC: + /* handled by fd layer */ + return 0; + } + + return (ENOTTY); +} diff --git sys/arch/loongarch64/loongarch64/openprom.c sys/arch/loongarch64/loongarch64/openprom.c new file mode 100644 index 00000000000..790d21b87a6 --- /dev/null +++ sys/arch/loongarch64/loongarch64/openprom.c @@ -0,0 +1,227 @@ +/* $OpenBSD: openprom.c,v 1.1 2021/04/23 12:01:03 jsg Exp $ */ +/* $NetBSD: openprom.c,v 1.4 2002/01/10 06:21:53 briggs Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Lawrence Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)openprom.c 8.1 (Berkeley) 6/11/93 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +static int lastnode; /* speed hack */ +static int optionsnode; /* node ID of ROM's options */ + +int openpromcheckid(int, int); +int openpromgetstr(int, char *, char **); +void openpromattach(int); + +void +openpromattach(int num) +{ +} + +int +openpromopen(dev_t dev, int flags, int mode, struct proc *p) +{ + return (0); +} + +int +openpromclose(dev_t dev, int flags, int mode, struct proc *p) +{ + return (0); +} + +/* + * Verify target ID is valid (exists in the OPENPROM tree), as + * listed from node ID sid forward. + */ +int +openpromcheckid(int sid, int tid) +{ + for (; sid != 0; sid = OF_peer(sid)) + if (sid == tid || openpromcheckid(OF_child(sid), tid)) + return (1); + + return (0); +} + +int +openpromgetstr(int len, char *user, char **cpp) +{ + int error; + char *cp; + + /* Reject obvious bogus requests */ + if ((u_int)len > (8 * 1024) - 1) + return (ENAMETOOLONG); + + *cpp = cp = malloc(len + 1, M_TEMP, M_WAITOK); + error = copyin(user, cp, len); + cp[len] = '\0'; + return (error); +} + +int +openpromioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) +{ + struct opiocdesc *op; + int node, len, ok, error; + char *name, *value, *nextprop; + + if (optionsnode == 0) + optionsnode = OF_getnodebyname(0, "options"); + + /* All too easy... */ + if (cmd == OPIOCGETOPTNODE) { + *(int *)data = optionsnode; + return (0); + } + + /* Verify node id */ + op = (struct opiocdesc *)data; + node = op->op_nodeid; + if (node != 0 && node != lastnode && node != optionsnode) { + /* Not an easy one, must search for it */ + ok = openpromcheckid(OF_peer(0), node); + if (!ok) + return (EINVAL); + lastnode = node; + } + + name = value = NULL; + error = 0; + switch (cmd) { + + case OPIOCGET: + if ((flags & FREAD) == 0) + return (EBADF); + if (node == 0) + return (EINVAL); + error = openpromgetstr(op->op_namelen, op->op_name, &name); + if (error) + break; + len = OF_getproplen(node, name); + if (len > op->op_buflen) { + error = ENOMEM; + break; + } + op->op_buflen = len; + /* -1 means no entry; 0 means no value */ + if (len <= 0) + break; + value = malloc(len, M_TEMP, M_WAITOK); + OF_getprop(node, name, value, len); + error = copyout(value, op->op_buf, len); + break; + + case OPIOCNEXTPROP: + if ((flags & FREAD) == 0) + return (EBADF); + if (node == 0) + return (EINVAL); + error = openpromgetstr(op->op_namelen, op->op_name, &name); + if (error) + break; + if (op->op_buflen <= 0) { + error = ENAMETOOLONG; + break; + } + value = nextprop = malloc(OFMAXPARAM, M_TEMP, + M_WAITOK | M_CANFAIL); + if (nextprop == NULL) { + error = ENOMEM; + break; + } + error = OF_nextprop(node, name, nextprop); + if (error == -1) { + error = EINVAL; + break; + } + if (error == 0) { + char nul = '\0'; + + op->op_buflen = 0; + error = copyout(&nul, op->op_buf, sizeof(char)); + break; + } + len = strlen(nextprop); + if (len > op->op_buflen) + len = op->op_buflen; + else + op->op_buflen = len; + error = copyout(nextprop, op->op_buf, len); + break; + + case OPIOCGETNEXT: + if ((flags & FREAD) == 0) + return (EBADF); + node = OF_peer(node); + *(int *)data = lastnode = node; + break; + + case OPIOCGETCHILD: + if ((flags & FREAD) == 0) + return (EBADF); + if (node == 0) + return (EINVAL); + node = OF_child(node); + *(int *)data = lastnode = node; + break; + + default: + return (ENOTTY); + } + + free(name, M_TEMP, 0); + free(value, M_TEMP, 0); + + return (error); +} diff --git sys/arch/loongarch64/loongarch64/pagezero.S sys/arch/loongarch64/loongarch64/pagezero.S new file mode 100644 index 00000000000..3e359e9bba6 --- /dev/null +++ sys/arch/loongarch64/loongarch64/pagezero.S @@ -0,0 +1,42 @@ +/* $OpenBSD: pagezero.S,v 1.2 2021/05/12 01:20:52 jsg Exp $ */ + +/* + * Copyright (c) 2020 Brian Bamsch + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include "assym.h" + +ENTRY(pagezero) + RETGUARD_SETUP(pagezero, $t6) + li.d $a1, PAGE_SIZE + add.d $a1, $a0, $a1 + +1: st.d $zero, $a0, 0 + st.d $zero, $a0, 8 + st.d $zero, $a0, 16 + st.d $zero, $a0, 24 + st.d $zero, $a0, 32 + st.d $zero, $a0, 40 + st.d $zero, $a0, 48 + st.d $zero, $a0, 56 + addi.d $a0, $a0, 64 + blt $a0, $a1, 1b + + RETGUARD_CHECK(pagezero, $t6) + jr $ra +END(pagezero) diff --git sys/arch/loongarch64/loongarch64/pmap.c sys/arch/loongarch64/loongarch64/pmap.c new file mode 100644 index 00000000000..2eb2fa03636 --- /dev/null +++ sys/arch/loongarch64/loongarch64/pmap.c @@ -0,0 +1,2181 @@ +/* $OpenBSD: pmap.c,v 1.49 2026/04/15 21:15:08 kettenis Exp $ */ + +/* + * Copyright (c) 2019-2020 Brian Bamsch + * Copyright (c) 2008-2009,2014-2016 Dale Rahn + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#ifdef MULTIPROCESSOR + +static inline int +pmap_is_active(struct pmap *pm, struct cpu_info *ci) +{ + return pm == pmap_kernel() || pm == ci->ci_curpm; +} + +#endif + +void +do_tlb_flush_page(pmap_t pm, vaddr_t va) +{ +#ifdef MULTIPROCESSOR + CPU_INFO_ITERATOR cii; + struct cpu_info *ci; + unsigned long hart_mask = 0; + + CPU_INFO_FOREACH(cii, ci) { + if (ci == curcpu()) + continue; + if (pmap_is_active(pm, ci)) + hart_mask |= (1UL << ci->ci_hartid); + } + + /* + * From the RISC-V privileged spec: + * + * SFENCE.VMA orders only the local hart's implicit references + * to the memory-management data structures. Consequently, other + * harts must be notified separately when the memory-management + * data structures have been modified. One approach is to use 1) + * a local data fence to ensure local writes are visible + * globally, then 2) an interprocessor interrupt to the other + * thread, then 3) a local SFENCE.VMA in the interrupt handler + * of the remote thread, and finally 4) signal back to + * originating thread that operation is complete. + */ + if (hart_mask != 0) { + membar_sync(); + sbi_remote_sfence_vma(&hart_mask, va, PAGE_SIZE); + } +#endif + + sfence_vma_page(va); +} + +void +do_tlb_flush(pmap_t pm) +{ +#ifdef MULTIPROCESSOR + CPU_INFO_ITERATOR cii; + struct cpu_info *ci; + unsigned long hart_mask = 0; + + CPU_INFO_FOREACH(cii, ci) { + if (ci == curcpu()) + continue; + if (pmap_is_active(pm, ci)) + hart_mask |= (1UL << ci->ci_hartid); + } + + /* + * From the RISC-V privileged spec: + * + * SFENCE.VMA orders only the local hart's implicit references + * to the memory-management data structures. Consequently, other + * harts must be notified separately when the memory-management + * data structures have been modified. One approach is to use 1) + * a local data fence to ensure local writes are visible + * globally, then 2) an interprocessor interrupt to the other + * thread, then 3) a local SFENCE.VMA in the interrupt handler + * of the remote thread, and finally 4) signal back to + * originating thread that operation is complete. + */ + if (hart_mask != 0) { + membar_sync(); + sbi_remote_sfence_vma(&hart_mask, 0, -1); + } +#endif + + sfence_vma(); +} + +void +tlb_flush_page(pmap_t pm, vaddr_t va) +{ + if (cpu_errata_sifive_cip_1200) + do_tlb_flush(pm); + else + do_tlb_flush_page(pm, va); +} + +static inline void +icache_flush(void) +{ +#ifdef MULTIPROCESSOR + CPU_INFO_ITERATOR cii; + struct cpu_info *ci; + unsigned long hart_mask = 0; +#endif + + fence_i(); + +#ifdef MULTIPROCESSOR + CPU_INFO_FOREACH(cii, ci) { + if (ci == curcpu()) + continue; + hart_mask |= (1UL << ci->ci_hartid); + } + + /* + * From the RISC-V ISA: + * + * To make a store to instruction memory visible to all RISC-V + * harts, the writing hart has to execute a data FENCE before + * requesting that all remote RISC-V harts execute a FENCE.I. + */ + if (hart_mask != 0) { + membar_sync(); + sbi_remote_fence_i(&hart_mask); + } +#endif +} + +struct pmap kernel_pmap_; + +LIST_HEAD(pted_pv_head, pte_desc); + +struct pte_desc { + LIST_ENTRY(pte_desc) pted_pv_list; + pt_entry_t pted_pte; + pmap_t pted_pmap; + vaddr_t pted_va; +}; + +struct pmapvp1 { + pt_entry_t l1[VP_IDX1_CNT]; + struct pmapvp2 *vp[VP_IDX1_CNT]; +}; + +struct pmapvp2 { + pt_entry_t l2[VP_IDX2_CNT]; + struct pmapvp3 *vp[VP_IDX2_CNT]; +}; + +struct pmapvp3 { + pt_entry_t l3[VP_IDX3_CNT]; + struct pte_desc *vp[VP_IDX3_CNT]; +}; +CTASSERT(sizeof(struct pmapvp1) == sizeof(struct pmapvp2)); +CTASSERT(sizeof(struct pmapvp1) == sizeof(struct pmapvp3)); + +void pmap_vp_destroy(pmap_t); + +/* Allocator for VP pool. */ +void *pmap_vp_page_alloc(struct pool *, int, int *); +void pmap_vp_page_free(struct pool *, void *); + +struct pool_allocator pmap_vp_allocator = { + pmap_vp_page_alloc, pmap_vp_page_free, sizeof(struct pmapvp1) +}; + +void pmap_remove_pted(pmap_t, struct pte_desc *); +void pmap_kremove_pg(vaddr_t); +void pmap_set_l2(struct pmap *, uint64_t, struct pmapvp2 *, paddr_t); +void pmap_set_l3(struct pmap *, uint64_t, struct pmapvp3 *, paddr_t); +void pmap_set_satp(struct proc *); + +void pmap_fill_pte(pmap_t, vaddr_t, paddr_t, struct pte_desc *, + vm_prot_t, int, int); +void pmap_pte_insert(struct pte_desc *); +void pmap_pte_remove(struct pte_desc *, int); +void pmap_pte_update(struct pte_desc *, pt_entry_t *); +void pmap_release(pmap_t); +paddr_t pmap_steal_avail(size_t, int, void **); +void pmap_remove_avail(paddr_t, paddr_t); +vaddr_t pmap_map_stolen(vaddr_t); + +vaddr_t vmmap; +vaddr_t zero_page; +vaddr_t copy_src_page; +vaddr_t copy_dst_page; + +#define CPU_VENDOR_THEAD 0x5b7 + +struct pool pmap_pmap_pool; +struct pool pmap_pted_pool; +struct pool pmap_vp_pool; + +int pmap_initialized = 0; + +struct mem_region { + vaddr_t start; + vsize_t size; +}; + +struct mem_region pmap_avail_regions[10]; +struct mem_region pmap_allocated_regions[10]; +struct mem_region *pmap_avail = &pmap_avail_regions[0]; +struct mem_region *pmap_allocated = &pmap_allocated_regions[0]; +int pmap_cnt_avail, pmap_cnt_allocated; +uint64_t pmap_avail_kvo; + +paddr_t pmap_cached_start, pmap_cached_end; +paddr_t pmap_uncached_start, pmap_uncached_end; + +static inline void +pmap_lock(struct pmap *pmap) +{ + if (pmap != pmap_kernel()) + mtx_enter(&pmap->pm_mtx); +} + +static inline void +pmap_unlock(struct pmap *pmap) +{ + if (pmap != pmap_kernel()) + mtx_leave(&pmap->pm_mtx); +} + +/* virtual to physical helpers */ +static inline int +VP_IDX1(vaddr_t va) +{ + return (va >> VP_IDX1_POS) & VP_IDX1_MASK; +} + +static inline int +VP_IDX2(vaddr_t va) +{ + return (va >> VP_IDX2_POS) & VP_IDX2_MASK; +} + +static inline int +VP_IDX3(vaddr_t va) +{ + return (va >> VP_IDX3_POS) & VP_IDX3_MASK; +} + +/* + * On RISC-V, the encodings for write permission without read + * permission (r=0, w=1, x=0, or r=0, w=1, x=1) are reserved, so + * PROT_WRITE implies PROT_READ. We need to handle PROT_NONE + * separately (see pmap_pte_update()) since r=0, w=0, x=0 is reserved + * for non-leaf page table entries. + */ +const pt_entry_t ap_bits_user[8] = { + [PROT_NONE] = 0, + [PROT_READ] = PTE_U|PTE_A|PTE_R, + [PROT_WRITE] = PTE_U|PTE_A|PTE_R|PTE_D|PTE_W, + [PROT_WRITE|PROT_READ] = PTE_U|PTE_A|PTE_R|PTE_D|PTE_W, + [PROT_EXEC] = PTE_U|PTE_A|PTE_X, + [PROT_EXEC|PROT_READ] = PTE_U|PTE_A|PTE_X|PTE_R, + [PROT_EXEC|PROT_WRITE] = PTE_U|PTE_A|PTE_X|PTE_R|PTE_D|PTE_W, + [PROT_EXEC|PROT_WRITE|PROT_READ] = PTE_U|PTE_A|PTE_X|PTE_R|PTE_D|PTE_W, +}; + +const pt_entry_t ap_bits_kern[8] = { + [PROT_NONE] = 0, + [PROT_READ] = PTE_A|PTE_R, + [PROT_WRITE] = PTE_A|PTE_R|PTE_D|PTE_W, + [PROT_WRITE|PROT_READ] = PTE_A|PTE_R|PTE_D|PTE_W, + [PROT_EXEC] = PTE_A|PTE_X, + [PROT_EXEC|PROT_READ] = PTE_A|PTE_X|PTE_R, + [PROT_EXEC|PROT_WRITE] = PTE_A|PTE_X|PTE_R|PTE_D|PTE_W, + [PROT_EXEC|PROT_WRITE|PROT_READ] = PTE_A|PTE_X|PTE_R|PTE_D|PTE_W, +}; + +/* PBMT encodings for the Svpbmt modes. */ +uint64_t pmap_pma; +uint64_t pmap_nc; +uint64_t pmap_io; + +/* + * This is used for pmap_kernel() mappings, they are not to be removed + * from the vp table because they were statically initialized at the + * initial pmap initialization. This is so that memory allocation + * is not necessary in the pmap_kernel() mappings. + * Otherwise bad race conditions can appear. + */ +struct pte_desc * +pmap_vp_lookup(pmap_t pm, vaddr_t va, pt_entry_t **pl3entry) +{ + struct pmapvp1 *vp1; + struct pmapvp2 *vp2; + struct pmapvp3 *vp3; + struct pte_desc *pted; + + vp1 = pm->pm_vp.l1; + if (vp1 == NULL) { + return NULL; + } + + vp2 = vp1->vp[VP_IDX1(va)]; + if (vp2 == NULL) { + return NULL; + } + + vp3 = vp2->vp[VP_IDX2(va)]; + if (vp3 == NULL) { + return NULL; + } + + pted = vp3->vp[VP_IDX3(va)]; + if (pl3entry != NULL) + *pl3entry = &(vp3->l3[VP_IDX3(va)]); + + return pted; +} + +/* + * Create a V -> P mapping for the given pmap and virtual address + * with reference to the pte descriptor that is used to map the page. + * This code should track allocations of vp table allocations + * so they can be freed efficiently. + * + * XXX it may be possible to save some bits of count in the + * upper address bits of the pa or the pte entry. + * However that does make populating the other bits more tricky. + * each level has 512 entries, so that mean 9 bits to store + * stash 3 bits each in the first 3 entries? + */ +int +pmap_vp_enter(pmap_t pm, vaddr_t va, struct pte_desc *pted, int flags) +{ + struct pmapvp1 *vp1; + struct pmapvp2 *vp2; + struct pmapvp3 *vp3; + + vp1 = pm->pm_vp.l1; + + vp2 = vp1->vp[VP_IDX1(va)]; + if (vp2 == NULL) { + vp2 = pool_get(&pmap_vp_pool, PR_NOWAIT | PR_ZERO); + if (vp2 == NULL) { + if ((flags & PMAP_CANFAIL) == 0) + panic("%s: unable to allocate L2", __func__); + return ENOMEM; + } + pmap_set_l2(pm, va, vp2, 0); + } + + vp3 = vp2->vp[VP_IDX2(va)]; + if (vp3 == NULL) { + vp3 = pool_get(&pmap_vp_pool, PR_NOWAIT | PR_ZERO); + if (vp3 == NULL) { + if ((flags & PMAP_CANFAIL) == 0) + panic("%s: unable to allocate L3", __func__); + return ENOMEM; + } + pmap_set_l3(pm, va, vp3, 0); + } + + vp3->vp[VP_IDX3(va)] = pted; + return 0; +} + +void +pmap_vp_populate(pmap_t pm, vaddr_t va) +{ + struct pte_desc *pted; + struct pmapvp1 *vp1; + struct pmapvp2 *vp2; + struct pmapvp3 *vp3; + void *vp; + + pted = pool_get(&pmap_pted_pool, PR_WAITOK | PR_ZERO); + vp = pool_get(&pmap_vp_pool, PR_WAITOK | PR_ZERO); + + pmap_lock(pm); + + vp1 = pm->pm_vp.l1; + + vp2 = vp1->vp[VP_IDX1(va)]; + if (vp2 == NULL) { + vp2 = vp; vp = NULL; + pmap_set_l2(pm, va, vp2, 0); + } + + if (vp == NULL) { + pmap_unlock(pm); + vp = pool_get(&pmap_vp_pool, PR_WAITOK | PR_ZERO); + pmap_lock(pm); + } + + vp3 = vp2->vp[VP_IDX2(va)]; + if (vp3 == NULL) { + vp3 = vp; vp = NULL; + pmap_set_l3(pm, va, vp3, 0); + } + + if (vp3->vp[VP_IDX3(va)] == NULL) { + vp3->vp[VP_IDX3(va)] = pted; + pted = NULL; + } + + pmap_unlock(pm); + + if (vp) + pool_put(&pmap_vp_pool, vp); + if (pted) + pool_put(&pmap_pted_pool, pted); +} + +void * +pmap_vp_page_alloc(struct pool *pp, int flags, int *slowdown) +{ + struct kmem_dyn_mode kd = KMEM_DYN_INITIALIZER; + + kd.kd_waitok = ISSET(flags, PR_WAITOK); + kd.kd_trylock = ISSET(flags, PR_NOWAIT); + kd.kd_slowdown = slowdown; + + return km_alloc(pp->pr_pgsize, &kv_any, &kp_dirty, &kd); +} + +void +pmap_vp_page_free(struct pool *pp, void *v) +{ + km_free(v, pp->pr_pgsize, &kv_any, &kp_dirty); +} + +static inline u_int32_t +PTED_MANAGED(struct pte_desc *pted) +{ + return (pted->pted_va & PTED_VA_MANAGED_M); +} + +static inline u_int32_t +PTED_WIRED(struct pte_desc *pted) +{ + return (pted->pted_va & PTED_VA_WIRED_M); +} + +static inline u_int32_t +PTED_VALID(struct pte_desc *pted) +{ + return (pted->pted_pte != 0); +} + +/* + * PV entries - + * manipulate the physical to virtual translations for the entire system. + * + * QUESTION: should all mapped memory be stored in PV tables? Or + * is it alright to only store "ram" memory. Currently device mappings + * are not stored. + * It makes sense to pre-allocate mappings for all of "ram" memory, since + * it is likely that it will be mapped at some point, but would it also + * make sense to use a tree/table like is use for pmap to store device + * mappings? + * Further notes: It seems that the PV table is only used for pmap_protect + * and other paging related operations. Given this, it is not necessary + * to store any pmap_kernel() entries in PV tables and does not make + * sense to store device mappings in PV either. + * + * Note: unlike other powerpc pmap designs, the array is only an array + * of pointers. Since the same structure is used for holding information + * in the VP table, the PV table, and for kernel mappings, the wired entries. + * Allocate one data structure to hold all of the info, instead of replicating + * it multiple times. + * + * One issue of making this a single data structure is that two pointers are + * wasted for every page which does not map ram (device mappings), this + * should be a low percentage of mapped pages in the system, so should not + * have too noticeable unnecessary ram consumption. + */ + +void +pmap_enter_pv(struct pte_desc *pted, struct vm_page *pg) +{ + /* + * XXX does this test mean that some pages try to be managed, + * but this is called too soon? + */ + if (__predict_false(!pmap_initialized)) + return; + + mtx_enter(&pg->mdpage.pv_mtx); + LIST_INSERT_HEAD(&(pg->mdpage.pv_list), pted, pted_pv_list); + pted->pted_va |= PTED_VA_MANAGED_M; + mtx_leave(&pg->mdpage.pv_mtx); +} + +void +pmap_remove_pv(struct pte_desc *pted) +{ + struct vm_page *pg = PHYS_TO_VM_PAGE(pted->pted_pte & PTE_RPGN); + + mtx_enter(&pg->mdpage.pv_mtx); + LIST_REMOVE(pted, pted_pv_list); + mtx_leave(&pg->mdpage.pv_mtx); +} + +int +pmap_enter(pmap_t pm, vaddr_t va, paddr_t pa, vm_prot_t prot, int flags) +{ + struct pte_desc *pted; + struct vm_page *pg; + int error; + int cache = PMAP_CACHE_WB; + + if (pa & PMAP_NOCACHE) + cache = PMAP_CACHE_CI; + if (pa & PMAP_DEVICE) + cache = PMAP_CACHE_DEV; + pg = PHYS_TO_VM_PAGE(pa); + + pmap_lock(pm); + pted = pmap_vp_lookup(pm, va, NULL); + if (pted && PTED_VALID(pted)) { + if ((pted->pted_pte & PTE_RPGN) == (pa & PTE_RPGN) && + (pted->pted_va & PROT_MASK) == (prot & PROT_MASK) && + (pted->pted_va & PMAP_CACHE_BITS) == cache) { + pmap_unlock(pm); + return 0; + } + + pmap_remove_pted(pm, pted); + /* we lost our pted if it was user */ + if (pm != pmap_kernel()) + pted = pmap_vp_lookup(pm, va, NULL); + } + + pm->pm_stats.resident_count++; + + /* Do not have pted for this, get one and put it in VP */ + if (pted == NULL) { + pted = pool_get(&pmap_pted_pool, PR_NOWAIT | PR_ZERO); + if (pted == NULL) { + if ((flags & PMAP_CANFAIL) == 0) + panic("%s: failed to allocate pted", __func__); + error = ENOMEM; + goto out; + } + if (pmap_vp_enter(pm, va, pted, flags)) { + if ((flags & PMAP_CANFAIL) == 0) + panic("%s: failed to allocate L2/L3", __func__); + error = ENOMEM; + pool_put(&pmap_pted_pool, pted); + goto out; + } + } + + /* + * If it should be enabled _right now_, we can skip doing ref/mod + * emulation. Any access includes reference, modified only by write. + */ + if (pg != NULL && + ((flags & PROT_MASK) || (pg->pg_flags & PG_PMAP_REF))) { + atomic_setbits_int(&pg->pg_flags, PG_PMAP_REF); + if ((prot & PROT_WRITE) && (flags & PROT_WRITE)) { + atomic_setbits_int(&pg->pg_flags, PG_PMAP_MOD); + atomic_clearbits_int(&pg->pg_flags, PG_PMAP_EXE); + } + } + + pmap_fill_pte(pm, va, pa, pted, prot, flags, cache); + + if (pg != NULL) { + pmap_enter_pv(pted, pg); /* only managed mem */ + } + + if (pg != NULL && (flags & PROT_EXEC)) { + if ((pg->pg_flags & PG_PMAP_EXE) == 0) + icache_flush(); + atomic_setbits_int(&pg->pg_flags, PG_PMAP_EXE); + } + + /* + * Insert into table, if this mapping said it needed to be mapped + * now. + */ + if (flags & (PROT_READ|PROT_WRITE|PROT_EXEC|PMAP_WIRED)) { + pmap_pte_insert(pted); + tlb_flush_page(pm, va & ~PAGE_MASK); + } + + error = 0; +out: + pmap_unlock(pm); + return error; +} + +void +pmap_populate(pmap_t pm, vaddr_t va) +{ + pmap_vp_populate(pm, va); +} + +/* + * Remove the given range of mapping entries. + */ +void +pmap_remove(pmap_t pm, vaddr_t sva, vaddr_t eva) +{ + struct pte_desc *pted; + vaddr_t va; + + pmap_lock(pm); + for (va = sva; va < eva; va += PAGE_SIZE) { + pted = pmap_vp_lookup(pm, va, NULL); + + if (pted == NULL) + continue; + + if (PTED_WIRED(pted)) { + pm->pm_stats.wired_count--; + pted->pted_va &= ~PTED_VA_WIRED_M; + } + + if (PTED_VALID(pted)) + pmap_remove_pted(pm, pted); + } + pmap_unlock(pm); +} + +/* + * remove a single mapping, notice that this code is O(1) + */ +void +pmap_remove_pted(pmap_t pm, struct pte_desc *pted) +{ + pm->pm_stats.resident_count--; + + if (PTED_WIRED(pted)) { + pm->pm_stats.wired_count--; + pted->pted_va &= ~PTED_VA_WIRED_M; + } + + pmap_pte_remove(pted, pm != pmap_kernel()); + tlb_flush_page(pm, pted->pted_va & ~PAGE_MASK); + + if (PTED_MANAGED(pted)) + pmap_remove_pv(pted); + + pted->pted_pte = 0; + pted->pted_va = 0; + + if (pm != pmap_kernel()) + pool_put(&pmap_pted_pool, pted); +} + + +/* + * Populate a kernel mapping for the given page. + * kernel mappings have a larger set of prerequisites than normal mappings. + * + * 1. no memory should be allocated to create a kernel mapping. + * 2. a vp mapping should already exist, even if invalid. (see 1) + * 3. all vp tree mappings should already exist (see 1) + * + */ +void +_pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot, int flags, int cache) +{ + pmap_t pm = pmap_kernel(); + struct pte_desc *pted; + struct vm_page *pg; + + pg = PHYS_TO_VM_PAGE(pa); + if (pg && cache == PMAP_CACHE_CI) { + _pmap_kenter_pa(va, pa, prot, flags, PMAP_CACHE_WB); + cpu_dcache_wbinv_range(va & ~PAGE_MASK, PAGE_SIZE); + } + + pted = pmap_vp_lookup(pm, va, NULL); + + /* Do not have pted for this, get one and put it in VP */ + if (pted == NULL) { + panic("pted not preallocated in pmap_kernel() va %lx pa %lx", + va, pa); + } + + if (pted && PTED_VALID(pted)) + pmap_kremove_pg(va); /* pted is reused */ + + pm->pm_stats.resident_count++; + + flags |= PMAP_WIRED; /* kernel mappings are always wired. */ + /* Calculate PTE */ + pmap_fill_pte(pm, va, pa, pted, prot, flags, cache); + + /* + * Insert into table + * We were told to map the page, probably called from vm_fault, + * so map the page! + */ + pmap_pte_insert(pted); + tlb_flush_page(pm, va & ~PAGE_MASK); +} + +void +pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot) +{ + int cache = PMAP_CACHE_WB; + + if (pa & PMAP_NOCACHE) + cache = PMAP_CACHE_CI; + if (pa & PMAP_DEVICE) + cache = PMAP_CACHE_DEV; + + _pmap_kenter_pa(va, pa, prot, prot, cache); +} + +void +pmap_kenter_cache(vaddr_t va, paddr_t pa, vm_prot_t prot, int cacheable) +{ + _pmap_kenter_pa(va, pa, prot, prot, cacheable); +} + +/* + * remove kernel (pmap_kernel()) mapping, one page + */ +void +pmap_kremove_pg(vaddr_t va) +{ + pmap_t pm = pmap_kernel(); + struct pte_desc *pted; + int s; + + pted = pmap_vp_lookup(pm, va, NULL); + if (pted == NULL) + return; + + if (!PTED_VALID(pted)) + return; /* not mapped */ + + s = splvm(); + + pm->pm_stats.resident_count--; + + /* + * Table needs to be locked here as well as pmap, and pv list. + * so that we know the mapping information is either valid, + * or that the mapping is not present in the hash table. + */ + pmap_pte_remove(pted, 0); + tlb_flush_page(pm, pted->pted_va & ~PAGE_MASK); + + if (PTED_MANAGED(pted)) + pmap_remove_pv(pted); + + if (PTED_WIRED(pted)) + pm->pm_stats.wired_count--; + + /* invalidate pted; */ + pted->pted_pte = 0; + pted->pted_va = 0; + + splx(s); +} + +/* + * remove kernel (pmap_kernel()) mappings + */ +void +pmap_kremove(vaddr_t va, vsize_t len) +{ + for (len >>= PAGE_SHIFT; len >0; len--, va += PAGE_SIZE) + pmap_kremove_pg(va); +} + +void +pmap_fill_pte(pmap_t pm, vaddr_t va, paddr_t pa, struct pte_desc *pted, + vm_prot_t prot, int flags, int cache) +{ + pted->pted_va = va; + pted->pted_pmap = pm; + + switch (cache) { + case PMAP_CACHE_WB: + break; + case PMAP_CACHE_CI: + if (pa >= pmap_cached_start && pa <= pmap_cached_end) + pa += (pmap_uncached_start - pmap_cached_start); + break; + case PMAP_CACHE_DEV: + break; + default: + panic("%s: invalid cache mode", __func__); + } + pted->pted_va |= cache; + + pted->pted_va |= prot & PROT_MASK; + + if (flags & PMAP_WIRED) { + pted->pted_va |= PTED_VA_WIRED_M; + pm->pm_stats.wired_count++; + } + + pted->pted_pte = pa & PTE_RPGN; + pted->pted_pte |= flags & PROT_MASK; +} + +/* + * Fill the given physical page with zeros. + */ +void +pmap_zero_page(struct vm_page *pg) +{ + paddr_t pa = VM_PAGE_TO_PHYS(pg); + vaddr_t va = zero_page + cpu_number() * PAGE_SIZE; + + pmap_kenter_pa(va, pa, PROT_READ|PROT_WRITE); + pagezero(va); + pmap_kremove_pg(va); +} + +/* + * Copy the given physical page. + */ +void +pmap_copy_page(struct vm_page *srcpg, struct vm_page *dstpg) +{ + paddr_t srcpa = VM_PAGE_TO_PHYS(srcpg); + paddr_t dstpa = VM_PAGE_TO_PHYS(dstpg); + vaddr_t srcva = copy_src_page + cpu_number() * PAGE_SIZE; + vaddr_t dstva = copy_dst_page + cpu_number() * PAGE_SIZE; + int s; + + /* + * XXX The buffer flipper (incorrectly?) uses pmap_copy_page() + * (from uvm_pagerealloc_multi()) from interrupt context! + */ + s = splbio(); + pmap_kenter_pa(srcva, srcpa, PROT_READ); + pmap_kenter_pa(dstva, dstpa, PROT_READ|PROT_WRITE); + memcpy((void *)dstva, (void *)srcva, PAGE_SIZE); + pmap_kremove_pg(srcva); + pmap_kremove_pg(dstva); + splx(s); +} + +void +pmap_pinit(pmap_t pm) +{ + struct pmapvp1 *vp1, *kvp1; + vaddr_t l1va; + uint64_t l1pa; + + /* Allocate a full L1 table. */ + while (pm->pm_vp.l1 == NULL) { + pm->pm_vp.l1 = pool_get(&pmap_vp_pool, + PR_WAITOK | PR_ZERO); + } + + vp1 = pm->pm_vp.l1; /* top level is l1 */ + l1va = (vaddr_t)vp1->l1; + + /* Fill kernel PTEs. */ + kvp1 = pmap_kernel()->pm_vp.l1; + memcpy(&vp1->l1[L1_KERN_BASE], &kvp1->l1[L1_KERN_BASE], + L1_KERN_ENTRIES * sizeof(pt_entry_t)); + memcpy(&vp1->vp[L1_KERN_BASE], &kvp1->vp[L1_KERN_BASE], + L1_KERN_ENTRIES * sizeof(struct pmapvp2 *)); + + pmap_extract(pmap_kernel(), l1va, (paddr_t *)&l1pa); + pmap_reference(pm); +} + +int pmap_vp_poolcache = 0; /* force vp poolcache to allocate late */ + +/* + * Create and return a physical map. + */ +pmap_t +pmap_create(void) +{ + pmap_t pmap; + + pmap = pool_get(&pmap_pmap_pool, PR_WAITOK | PR_ZERO); + + mtx_init(&pmap->pm_mtx, IPL_VM); + + pmap_pinit(pmap); + if (pmap_vp_poolcache == 0) { + pool_setlowat(&pmap_vp_pool, 20); + pmap_vp_poolcache = 20; + } + return (pmap); +} + +/* + * Add a reference to a given pmap. + */ +void +pmap_reference(pmap_t pm) +{ + atomic_inc_int(&pm->pm_refs); +} + +/* + * Retire the given pmap from service. + * Should only be called if the map contains no valid mappings. + */ +void +pmap_destroy(pmap_t pm) +{ + int refs; + + refs = atomic_dec_int_nv(&pm->pm_refs); + if (refs > 0) + return; + + /* + * reference count is zero, free pmap resources and free pmap. + */ + pmap_release(pm); + pool_put(&pmap_pmap_pool, pm); +} + +/* + * Release any resources held by the given physical map. + * Called when a pmap initialized by pmap_pinit is being released. + */ +void +pmap_release(pmap_t pm) +{ + pmap_vp_destroy(pm); +} + +void +pmap_vp_destroy(pmap_t pm) +{ + struct pmapvp1 *vp1; + struct pmapvp2 *vp2; + struct pmapvp3 *vp3; + struct pte_desc *pted; + int j, k, l; + + vp1 = pm->pm_vp.l1; + /* + * there is not a separate supervisor and user page table root ? + * remove only user page tables + */ + for (j = 0; j < L1_KERN_BASE; j++) { + vp2 = vp1->vp[j]; + if (vp2 == NULL) + continue; + vp1->vp[j] = NULL; + + for (k = 0; k < VP_IDX2_CNT; k++) { + vp3 = vp2->vp[k]; + if (vp3 == NULL) + continue; + vp2->vp[k] = NULL; + + for (l = 0; l < VP_IDX3_CNT; l++) { + pted = vp3->vp[l]; + if (pted == NULL) + continue; + vp3->vp[l] = NULL; + + pool_put(&pmap_pted_pool, pted); + } + pool_put(&pmap_vp_pool, vp3); + } + pool_put(&pmap_vp_pool, vp2); + } + pool_put(&pmap_vp_pool, pm->pm_vp.l1); + pm->pm_vp.l1 = NULL; + return; +} + +vaddr_t virtual_avail; +int pmap_virtual_space_called; + +static inline pt_entry_t +VP_Lx(paddr_t pa) +{ + /* + * This function takes the pa address given and manipulates it + * into the form that should be inserted into the VM table. + */ + // NOTE: We always assume the entry is valid. OpenBSD/arm64 uses + // the least significant bits to differentiate between PTD / PTE. + // In address translation mode PTD / PTE distinguished + // by the lack of PTE_R / PTE_X on an entry with PTE_V set. For both + // a PTD and PTE, the PTE_V bit is set. + return (((pa & PTE_RPGN) >> PAGE_SHIFT) << PTE_PPN0_S) | PTE_V; +} + +/* + * In pmap_bootstrap() we allocate the page tables for the first GB + * of the kernel address space. + */ +vaddr_t pmap_maxkvaddr = VM_MIN_KERNEL_ADDRESS + 1024 * 1024 * 1024; + +/* + * Allocator for growing the kernel page tables. We use a dedicated + * submap to make sure we have the space to map them as we are called + * when address space is tight! + */ + +struct vm_map *pmap_kvp_map; + +const struct kmem_va_mode kv_kvp = { + .kv_map = &pmap_kvp_map, + .kv_wait = 0 +}; + +void * +pmap_kvp_alloc(void) +{ + void *kvp; + + if (!uvm.page_init_done && !pmap_virtual_space_called) { + paddr_t pa[2]; + vaddr_t va; + + if (!uvm_page_physget(&pa[0]) || !uvm_page_physget(&pa[1])) + panic("%s: out of memory", __func__); + + va = virtual_avail; + virtual_avail += 2 * PAGE_SIZE; + KASSERT(virtual_avail <= pmap_maxkvaddr); + kvp = (void *)va; + + pmap_kenter_pa(va, pa[0], PROT_READ|PROT_WRITE); + pmap_kenter_pa(va + PAGE_SIZE, pa[1], PROT_READ|PROT_WRITE); + pagezero(va); + pagezero(va + PAGE_SIZE); + } else { + kvp = km_alloc(sizeof(struct pmapvp1), &kv_kvp, &kp_zero, + &kd_nowait); + } + + return kvp; +} + +struct pte_desc * +pmap_kpted_alloc(void) +{ + static struct pte_desc *pted; + static int npted; + + if (npted == 0) { + if (!uvm.page_init_done && !pmap_virtual_space_called) { + paddr_t pa; + vaddr_t va; + + if (!uvm_page_physget(&pa)) + panic("%s: out of memory", __func__); + + va = virtual_avail; + virtual_avail += PAGE_SIZE; + KASSERT(virtual_avail <= pmap_maxkvaddr); + pted = (struct pte_desc *)va; + + pmap_kenter_pa(va, pa, PROT_READ|PROT_WRITE); + pagezero(va); + } else { + pted = km_alloc(PAGE_SIZE, &kv_kvp, &kp_zero, + &kd_nowait); + if (pted == NULL) + return NULL; + } + + npted = PAGE_SIZE / sizeof(struct pte_desc); + } + + npted--; + return pted++; +} + +vaddr_t +pmap_growkernel(vaddr_t maxkvaddr) +{ + struct pmapvp1 *vp1 = pmap_kernel()->pm_vp.l1; + struct pmapvp2 *vp2; + struct pmapvp3 *vp3; + struct pte_desc *pted; + paddr_t pa; + int lb_idx2, ub_idx2; + int i, j, k; + int s; + + if (maxkvaddr <= pmap_maxkvaddr) + return pmap_maxkvaddr; + + /* + * Not strictly necessary, but we use an interrupt-safe map + * and uvm asserts that we're at IPL_VM. + */ + s = splvm(); + + for (i = VP_IDX1(pmap_maxkvaddr); i <= VP_IDX1(maxkvaddr - 1); i++) { + vp2 = vp1->vp[i]; + KASSERT(vp2 != NULL); + + if (i == VP_IDX1(pmap_maxkvaddr)) { + lb_idx2 = VP_IDX2(pmap_maxkvaddr); + } else { + lb_idx2 = 0; + } + + if (i == VP_IDX1(maxkvaddr - 1)) { + ub_idx2 = VP_IDX2(maxkvaddr - 1); + } else { + ub_idx2 = VP_IDX2_CNT - 1; + } + + for (j = lb_idx2; j <= ub_idx2; j++) { + vp3 = vp2->vp[j]; + if (vp3 == NULL) { + vp3 = pmap_kvp_alloc(); + if (vp3 == NULL) + goto fail; + pmap_extract(pmap_kernel(), (vaddr_t)vp3, &pa); + vp2->vp[j] = vp3; + vp2->l2[j] = VP_Lx(pa); + } + + for (k = 0; k <= VP_IDX3_CNT - 1; k++) { + if (vp3->vp[k] == NULL) { + pted = pmap_kpted_alloc(); + if (pted == NULL) + goto fail; + vp3->vp[k] = pted; + pmap_maxkvaddr += PAGE_SIZE; + } + } + } + } + KASSERT(pmap_maxkvaddr >= maxkvaddr); + +fail: + splx(s); + + return pmap_maxkvaddr; +} + +void pmap_setup_avail(uint64_t memstart, uint64_t memend, uint64_t kvo); + +/* + * Initialize pmap setup. + * ALL of the code which deals with avail needs rewritten as an actual + * memory allocation. + */ +CTASSERT(sizeof(struct pmapvp1) == 2 * PAGE_SIZE); + +int mappings_allocated = 0; +int pted_allocated = 0; + +extern char __text_start[], _etext[]; +extern char __rodata_start[], _erodata[]; + +paddr_t dmap_phys_base; + +void +pmap_bootstrap_dmap(vaddr_t kern_l1, paddr_t min_pa, paddr_t max_pa) +{ + vaddr_t va; + paddr_t pa; + pt_entry_t *l1; + u_int l1_slot; + pt_entry_t entry; + pn_t pn; + + pa = dmap_phys_base = min_pa & ~L1_OFFSET; // 1 GiB Align + va = DMAP_MIN_ADDRESS; + l1 = (pt_entry_t *)kern_l1; + l1_slot = VP_IDX1(DMAP_MIN_ADDRESS); + + for (; va < DMAP_MAX_ADDRESS && pa < max_pa; + pa += L1_SIZE, va += L1_SIZE, l1_slot++) { + KASSERT(l1_slot < Ln_ENTRIES); + + /* gigapages */ + pn = (pa / PAGE_SIZE); + entry = PTE_KERN | pmap_pma; + entry |= (pn << PTE_PPN0_S); + l1[l1_slot] = entry; + } + + sfence_vma(); +} + +vaddr_t +pmap_bootstrap(long kvo, vaddr_t l1pt, vaddr_t kernelstart, vaddr_t kernelend, + paddr_t memstart, paddr_t memend) +{ + void *va; + paddr_t pa, pt1pa; + struct pmapvp1 *vp1; + struct pmapvp2 *vp2; + struct pmapvp3 *vp3; + struct pte_desc *pted; + vaddr_t vstart; + int i, j, k; + int lb_idx2, ub_idx2; + uint64_t marchid, mimpid; + uint32_t mvendorid; + + mvendorid = sbi_get_mvendorid(); + marchid = sbi_get_marchid(); + mimpid = sbi_get_mimpid(); + + /* + * The T-Head cores implement a page attributes extension that + * violates the RISC-V privileged architecture specification. + * Work around this as best as we can by adding the + * appropriate page attributes in a way that is mostly + * compatible with the Svpbmt extension. + */ + if (mvendorid == CPU_VENDOR_THEAD && marchid == 0 && mimpid == 0) { + pmap_pma = PTE_THEAD_C | PTE_THEAD_B | PTE_THEAD_SH; + pmap_nc = PTE_THEAD_B | PTE_THEAD_SH; + pmap_io = PTE_THEAD_SO | PTE_THEAD_SH; + } + + pmap_setup_avail(memstart, memend, kvo); + pmap_remove_avail(kernelstart + kvo, kernelend + kvo); + + /* + * KERNEL IS ASSUMED TO BE 39 bits (or less), start from L1, + * not L0 ALSO kernel mappings may not cover enough ram to + * bootstrap so all accesses initializing tables must be done + * via physical pointers + */ + + /* Map the initial 64MB block to the Direct Mapped Region. */ + pmap_bootstrap_dmap(l1pt, memstart, memend); + + pt1pa = pmap_steal_avail(2 * sizeof(struct pmapvp1), Lx_TABLE_ALIGN, + &va); + vp1 = (struct pmapvp1 *) PHYS_TO_DMAP(pt1pa); + pmap_kernel()->pm_vp.l1 = (struct pmapvp1 *)va; + pmap_kernel()->pm_privileged = 1; + + /* allocate memory (in unit of pages) for l2 and l3 page table */ + for (i = VP_IDX1(VM_MIN_KERNEL_ADDRESS); + i <= VP_IDX1(VM_MAX_KERNEL_ADDRESS - 1); + i++) { + mappings_allocated++; + pa = pmap_steal_avail(sizeof(struct pmapvp2), Lx_TABLE_ALIGN, + &va); + vp2 = (struct pmapvp2 *)PHYS_TO_DMAP(pa); + vp1->vp[i] = va; + vp1->l1[i] = VP_Lx(pa); + + /* + * We must fully populate the l1 page tables since + * they get copied into the page tables for userland + * processes. But skip populating the l2 page tables + * above pmap_maxkvaddr. They will be populated by + * pmap_growkernel() when necessary. + */ + if (i > VP_IDX1(pmap_maxkvaddr - 1)) + continue; + + if (i == VP_IDX1(VM_MIN_KERNEL_ADDRESS)) { + lb_idx2 = VP_IDX2(VM_MIN_KERNEL_ADDRESS); + } else { + lb_idx2 = 0; + } + if (i == VP_IDX1(pmap_maxkvaddr - 1)) { + ub_idx2 = VP_IDX2(pmap_maxkvaddr - 1); + } else { + ub_idx2 = VP_IDX2_CNT - 1; + } + for (j = lb_idx2; j <= ub_idx2; j++) { + mappings_allocated++; + pa = pmap_steal_avail(sizeof(struct pmapvp3), + Lx_TABLE_ALIGN, &va); + vp3 = (struct pmapvp3 *)PHYS_TO_DMAP(pa); + vp2->vp[j] = va; + vp2->l2[j] = VP_Lx(pa); + } + } + /* allocate memory for pte_desc */ + for (i = VP_IDX1(VM_MIN_KERNEL_ADDRESS); + i <= VP_IDX1(pmap_maxkvaddr - 1); + i++) { + vp2 = (void *)PHYS_TO_DMAP((long)vp1->vp[i] + kvo); + + if (i == VP_IDX1(VM_MIN_KERNEL_ADDRESS)) { + lb_idx2 = VP_IDX2(VM_MIN_KERNEL_ADDRESS); + } else { + lb_idx2 = 0; + } + if (i == VP_IDX1(pmap_maxkvaddr - 1)) { + ub_idx2 = VP_IDX2(pmap_maxkvaddr - 1); + } else { + ub_idx2 = VP_IDX2_CNT - 1; + } + for (j = lb_idx2; j <= ub_idx2; j++) { + vp3 = (void *)PHYS_TO_DMAP((long)vp2->vp[j] + kvo); + + for (k = 0; k <= VP_IDX3_CNT - 1; k++) { + pted_allocated++; + pa = pmap_steal_avail(sizeof(struct pte_desc), + 4, &va); + pted = va; + vp3->vp[k] = pted; + } + } + } + + pmap_avail_fixup(); + + /* + * At this point we are still running on the bootstrap page + * tables however all memory for the final page tables is + * 'allocated' and should now be mapped. This means we are + * able to use the virtual addressing to populate the final + * mappings into the new mapping tables. + */ + vstart = pmap_map_stolen(kernelstart); + + /* + * Temporarily add the Direct Map Area into the kernel pmap + * such that we can continue to access stolen memory by + * physical address. + */ + pmap_bootstrap_dmap((vaddr_t)pmap_kernel()->pm_vp.l1, memstart, memend); + + /* Switch to the new page tables. */ + uint64_t satp = pmap_kernel()->pm_satp; + __asm volatile("csrwr %0, 0x19" :: "r" (satp) : "memory"); + sfence_vma(); + + curcpu()->ci_curpm = pmap_kernel(); + + vmmap = vstart; + vstart += PAGE_SIZE; + + return vstart; +} + +void +pmap_set_l2(struct pmap *pm, uint64_t va, struct pmapvp2 *l2_va, paddr_t l2_pa) +{ + pt_entry_t pg_entry; + struct pmapvp1 *vp1; + int idx1; + + if (l2_pa == 0) { + /* + * if this is called from pmap_vp_enter, this is a + * normally mapped page, call pmap_extract to get pa + */ + pmap_extract(pmap_kernel(), (vaddr_t)l2_va, &l2_pa); + } + + if (l2_pa & (Lx_TABLE_ALIGN-1)) + panic("misaligned L2 table"); + + pg_entry = VP_Lx(l2_pa); + + idx1 = VP_IDX1(va); + vp1 = pm->pm_vp.l1; + vp1->vp[idx1] = l2_va; + vp1->l1[idx1] = pg_entry; +} + +void +pmap_set_l3(struct pmap *pm, uint64_t va, struct pmapvp3 *l3_va, paddr_t l3_pa) +{ + pt_entry_t pg_entry; + struct pmapvp1 *vp1; + struct pmapvp2 *vp2; + int idx1, idx2; + + if (l3_pa == 0) { + /* + * if this is called from pmap_vp_enter, this is a + * normally mapped page, call pmap_extract to get pa + */ + pmap_extract(pmap_kernel(), (vaddr_t)l3_va, &l3_pa); + } + + if (l3_pa & (Lx_TABLE_ALIGN-1)) + panic("misaligned L2 table"); + + pg_entry = VP_Lx(l3_pa); + + idx1 = VP_IDX1(va); + idx2 = VP_IDX2(va); + vp1 = pm->pm_vp.l1; + vp2 = vp1->vp[idx1]; + vp2->vp[idx2] = l3_va; + vp2->l2[idx2] = pg_entry; +} + +/* + * activate a pmap entry + */ +void +pmap_activate(struct proc *p) +{ + pmap_t pm = p->p_vmspace->vm_map.pmap; + u_long sie; + + sie = intr_disable(); + if (p == curproc && pm != curcpu()->ci_curpm) + pmap_set_satp(p); + intr_restore(sie); +} + +/* + * deactivate a pmap entry + */ +void +pmap_deactivate(struct proc *p) +{ +} + +/* + * Get the physical page address for the given pmap/virtual address. + */ +int +pmap_extract(pmap_t pm, vaddr_t va, paddr_t *pap) +{ + struct pte_desc *pted; + paddr_t pa; + + pmap_lock(pm); + pted = pmap_vp_lookup(pm, va, NULL); + if (!pted || !PTED_VALID(pted)) { + pmap_unlock(pm); + return 0; + } + if (pap != NULL) { + pa = pted->pted_pte & PTE_RPGN; + if (pa >= pmap_uncached_start && pa <= pmap_uncached_end) + pa -= (pmap_uncached_start - pmap_cached_start); + *pap = pa | (va & PAGE_MASK); + } + pmap_unlock(pm); + + return 1; +} + +void +pmap_page_ro(pmap_t pm, vaddr_t va, vm_prot_t prot) +{ + struct pte_desc *pted; + pt_entry_t *pl3; + + /* Every VA needs a pted, even unmanaged ones. */ + pted = pmap_vp_lookup(pm, va, &pl3); + if (!pted || !PTED_VALID(pted)) { + return; + } + + pted->pted_va &= ~PROT_WRITE; + pted->pted_pte &= ~PROT_WRITE; + if ((prot & PROT_READ) == 0) { + pted->pted_va &= ~PROT_READ; + pted->pted_pte &= ~PROT_READ; + } + if ((prot & PROT_EXEC) == 0) { + pted->pted_va &= ~PROT_EXEC; + pted->pted_pte &= ~PROT_EXEC; + } + pmap_pte_update(pted, pl3); + tlb_flush_page(pm, pted->pted_va & ~PAGE_MASK); +} + +/* + * Lower the protection on the specified physical page. + * + * There are only two cases, either the protection is going to 0, + * or it is going to read-only. + */ +void +pmap_page_protect(struct vm_page *pg, vm_prot_t prot) +{ + struct pte_desc *pted; + struct pmap *pm; + + if (prot != PROT_NONE) { + mtx_enter(&pg->mdpage.pv_mtx); + LIST_FOREACH(pted, &(pg->mdpage.pv_list), pted_pv_list) { + pmap_page_ro(pted->pted_pmap, pted->pted_va, prot); + } + mtx_leave(&pg->mdpage.pv_mtx); + return; + } + + mtx_enter(&pg->mdpage.pv_mtx); + while ((pted = LIST_FIRST(&(pg->mdpage.pv_list))) != NULL) { + pmap_reference(pted->pted_pmap); + pm = pted->pted_pmap; + mtx_leave(&pg->mdpage.pv_mtx); + + pmap_lock(pm); + + /* + * We dropped the pvlist lock before grabbing the pmap + * lock to avoid lock ordering problems. This means + * we have to check the pvlist again since somebody + * else might have modified it. All we care about is + * that the pvlist entry matches the pmap we just + * locked. If it doesn't, unlock the pmap and try + * again. + */ + mtx_enter(&pg->mdpage.pv_mtx); + pted = LIST_FIRST(&(pg->mdpage.pv_list)); + if (pted == NULL || pted->pted_pmap != pm) { + mtx_leave(&pg->mdpage.pv_mtx); + pmap_unlock(pm); + pmap_destroy(pm); + mtx_enter(&pg->mdpage.pv_mtx); + continue; + } + mtx_leave(&pg->mdpage.pv_mtx); + + pmap_remove_pted(pm, pted); + pmap_unlock(pm); + pmap_destroy(pm); + + mtx_enter(&pg->mdpage.pv_mtx); + } + /* page is being reclaimed, sync icache next use */ + atomic_clearbits_int(&pg->pg_flags, PG_PMAP_EXE); + mtx_leave(&pg->mdpage.pv_mtx); +} + +void +pmap_protect(pmap_t pm, vaddr_t sva, vaddr_t eva, vm_prot_t prot) +{ + if (prot & (PROT_READ | PROT_EXEC)) { + pmap_lock(pm); + while (sva < eva) { + pmap_page_ro(pm, sva, prot); + sva += PAGE_SIZE; + } + pmap_unlock(pm); + return; + } + pmap_remove(pm, sva, eva); +} + +void +pmap_init(void) +{ + struct pmapvp1 *kvp1; + void *node; + + node = fdt_find_node("/"); + if (fdt_is_compatible(node, "starfive,jh7100")) { + pmap_cached_start = 0x0080000000ULL; + pmap_cached_end = 0x087fffffffULL; + pmap_uncached_start = 0x1000000000ULL; + pmap_uncached_end = 0x17ffffffffULL; + } + + /* Clear DMAP PTEs. */ + kvp1 = pmap_kernel()->pm_vp.l1; + memset(&kvp1->l1[L1_DMAP_BASE], 0, + L1_DMAP_ENTRIES * sizeof(pt_entry_t)); + memset(&kvp1->vp[L1_DMAP_BASE], 0, + L1_DMAP_ENTRIES * sizeof(struct pmapvp2 *)); + sfence_vma(); + + pool_init(&pmap_pmap_pool, sizeof(struct pmap), 0, IPL_NONE, 0, + "pmap", NULL); + pool_setlowat(&pmap_pmap_pool, 2); + pool_init(&pmap_pted_pool, sizeof(struct pte_desc), 0, IPL_VM, 0, + "pted", NULL); + pool_setlowat(&pmap_pted_pool, 20); + pool_init(&pmap_vp_pool, sizeof(struct pmapvp1), PAGE_SIZE, IPL_VM, 0, + "vp", &pmap_vp_allocator); + pool_setlowat(&pmap_vp_pool, 20); + + pmap_initialized = 1; +} + +void +pmap_proc_iflush(struct process *pr, vaddr_t va, vsize_t len) +{ + icache_flush(); +} + +void +pmap_pte_insert(struct pte_desc *pted) +{ + /* put entry into table */ + /* need to deal with ref/change here */ + pmap_t pm = pted->pted_pmap; + pt_entry_t *pl3; + + if (pmap_vp_lookup(pm, pted->pted_va, &pl3) == NULL) { + panic("%s: have a pted, but missing a vp" + " for %lx va pmap %p", __func__, pted->pted_va, pm); + } + + pmap_pte_update(pted, pl3); +} + +void +pmap_pte_update(struct pte_desc *pted, uint64_t *pl3) +{ + uint64_t pte, access_bits; + pmap_t pm = pted->pted_pmap; + uint64_t attr = 0; + + switch (pted->pted_va & PMAP_CACHE_BITS) { + case PMAP_CACHE_WB: + attr |= pmap_pma; + break; + case PMAP_CACHE_CI: + attr |= pmap_nc; + break; + case PMAP_CACHE_DEV: + attr |= pmap_io; + break; + default: + panic("%s: invalid cache mode", __func__); + } + + if (pm->pm_privileged) + access_bits = ap_bits_kern[pted->pted_pte & PROT_MASK]; + else + access_bits = ap_bits_user[pted->pted_pte & PROT_MASK]; + + pte = VP_Lx(pted->pted_pte) | attr | access_bits | PTE_V; + *pl3 = access_bits ? pte : 0; +} + +void +pmap_pte_remove(struct pte_desc *pted, int remove_pted) +{ + struct pmapvp1 *vp1; + struct pmapvp2 *vp2; + struct pmapvp3 *vp3; + pmap_t pm = pted->pted_pmap; + + vp1 = pm->pm_vp.l1; + if (vp1->vp[VP_IDX1(pted->pted_va)] == NULL) { + panic("have a pted, but missing the l2 for %lx va pmap %p", + pted->pted_va, pm); + } + vp2 = vp1->vp[VP_IDX1(pted->pted_va)]; + if (vp2 == NULL) { + panic("have a pted, but missing the l2 for %lx va pmap %p", + pted->pted_va, pm); + } + vp3 = vp2->vp[VP_IDX2(pted->pted_va)]; + if (vp3 == NULL) { + panic("have a pted, but missing the l2 for %lx va pmap %p", + pted->pted_va, pm); + } + vp3->l3[VP_IDX3(pted->pted_va)] = 0; + if (remove_pted) + vp3->vp[VP_IDX3(pted->pted_va)] = NULL; +} + +/* + * This function exists to do software referenced/modified emulation. + * It's purpose is to tell the caller that a fault was generated either + * for this emulation, or to tell the caller that it's a legit fault. + */ +int +pmap_fault_fixup(pmap_t pm, vaddr_t va, vm_prot_t ftype) +{ + struct pte_desc *pted; + struct vm_page *pg; + paddr_t pa; + pt_entry_t *pl3 = NULL; + int retcode = 0; + + pmap_lock(pm); + + /* Every VA needs a pted, even unmanaged ones. */ + pted = pmap_vp_lookup(pm, va, &pl3); + if (!pted || !PTED_VALID(pted)) + goto done; + + /* There has to be a PA for the VA, get it. */ + pa = (pted->pted_pte & PTE_RPGN); + + /* If it's unmanaged, it must not fault. */ + pg = PHYS_TO_VM_PAGE(pa); + if (pg == NULL) + goto done; + + /* + * Check the fault types to find out if we were doing + * any mod/ref emulation and fixup the PTE if we were. + */ + if ((ftype & PROT_WRITE) && /* fault caused by a write */ + !(pted->pted_pte & PROT_WRITE) && /* and write is disabled now */ + (pted->pted_va & PROT_WRITE)) { /* but is supposedly allowed */ + + /* + * Page modified emulation. A write always includes + * a reference. This means that we can enable read and + * exec as well, akin to the page reference emulation. + */ + atomic_setbits_int(&pg->pg_flags, PG_PMAP_MOD|PG_PMAP_REF); + atomic_clearbits_int(&pg->pg_flags, PG_PMAP_EXE); + + /* Thus, enable read, write and exec. */ + pted->pted_pte |= + (pted->pted_va & (PROT_READ|PROT_WRITE|PROT_EXEC)); + } else if ((ftype & PROT_EXEC) && /* fault caused by an exec */ + !(pted->pted_pte & PROT_EXEC) && /* and exec is disabled now */ + (pted->pted_va & PROT_EXEC)) { /* but is supposedly allowed */ + + /* + * Exec always includes a reference. Since we now know + * the page has been accessed, we can enable read as well + * if UVM allows it. + */ + atomic_setbits_int(&pg->pg_flags, PG_PMAP_REF); + + /* Thus, enable read and exec. */ + pted->pted_pte |= (pted->pted_va & (PROT_READ|PROT_EXEC)); + } else if ((ftype & PROT_READ) && /* fault caused by a read */ + !(pted->pted_pte & PROT_READ) && /* and read is disabled now */ + (pted->pted_va & PROT_READ)) { /* but is supposedly allowed */ + + /* + * Page referenced emulation. Since we now know the page + * has been accessed, we can enable exec as well if UVM + * allows it. + */ + atomic_setbits_int(&pg->pg_flags, PG_PMAP_REF); + + /* Thus, enable read and exec. */ + pted->pted_pte |= (pted->pted_va & (PROT_READ|PROT_EXEC)); + } else { + /* didn't catch it, so probably broken */ + goto done; + } + + /* + * If this is a page that can be executed, make sure to invalidate + * the instruction cache if the page has been modified or not used + * yet. + */ + if (pted->pted_va & PROT_EXEC) { + if ((pg->pg_flags & PG_PMAP_EXE) == 0) + icache_flush(); + atomic_setbits_int(&pg->pg_flags, PG_PMAP_EXE); + } + + /* We actually made a change, so flush it and sync. */ + pmap_pte_update(pted, pl3); + tlb_flush_page(pm, va & ~PAGE_MASK); + + retcode = 1; +done: + pmap_unlock(pm); + return retcode; +} + +void +pmap_postinit(void) +{ + vaddr_t minaddr, maxaddr; + u_long npteds, npages; + + /* + * Reserve enough virtual address space to grow the kernel + * page tables. We need a descriptor for each page as well as + * an extra page for level 1/2/3 page tables for management. + * To simplify the code, we always allocate full tables at + * level 3, so take that into account. + */ + npteds = (VM_MAX_KERNEL_ADDRESS - pmap_maxkvaddr + 1) / PAGE_SIZE; + npteds = roundup(npteds, VP_IDX3_CNT); + npages = howmany(npteds, PAGE_SIZE / (sizeof(struct pte_desc))); + npages += 2 * howmany(npteds, VP_IDX3_CNT); + npages += 2 * howmany(npteds, VP_IDX3_CNT * VP_IDX2_CNT); + npages += 2 * howmany(npteds, VP_IDX3_CNT * VP_IDX2_CNT * VP_IDX1_CNT); + + /* + * Use an interrupt safe map such that we don't recurse into + * uvm_map() to allocate map entries. + */ + minaddr = vm_map_min(kernel_map); + pmap_kvp_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr, + npages * PAGE_SIZE, VM_MAP_INTRSAFE, FALSE, NULL); +} + +void +pmap_init_percpu(void) +{ + pool_cache_init(&pmap_pted_pool); + pool_cache_init(&pmap_vp_pool); +} + +void +pmap_update(pmap_t pm) +{ +} + +int +pmap_is_referenced(struct vm_page *pg) +{ + return ((pg->pg_flags & PG_PMAP_REF) != 0); +} + +int +pmap_is_modified(struct vm_page *pg) +{ + return ((pg->pg_flags & PG_PMAP_MOD) != 0); +} + +int +pmap_clear_modify(struct vm_page *pg) +{ + struct pte_desc *pted; + + atomic_clearbits_int(&pg->pg_flags, PG_PMAP_MOD); + + mtx_enter(&pg->mdpage.pv_mtx); + LIST_FOREACH(pted, &(pg->mdpage.pv_list), pted_pv_list) { + pted->pted_pte &= ~PROT_WRITE; + pmap_pte_insert(pted); + tlb_flush_page(pted->pted_pmap, pted->pted_va & ~PAGE_MASK); + } + mtx_leave(&pg->mdpage.pv_mtx); + + return 0; +} + +/* + * When this turns off read permissions it also disables write permissions + * so that mod is correctly tracked after clear_ref; FAULT_READ; FAULT_WRITE; + */ +int +pmap_clear_reference(struct vm_page *pg) +{ + struct pte_desc *pted; + + atomic_clearbits_int(&pg->pg_flags, PG_PMAP_REF); + + mtx_enter(&pg->mdpage.pv_mtx); + LIST_FOREACH(pted, &(pg->mdpage.pv_list), pted_pv_list) { + pted->pted_pte &= ~PROT_MASK; + pmap_pte_insert(pted); + tlb_flush_page(pted->pted_pmap, pted->pted_va & ~PAGE_MASK); + } + mtx_leave(&pg->mdpage.pv_mtx); + + return 0; +} + +void +pmap_unwire(pmap_t pm, vaddr_t va) +{ + struct pte_desc *pted; + + pmap_lock(pm); + pted = pmap_vp_lookup(pm, va, NULL); + if (pted != NULL && PTED_WIRED(pted)) { + pm->pm_stats.wired_count--; + pted->pted_va &= ~PTED_VA_WIRED_M; + } + pmap_unlock(pm); +} + +void +pmap_remove_holes(struct vmspace *vm) +{ + /* NOOP */ +} + +void +pmap_virtual_space(vaddr_t *start, vaddr_t *end) +{ + *start = virtual_avail; + *end = VM_MAX_KERNEL_ADDRESS; + + /* Prevent further KVA stealing. */ + pmap_virtual_space_called = 1; +} + +void +pmap_setup_avail(uint64_t memstart, uint64_t memend, uint64_t kvo) +{ + /* This makes several assumptions + * 1) kernel will be located 'low' in memory + * 2) memory will not start at VM_MIN_KERNEL_ADDRESS + * 3) several MB of memory starting just after the kernel will + * be premapped at the kernel address in the bootstrap mappings + * 4) kvo will be the 64 bit number to add to the ram address to + * obtain the kernel virtual mapping of the ram. KVO == PA -> VA + * 5) it is generally assumed that these translations will occur with + * large granularity, at minimum the translation will be page + * aligned, if not 'section' or greater. + */ + + pmap_avail_kvo = kvo; + pmap_avail[0].start = memstart; + pmap_avail[0].size = memend - memstart; + pmap_cnt_avail = 1; + + pmap_avail_fixup(); +} + +void +pmap_avail_fixup(void) +{ + struct mem_region *mp; + vaddr_t align; + vaddr_t end; + + mp = pmap_avail; + while (mp->size !=0) { + align = round_page(mp->start); + if (mp->start != align) { + pmap_remove_avail(mp->start, align); + mp = pmap_avail; + continue; + } + end = mp->start+mp->size; + align = trunc_page(end); + if (end != align) { + pmap_remove_avail(align, end); + mp = pmap_avail; + continue; + } + mp++; + } +} + +/* remove a given region from avail memory */ +void +pmap_remove_avail(paddr_t base, paddr_t end) +{ + struct mem_region *mp; + int i; + long mpend; + + /* remove given region from available */ + for (mp = pmap_avail; mp->size; mp++) { + /* + * Check if this region holds all of the region + */ + mpend = mp->start + mp->size; + if (base > mpend) { + continue; + } + if (base <= mp->start) { + if (end <= mp->start) + break; /* region not present -??? */ + + if (end >= mpend) { + /* covers whole region */ + /* shorten */ + for (i = mp - pmap_avail; + i < pmap_cnt_avail; + i++) { + pmap_avail[i] = pmap_avail[i+1]; + } + pmap_cnt_avail--; + pmap_avail[pmap_cnt_avail].size = 0; + } else { + mp->start = end; + mp->size = mpend - end; + } + } else { + /* start after the beginning */ + if (end >= mpend) { + /* just truncate */ + mp->size = base - mp->start; + } else { + /* split */ + for (i = pmap_cnt_avail; + i > (mp - pmap_avail); + i--) { + pmap_avail[i] = pmap_avail[i - 1]; + } + pmap_cnt_avail++; + mp->size = base - mp->start; + mp++; + mp->start = end; + mp->size = mpend - end; + } + } + } + for (mp = pmap_allocated; mp->size != 0; mp++) { + if (base < mp->start) { + if (end == mp->start) { + mp->start = base; + mp->size += end - base; + break; + } + /* lengthen */ + for (i = pmap_cnt_allocated; i > (mp - pmap_allocated); + i--) { + pmap_allocated[i] = pmap_allocated[i - 1]; + } + pmap_cnt_allocated++; + mp->start = base; + mp->size = end - base; + return; + } + if (base == (mp->start + mp->size)) { + mp->size += end - base; + return; + } + } + if (mp->size == 0) { + mp->start = base; + mp->size = end - base; + pmap_cnt_allocated++; + } +} + +/* XXX - this zeros pages via their physical address */ +paddr_t +pmap_steal_avail(size_t size, int align, void **kva) +{ + struct mem_region *mp; + long start; + long remsize; + + for (mp = pmap_avail; mp->size; mp++) { + if (mp->size > size) { + start = (mp->start + (align -1)) & ~(align -1); + remsize = mp->size - (start - mp->start); + if (remsize >= 0) {//XXX buggy?? should be remsize >= size + pmap_remove_avail(start, start+size); + if (kva != NULL){ + *kva = (void *)(start - pmap_avail_kvo); + } + // XXX We clear the page based on its Direct + // Mapped address for now. Physical Addresses + // are not available because we have unmapped + // our identity mapped kernel. Should consider + // if we need to keep the identity mapping + // during pmap bootstrapping. + vaddr_t start_dmap = PHYS_TO_DMAP(start); + bzero((void*)(start_dmap), size); + return start; + } + } + } + panic("unable to allocate region with size %lx align %x", + size, align); +} + +vaddr_t +pmap_map_stolen(vaddr_t kernel_start) +{ + struct mem_region *mp; + paddr_t pa; + vaddr_t va; + uint64_t e; + + for (mp = pmap_allocated; mp->size; mp++) { + for (e = 0; e < mp->size; e += PAGE_SIZE) { + int prot = PROT_READ | PROT_WRITE; + + pa = mp->start + e; + va = pa - pmap_avail_kvo; + + if (va < VM_MIN_KERNEL_ADDRESS || + va >= VM_MAX_KERNEL_ADDRESS) + continue; + + if (va >= (vaddr_t)__text_start && + va < (vaddr_t)_etext) + prot = PROT_READ | PROT_EXEC; + else if (va >= (vaddr_t)__rodata_start && + va < (vaddr_t)_erodata) + prot = PROT_READ; + + pmap_kenter_cache(va, pa, prot, PMAP_CACHE_WB); + } + } + + return va + PAGE_SIZE; +} + +void +pmap_physload_avail(void) +{ + struct mem_region *mp; + uint64_t start, end; + + for (mp = pmap_avail; mp->size; mp++) { + if (mp->size < PAGE_SIZE) { + printf(" skipped - too small\n"); + continue; + } + start = mp->start; + if (start & PAGE_MASK) { + start = PAGE_SIZE + (start & PMAP_PA_MASK); + } + end = mp->start + mp->size; + if (end & PAGE_MASK) { + end = (end & PMAP_PA_MASK); + } + uvm_page_physload(atop(start), atop(end), + atop(start), atop(end), 0); + + } +} + +void +pmap_show_mapping(uint64_t va) +{ + struct pmapvp1 *vp1; + struct pmapvp2 *vp2; + struct pmapvp3 *vp3; + struct pte_desc *pted; + struct pmap *pm; + uint64_t satp; + + printf("showing mapping of %llx\n", va); + + if (va & 1ULL << 63) + pm = pmap_kernel(); + else + pm = curproc->p_vmspace->vm_map.pmap; + + vp1 = pm->pm_vp.l1; + + __asm volatile ("csrrd %0, 0x19" : "=r" (satp)); + + vp2 = vp1->vp[VP_IDX1(va)]; + printf(" vp2 = %p lp2 = %llx idx1 off %x\n", + vp2, vp1->l1[VP_IDX1(va)], VP_IDX1(va)*8); + if (vp2 == NULL) + return; + + vp3 = vp2->vp[VP_IDX2(va)]; + printf(" vp3 = %p lp3 = %llx idx2 off %x\n", + vp3, vp2->l2[VP_IDX2(va)], VP_IDX2(va)*8); + if (vp3 == NULL) + return; + + pted = vp3->vp[VP_IDX3(va)]; + printf(" pted = %p lp3 = %llx idx3 off %x\n", + pted, vp3->l3[VP_IDX3(va)], VP_IDX3(va)*8); +} + +void +pmap_set_satp(struct proc *p) +{ + struct cpu_info *ci = curcpu(); + pmap_t pm = p->p_vmspace->vm_map.pmap; + + ci->ci_curpm = pm; + load_satp(pm->pm_satp); + sfence_vma(); +} diff --git sys/arch/loongarch64/loongarch64/process_machdep.c sys/arch/loongarch64/loongarch64/process_machdep.c new file mode 100644 index 00000000000..8563bd0d235 --- /dev/null +++ sys/arch/loongarch64/loongarch64/process_machdep.c @@ -0,0 +1,132 @@ +/* $OpenBSD: process_machdep.c,v 1.6 2021/07/30 13:10:12 kettenis Exp $ */ + +/* + * Copyright (c) 2014 Patrick Wildt + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file may seem a bit stylized, but that so that it's easier to port. + * Functions to be implemented here are: + * + * process_read_regs(proc, regs) + * Get the current user-visible register set from the process + * and copy it into the regs structure (). + * The process is stopped at the time read_regs is called. + * + * process_write_regs(proc, regs) + * Update the current register set from the passed in regs + * structure. Take care to avoid clobbering special CPU + * registers or privileged bits in the PSL. + * The process is stopped at the time write_regs is called. + * + * process_sstep(proc, sstep) + * Arrange for the process to trap or not trap depending on sstep + * after executing a single instruction. + * + * process_set_pc(proc) + * Set the process's program counter. + */ + +#include + +#include +#include +#include +#include + +#include +#include + +int +process_read_regs(struct proc *p, struct reg *regs) +{ + struct trapframe *tf = p->p_addr->u_pcb.pcb_tf; + + memcpy(®s->r_t[0], &tf->tf_t[0], sizeof(regs->r_t)); + memcpy(®s->r_s[0], &tf->tf_s[0], sizeof(regs->r_s)); + memcpy(®s->r_a[0], &tf->tf_a[0], sizeof(regs->r_a)); + regs->r_ra = tf->tf_ra; + regs->r_sp = tf->tf_sp; + regs->r_gp = tf->tf_gp; + regs->r_tp = tf->tf_tp; + regs->r_sepc = tf->tf_sepc; + regs->r_sstatus = tf->tf_sstatus; + + return(0); +} + +int +process_read_fpregs(struct proc *p, struct fpreg *regs) +{ + struct trapframe *tf = p->p_addr->u_pcb.pcb_tf; + + if (p->p_addr->u_pcb.pcb_flags & PCB_FPU) + fpu_save(p, tf); + + if (p->p_addr->u_pcb.pcb_flags & PCB_FPU) + memcpy(regs, &p->p_addr->u_pcb.pcb_fpstate, sizeof(*regs)); + else + memset(regs, 0, sizeof(*regs)); + + return(0); +} + +#ifdef PTRACE + +int +process_write_regs(struct proc *p, struct reg *regs) +{ + struct trapframe *tf = p->p_addr->u_pcb.pcb_tf; + + memcpy(&tf->tf_t[0], ®s->r_t[0], sizeof(tf->tf_t)); + memcpy(&tf->tf_s[0], ®s->r_s[0], sizeof(tf->tf_s)); + memcpy(&tf->tf_a[0], ®s->r_a[0], sizeof(tf->tf_a)); + tf->tf_ra = regs->r_ra; + tf->tf_sp = regs->r_sp; + tf->tf_gp = regs->r_gp; + tf->tf_tp = regs->r_tp; + tf->tf_sepc = regs->r_sepc; + + return(0); +} + +int +process_write_fpregs(struct proc *p, struct fpreg *regs) +{ + + memcpy(&p->p_addr->u_pcb.pcb_fpstate, regs, + sizeof(p->p_addr->u_pcb.pcb_fpstate)); + p->p_addr->u_pcb.pcb_flags |= PCB_FPU; + + /* drop FPU state */ + + return(0); +} + +int +process_sstep(struct proc *p, int sstep) +{ + return (EOPNOTSUPP); +} + +int +process_set_pc(struct proc *p, caddr_t addr) +{ + struct trapframe *tf = p->p_addr->u_pcb.pcb_tf; + tf->tf_sepc = (uint64_t)addr; + return (0); +} + +#endif /* PTRACE */ diff --git sys/arch/loongarch64/loongarch64/sbi.c sys/arch/loongarch64/loongarch64/sbi.c new file mode 100644 index 00000000000..b7c86900695 --- /dev/null +++ sys/arch/loongarch64/loongarch64/sbi.c @@ -0,0 +1,245 @@ +/* $OpenBSD: sbi.c,v 1.8 2024/03/29 22:11:34 kettenis Exp $ */ + +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2019 Mitchell Horne + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include + +#include + +extern void (*cpuresetfn)(void); +extern void (*powerdownfn)(void); + +/* SBI Implementation-Specific Definitions */ +#define OPENSBI_VERSION_MAJOR_OFFSET 16 +#define OPENSBI_VERSION_MINOR_MASK 0xFFFF + +u_long sbi_spec_version; +u_long sbi_impl_id; +u_long sbi_impl_version; + +static struct sbi_ret +sbi_get_spec_version(void) +{ + return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_SPEC_VERSION)); +} + +static struct sbi_ret +sbi_get_impl_id(void) +{ + return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_IMPL_ID)); +} + +static struct sbi_ret +sbi_get_impl_version(void) +{ + return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_IMPL_VERSION)); +} + +void +sbi_print_version(void) +{ + u_int major; + u_int minor; + + /* For legacy SBI implementations. */ + if (sbi_spec_version == 0) { + printf("SBI: Unknown (Legacy) Implementation\n"); + printf("SBI Specification Version: 0.1\n"); + return; + } + + switch (sbi_impl_id) { + case (SBI_IMPL_ID_BBL): + printf("SBI: Berkely Boot Loader %lu", sbi_impl_version); + break; + case (SBI_IMPL_ID_OPENSBI): + major = sbi_impl_version >> OPENSBI_VERSION_MAJOR_OFFSET; + minor = sbi_impl_version & OPENSBI_VERSION_MINOR_MASK; + printf("SBI: OpenSBI v%u.%u", major, minor); + break; + default: + printf("SBI: Unrecognized Implementation: %lu", sbi_impl_id); + break; + } + + major = (sbi_spec_version & SBI_SPEC_VERS_MAJOR_MASK) >> + SBI_SPEC_VERS_MAJOR_OFFSET; + minor = (sbi_spec_version & SBI_SPEC_VERS_MINOR_MASK); + printf(", SBI Specification Version %u.%u\n", major, minor); +} + +#ifdef MULTIPROCESSOR + +int +sbi_hsm_hart_start(u_long hart, u_long start_addr, u_long priv) +{ + struct sbi_ret ret; + + ret = SBI_CALL3(SBI_EXT_ID_HSM, SBI_HSM_HART_START, hart, start_addr, + priv); + return (ret.error != 0 ? (int)ret.error : 0); +} + +void +sbi_hsm_hart_stop(void) +{ + (void)SBI_CALL0(SBI_EXT_ID_HSM, SBI_HSM_HART_STOP); +} + +int +sbi_hsm_hart_status(u_long hart) +{ + struct sbi_ret ret; + + ret = SBI_CALL1(SBI_EXT_ID_HSM, SBI_HSM_HART_STATUS, hart); + + return (ret.error != 0 ? (int)ret.error : (int)ret.value); +} + +#endif + +void +sbi_reset(void) +{ + SBI_CALL2(SBI_EXT_ID_SRST, SBI_SRST_RESET, + SBI_SRST_RESET_WARM_REBOOT, 0); +} + +void +sbi_powerdown(void) +{ + SBI_CALL2(SBI_EXT_ID_SRST, SBI_SRST_RESET, + SBI_SRST_RESET_SHUTDOWN, 0); +} + +void +sbi_init(void) +{ + struct sbi_ret sret; + + /* + * Get the spec version. For legacy SBI implementations this will + * return an error, otherwise it is guaranteed to succeed. + */ + sret = sbi_get_spec_version(); + if (sret.error != 0) { + /* We are running a legacy SBI implementation. */ + sbi_spec_version = 0; + return; + } + + /* Set the SBI implementation info. */ + sbi_spec_version = sret.value; + sbi_impl_id = sbi_get_impl_id().value; + sbi_impl_version = sbi_get_impl_version().value; + + /* + * Probe for legacy extensions. Currently we rely on all of them + * to be implemented, but this is not guaranteed by the spec. + */ + KASSERTMSG(sbi_probe_extension(SBI_SET_TIMER) != 0, + "SBI doesn't implement sbi_set_timer()"); + KASSERTMSG(sbi_probe_extension(SBI_CONSOLE_PUTCHAR) != 0, + "SBI doesn't implement sbi_console_putchar()"); + KASSERTMSG(sbi_probe_extension(SBI_CONSOLE_GETCHAR) != 0, + "SBI doesn't implement sbi_console_getchar()"); + KASSERTMSG(sbi_probe_extension(SBI_CLEAR_IPI) != 0, + "SBI doesn't implement sbi_clear_ipi()"); + KASSERTMSG(sbi_probe_extension(SBI_SEND_IPI) != 0, + "SBI doesn't implement sbi_send_ipi()"); + KASSERTMSG(sbi_probe_extension(SBI_REMOTE_FENCE_I) != 0, + "SBI doesn't implement sbi_remote_fence_i()"); + KASSERTMSG(sbi_probe_extension(SBI_REMOTE_SFENCE_VMA) != 0, + "SBI doesn't implement sbi_remote_sfence_vma()"); + KASSERTMSG(sbi_probe_extension(SBI_REMOTE_SFENCE_VMA_ASID) != 0, + "SBI doesn't implement sbi_remote_sfence_vma_asid()"); + KASSERTMSG(sbi_probe_extension(SBI_SHUTDOWN) != 0, + "SBI doesn't implement sbi_shutdown()"); + + /* + * Implement reboot and power down if the System Reset + * Extension is implemented. + */ + if (sbi_probe_extension(SBI_EXT_ID_SRST) != 0) { + cpuresetfn = sbi_reset; + powerdownfn = sbi_powerdown; + } +} + +/* + * Early console implementation based on the Console Putchar and + * Console Getchar legacy extensions. These extensions are deprecated + * but extremely useful for bringing up new boards. + */ + +void +sbi_cnprobe(struct consdev *cd) +{ +} + +void +sbi_cninit(struct consdev *cd) +{ +} + +int +sbi_cngetc(dev_t dev) +{ + int c; + + for (;;) { + c = sbi_console_getchar(); + if (c != -1) + return c; + } +} + +void +sbi_cnputc(dev_t dev, int c) +{ + sbi_console_putchar(c); +} + +void +sbi_cnpollc(dev_t dev, int on) +{ +} + +struct consdev sbi_consdev = { + .cn_probe = sbi_cnprobe, + .cn_init = sbi_cninit, + .cn_getc = sbi_cngetc, + .cn_putc = sbi_cnputc, + .cn_pollc = sbi_cnpollc, +}; + +struct consdev *cn_tab = &sbi_consdev; diff --git sys/arch/loongarch64/loongarch64/sig_machdep.c sys/arch/loongarch64/loongarch64/sig_machdep.c new file mode 100644 index 00000000000..c9c3cd0b39a --- /dev/null +++ sys/arch/loongarch64/loongarch64/sig_machdep.c @@ -0,0 +1,254 @@ +/* $OpenBSD: sig_machdep.c,v 1.11 2026/05/09 17:38:50 jsing Exp $ */ + +/* + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * William Jolitz and Don Ahn. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +/* + * Copyright (c) 2001 Opsycon AB (www.opsycon.se) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include + +#include /* XXX only needed by syscallargs.h */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +static __inline struct trapframe * +process_frame(struct proc *p) +{ + return p->p_addr->u_pcb.pcb_tf; +} + +/* + * Send an interrupt to process. + * + * Stack is set up to allow sigcode to call routine, followed by + * syscall to sigreturn routine below. After sigreturn resets the + * signal mask, the stack, and the frame pointer, it returns to the + * user specified pc. + */ +int +sendsig(sig_t catcher, int sig, sigset_t mask, const siginfo_t *ksip, + int info, int onstack) +{ + struct proc *p = curproc; + struct trapframe *tf; + struct sigframe *fp, frame; + struct fpreg *fpreg; + siginfo_t *sip = NULL; + int i; + + tf = process_frame(p); + + /* Allocate space for the signal handler context. */ + if ((p->p_sigstk.ss_flags & SS_DISABLE) == 0 && + !sigonstack(tf->tf_sp) && onstack) + fp = (struct sigframe *) + trunc_page((vaddr_t)p->p_sigstk.ss_sp + p->p_sigstk.ss_size); + else + fp = (struct sigframe *)tf->tf_sp; + + /* make room on the stack */ + fp--; + + /* make the stack aligned */ + fp = (struct sigframe *)STACKALIGN(fp); + + /* Save FPU and vector state to PCB if necessary. */ + if (p->p_addr->u_pcb.pcb_flags & PCB_FPU) + fpu_save(p, tf); + if (p->p_addr->u_pcb.pcb_flags & PCB_VECTOR) + vector_save(p, tf); + + /* Build stack frame for signal trampoline. */ + bzero(&frame, sizeof(frame)); + frame.sf_signum = sig; + + /* Save register context. */ + for (i=0; i < 7; i++) + frame.sf_sc.sc_t[i] = tf->tf_t[i]; + for (i=0; i < 12; i++) + frame.sf_sc.sc_s[i] = tf->tf_s[i]; + for (i=0; i < 8; i++) + frame.sf_sc.sc_a[i] = tf->tf_a[i]; + frame.sf_sc.sc_ra = tf->tf_ra; + frame.sf_sc.sc_sp = tf->tf_sp; + frame.sf_sc.sc_tp = tf->tf_tp; + frame.sf_sc.sc_sepc = tf->tf_sepc; + + /* Save signal mask. */ + frame.sf_sc.sc_mask = mask; + + /* Copy the saved FPU state into the frame if necessary. */ + if (p->p_addr->u_pcb.pcb_flags & PCB_FPU) { + fpreg = &p->p_addr->u_pcb.pcb_fpstate; + for (i = 0; i < 32; i++) + frame.sf_sc.sc_f[i] = fpreg->fp_f[i]; + frame.sf_sc.sc_fcsr = fpreg->fp_fcsr; + } + + if (info) { + sip = &fp->sf_si; + frame.sf_si = *ksip; + } + + frame.sf_sc.sc_cookie = (long)&fp->sf_sc ^ p->p_p->ps_sigcookie; + if (copyout(&frame, fp, sizeof(frame)) != 0) { + /* + * Process has trashed its stack; alert caller which + * will give it an illegal instruction to halt it in + * its tracks. + */ + return 1; + } + + + /* + * Build context to run handler in. We invoke the handler + * directly, only returning via the trampoline. + */ + tf->tf_a[0] = sig; + tf->tf_a[1] = (register_t)sip; + tf->tf_a[2] = (register_t)&fp->sf_sc; + tf->tf_ra = p->p_p->ps_sigcode; + tf->tf_sp = (register_t)fp; + + tf->tf_sepc = (register_t)catcher; + + return 0; +} + +/* + * System call to cleanup state after a signal + * has been taken. Reset signal mask and + * stack state from context left by sendsig (above). + * Return to previous pc and psl as specified by + * context left by sendsig. Check carefully to + * make sure that the user has not modified the + * psr to gain improper privileges or to cause + * a machine fault. + */ + +int +sys_sigreturn(struct proc *p, void *v, register_t *retval) +{ + + struct sys_sigreturn_args /* { + syscallarg(struct sigcontext *) sigcntxp; + } */ *uap = v; + struct sigcontext ksc, *scp = SCARG(uap, sigcntxp); + struct trapframe *tf; + struct fpreg *fpreg; + int i; + + if (PROC_PC(p) != p->p_p->ps_sigcoderet) { + sigexit(p, SIGILL); + return (EPERM); + } + + if (copyin(scp, &ksc, sizeof(*scp)) != 0) + return (EFAULT); + + if (ksc.sc_cookie != ((long)scp ^ p->p_p->ps_sigcookie)) { + sigexit(p, SIGILL); + return (EFAULT); + } + + /* Prevent reuse of the sigcontext cookie */ + ksc.sc_cookie = 0; + (void)copyout(&ksc.sc_cookie, (caddr_t)scp + + offsetof(struct sigcontext, sc_cookie), sizeof (ksc.sc_cookie)); + + /* Restore register context. */ + tf = process_frame(p); + for (i=0; i < 7; i++) + tf->tf_t[i] = ksc.sc_t[i]; + for (i=0; i < 12; i++) + tf->tf_s[i] = ksc.sc_s[i]; + for (i=0; i < 8; i++) + tf->tf_a[i] = ksc.sc_a[i]; + tf->tf_ra = ksc.sc_ra; + tf->tf_sp = ksc.sc_sp; + tf->tf_tp = ksc.sc_tp; + tf->tf_sepc = ksc.sc_sepc; + + /* Write saved FPU state back to PCB if necessary. */ + if (p->p_addr->u_pcb.pcb_flags & PCB_FPU) { + fpreg = &p->p_addr->u_pcb.pcb_fpstate; + for (i = 0; i < 32; i++) + fpreg->fp_f[i] = ksc.sc_f[i]; + fpreg->fp_fcsr = ksc.sc_fcsr; + + /* drop FPU state */ + } + + /* Restore signal mask. */ + p->p_sigmask = ksc.sc_mask & ~sigcantmask; + + return (EJUSTRETURN); +} diff --git sys/arch/loongarch64/loongarch64/support.S sys/arch/loongarch64/loongarch64/support.S new file mode 100644 index 00000000000..7d7b780b5ce --- /dev/null +++ sys/arch/loongarch64/loongarch64/support.S @@ -0,0 +1,83 @@ +/* $OpenBSD: support.S,v 1.3 2022/03/22 06:51:12 miod Exp $ */ + +/*- + * Copyright (c) 2015-2020 Ruslan Bukin + * All rights reserved. + * + * Portions of this software were developed by SRI International and the + * University of Cambridge Computer Laboratory under DARPA/AFRL contract + * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. + * + * Portions of this software were developed by the University of Cambridge + * Computer Laboratory as part of the CTSRD Project, with support from the + * UK Higher Education Innovation Fund (HEIF). + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "assym.h" +#include +#include + +ENTRY(setjmp) + /* Store the stack pointer */ + st.d $sp, $a0, 0 + addi.d $a0, $a0, 8 + + /* Store the general purpose registers and ra */ + st.d $s0, $a0, (0 * 8) + st.d $s1, $a0, (1 * 8) + st.d $s2, $a0, (2 * 8) + st.d $s3, $a0, (3 * 8) + st.d $s4, $a0, (4 * 8) + st.d $s5, $a0, (5 * 8) + st.d $s6, $a0, (6 * 8) + st.d $s7, $a0, (7 * 8) + st.d $s8, $a0, (8 * 8) + st.d $ra, $a0, (12 * 8) + + /* Return zero */ + li.d $a0, 0 + jr $ra +END(setjmp) + +ENTRY(longjmp) + /* Restore the stack pointer */ + ld.d $sp, $a0, 0 + addi.d $a0, $a0, 8 + + /* Restore the general purpose registers and ra */ + ld.d $s0, $a0, (0 * 8) + ld.d $s1, $a0, (1 * 8) + ld.d $s2, $a0, (2 * 8) + ld.d $s3, $a0, (3 * 8) + ld.d $s4, $a0, (4 * 8) + ld.d $s5, $a0, (5 * 8) + ld.d $s6, $a0, (6 * 8) + ld.d $s7, $a0, (7 * 8) + ld.d $s8, $a0, (8 * 8) + ld.d $ra, $a0, (12 * 8) + + /* Return nonzero */ + li.d $a0, 1 + jr $ra +END(longjmp) diff --git sys/arch/loongarch64/loongarch64/syscall.c sys/arch/loongarch64/loongarch64/syscall.c new file mode 100644 index 00000000000..de552ed34ac --- /dev/null +++ sys/arch/loongarch64/loongarch64/syscall.c @@ -0,0 +1,91 @@ +/* $OpenBSD: syscall.c,v 1.20 2026/03/08 17:07:31 deraadt Exp $ */ + +/* + * Copyright (c) 2020 Brian Bamsch + * Copyright (c) 2015 Dale Rahn + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include +#include +#include +#include +#include + +#include + +#include + +static __inline struct trapframe * +process_frame(struct proc *p) +{ + return p->p_addr->u_pcb.pcb_tf; +} + +void +svc_handler(trapframe_t *frame) +{ + struct proc *p = curproc; + const struct sysent *callp = sysent; + int code, error = ENOSYS; + register_t *args, rval[2]; + + atomic_inc_int(&uvmexp.syscalls); + + code = frame->tf_t[0]; + if (code <= 0 || code >= SYS_MAXSYSCALL) + goto bad; + + callp += code; + + args = &frame->tf_a[0]; + + rval[0] = 0; + rval[1] = 0; + + error = mi_syscall(p, code, callp, args, rval); + + switch (error) { + case 0: + frame->tf_a[0] = rval[0]; + frame->tf_t[0] = 0; /* syscall succeeded */ + break; + case ERESTART: + frame->tf_sepc -= 4; /* prev instruction */ + break; + case EJUSTRETURN: + break; + default: + bad: + frame->tf_a[0] = error; + frame->tf_t[0] = 1; /* syscall error */ + break; + } + + mi_syscall_return(p, code, error, rval); +} + +void +child_return(void *arg) +{ + struct proc *p = arg; + struct trapframe *frame = process_frame(p); + + frame->tf_a[0] = 0; + frame->tf_t[0] = 0; /* no error */ + + KERNEL_UNLOCK(); + + mi_child_return(p); +} diff --git sys/arch/loongarch64/loongarch64/trap.c sys/arch/loongarch64/loongarch64/trap.c new file mode 100644 index 00000000000..913b6c42469 --- /dev/null +++ sys/arch/loongarch64/loongarch64/trap.c @@ -0,0 +1,271 @@ +/* $OpenBSD: trap.c,v 1.23 2026/05/09 17:38:50 jsing Exp $ */ + +/* + * Copyright (c) 2020 Shivam Waghela + * Copyright (c) 2020 Brian Bamsch + * Copyright (c) 2020 Mengshi Li + * Copyright (c) 2015 Dale Rahn + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* Called from exception.S */ +void do_trap_supervisor(struct trapframe *); +void do_trap_user(struct trapframe *); + +static void udata_abort(struct trapframe *); +static void kdata_abort(struct trapframe *); + +static void +dump_regs(struct trapframe *frame) +{ + int n; + int i; + + n = (sizeof(frame->tf_t) / sizeof(frame->tf_t[0])); + for (i = 0; i < n; i++) + printf("t[%d] == 0x%016lx\n", i, frame->tf_t[i]); + + n = (sizeof(frame->tf_s) / sizeof(frame->tf_s[0])); + for (i = 0; i < n; i++) + printf("s[%d] == 0x%016lx\n", i, frame->tf_s[i]); + + n = (sizeof(frame->tf_a) / sizeof(frame->tf_a[0])); + for (i = 0; i < n; i++) + printf("a[%d] == 0x%016lx\n", i, frame->tf_a[i]); + + printf("sepc == 0x%016lx\n", frame->tf_sepc); + printf("sstatus == 0x%016lx\n", frame->tf_sstatus); + printf("stval == 0x%016lx\n", frame->tf_stval); + printf("scause == 0x%016lx\n", frame->tf_scause); +} + +void +do_trap_supervisor(struct trapframe *frame) +{ + uint64_t exception; + + /* Ensure we came from supervisor mode, interrupts disabled */ + + + if (frame->tf_scause & EXCP_INT) { + /* Interrupt */ + loongarch_cpu_intr(frame); + return; + } + + intr_enable(); + atomic_inc_int(&uvmexp.traps); + + exception = (frame->tf_scause & EXCP_MASK); + switch (exception) { + case EXCP_PIL: + case EXCP_PIS: + case EXCP_PIF: + kdata_abort(frame); + break; + case EXCP_BRK: +#ifdef DDB + db_trapper(frame->tf_sepc,0/*XXX*/, frame, exception); +#else + dump_regs(frame); + panic("No debugger in kernel."); +#endif + break; + case EXCP_INE: + dump_regs(frame); + panic("Illegal instruction at 0x%016lx", frame->tf_sepc); + break; + default: + dump_regs(frame); + panic("Unknown kernel exception %llx trap value pc 0x%lx stval %lx", + exception, frame->tf_sepc, frame->tf_stval); + } +} + +void +do_trap_user(struct trapframe *frame) +{ + struct proc *p = curcpu()->ci_curproc; + uint64_t exception; + union sigval sv; + + p->p_addr->u_pcb.pcb_tf = frame; + + /* Ensure we came from usermode, interrupts disabled */ + + + if (frame->tf_scause & EXCP_INT) { + /* Interrupt */ + loongarch_cpu_intr(frame); + return; + } + + intr_enable(); + atomic_inc_int(&uvmexp.traps); + refreshcreds(p); + + exception = (frame->tf_scause & EXCP_MASK); + switch (exception) { + case EXCP_PIL: + case EXCP_PIS: + case EXCP_PIF: + udata_abort(frame); + break; + case EXCP_SYS: + frame->tf_sepc += 4; /* Next instruction */ + svc_handler(frame); + break; + case EXCP_INE: + if ((loongarch_hwcap ) != 0 && + vector_instruction(frame->tf_stval)) { + vector_load(p); + break; + } + sv.sival_ptr = (void *)frame->tf_stval; + trapsignal(p, SIGILL, 0, ILL_ILLTRP, sv); + break; + case EXCP_BRK: + sv.sival_ptr = (void *)frame->tf_stval; + trapsignal(p, SIGTRAP, 0, TRAP_BRKPT, sv); + break; + default: + dump_regs(frame); + panic("Unknown userland exception %llx, trap value %lx", + exception, frame->tf_stval); + } + + userret(p); +} + +static inline vm_prot_t +accesstype(struct trapframe *frame) +{ + vm_prot_t access_type; + + if (frame->tf_scause == EXCP_PIS || + frame->tf_scause == EXCP_PIS) { + access_type = PROT_WRITE; + } else if (frame->tf_scause == EXCP_PIF || + frame->tf_scause == EXCP_PIF) { + access_type = PROT_EXEC; + } else { + access_type = PROT_READ; + } + return access_type; +} + +static void +udata_abort(struct trapframe *frame) +{ + struct vm_map *map; + uint64_t stval = frame->tf_stval; + union sigval sv; + vm_prot_t access_type = accesstype(frame); + vaddr_t va; + struct proc *p; + int error, sig, code; + + p = curcpu()->ci_curproc; + + va = trunc_page(stval); + + map = &p->p_vmspace->vm_map; + + if (!uvm_map_inentry(p, &p->p_spinentry, PROC_STACK(p), + "[%s]%d/%d sp=%lx inside %lx-%lx: not MAP_STACK\n", + uvm_map_inentry_sp, p->p_vmspace->vm_map.sserial)) + return; + + /* Handle referenced/modified emulation */ + if (pmap_fault_fixup(map->pmap, va, access_type)) + return; + + error = uvm_fault(map, va, 0, access_type); + + if (error == 0) { + uvm_grow(p, va); + return; + } + + if (error == ENOMEM) { + sig = SIGKILL; + code = 0; + } else if (error == EIO) { + sig = SIGBUS; + code = BUS_OBJERR; + } else if (error == EACCES) { + sig = SIGSEGV; + code = SEGV_ACCERR; + } else { + sig = SIGSEGV; + code = SEGV_MAPERR; + } + sv.sival_ptr = (void *)stval; + trapsignal(p, sig, 0, code, sv); +} + +static void +kdata_abort(struct trapframe *frame) +{ + struct vm_map *map; + uint64_t stval = frame->tf_stval; + struct pcb *pcb; + vm_prot_t access_type = accesstype(frame); + vaddr_t va; + struct proc *p; + int error = 0; + + pcb = curcpu()->ci_curpcb; + p = curcpu()->ci_curproc; + + va = trunc_page(stval); + + if (stval >= VM_MAXUSER_ADDRESS) + map = kernel_map; + else { + map = &p->p_vmspace->vm_map; + } + + /* Handle referenced/modified emulation */ + if (!pmap_fault_fixup(map->pmap, va, access_type)) { + error = uvm_fault(map, va, 0, access_type); + + if (error == 0 && map != kernel_map) + uvm_grow(p, va); + } + + if (error != 0) { + if (curcpu()->ci_idepth == 0 && + pcb->pcb_onfault != 0) { + frame->tf_a[0] = error; + frame->tf_sepc = (register_t)pcb->pcb_onfault; + return; + } + dump_regs(frame); + panic("Fatal page fault at %#lx: %#08lx", frame->tf_sepc, + (vaddr_t)stval); + } +} diff --git sys/arch/loongarch64/loongarch64/vector.c sys/arch/loongarch64/loongarch64/vector.c new file mode 100644 index 00000000000..2f7d9e6282c --- /dev/null +++ sys/arch/loongarch64/loongarch64/vector.c @@ -0,0 +1,91 @@ +/* $OpenBSD: vector.c,v 1.1 2026/05/09 17:38:50 jsing Exp $ */ + +/* + * Copyright (c) 2026 Joel Sing + * Copyright (c) 2020 Dale Rahn + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#define CSR_VSTART 0x008 +#define CSR_VXSAT 0x009 +#define CSR_VXRM 0x00a +#define CSR_VCSR 0x00f +#define CSR_VL 0xc20 +#define CSR_VTYPE 0xc21 +#define CSR_VLENB 0xc22 + +int +vector_instruction(register_t stval) +{ + register_t opcode, funct3, csr; + + /* + * Indicate whether the instruction belongs to a vector extension, + * or is a CSR instruction that references a vector CSR register. + */ + opcode = stval & 0x7f; + funct3 = (stval >> 12) & 0x7; + + /* LOAD-FP for V. */ + if (opcode == 0b0000111 && (funct3 == 0b000 || funct3 == 0b101 || + funct3 == 0b110 || funct3 == 0b111)) + return 1; + + /* STORE-FP for V. */ + if (opcode == 0b0100111 && (funct3 == 0b000 || funct3 == 0b101 || + funct3 == 0b110 || funct3 == 0b111)) + return 1; + + /* OP-V. */ + if (opcode == 0b1010111) + return 1; + + /* CSR instruction with vector CSR register. */ + if (opcode == 0b1110011 && (funct3 == 0b001 || funct3 == 0b010 || + funct3 == 0b011 || funct3 == 0b101 || funct3 == 0b110 || + funct3 == 0b111)) { + csr = (stval >> 20) & 0xfff; + return csr == CSR_VSTART || csr == CSR_VXSAT || + csr == CSR_VXRM || csr == CSR_VCSR || csr == CSR_VL || + csr == CSR_VTYPE || csr == CSR_VLENB; + } + + return 0; +} + +void +vector_disable(void) +{ +} + +void +vector_enable_clean(void) +{ +} + +void +vector_save(struct proc *p, struct trapframe *tf) +{ +} + +void +vector_load(struct proc *p) +{ +} diff --git sys/arch/loongarch64/loongarch64/vm_machdep.c sys/arch/loongarch64/loongarch64/vm_machdep.c new file mode 100644 index 00000000000..2e3ab229b1a --- /dev/null +++ sys/arch/loongarch64/loongarch64/vm_machdep.c @@ -0,0 +1,194 @@ +/* $OpenBSD: vm_machdep.c,v 1.13 2026/05/09 17:38:50 jsing Exp $ */ + +/*- + * Copyright (c) 1995 Charles M. Hannum. All rights reserved. + * Copyright (c) 1982, 1986 The Regents of the University of California. + * Copyright (c) 1989, 1990 William Jolitz + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * the Systems Programming Group of the University of Utah Computer + * Science Department, and William Jolitz. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)vm_machdep.c 7.3 (Berkeley) 5/13/91 + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include + +/* + * Finish a fork operation, with process p2 nearly set up. + * Copy and update the kernel stack and pcb, making the child + * ready to run, and marking it so that it can return differently + * than the parent. Returns 1 in the child process, 0 in the parent. + */ +void +cpu_fork(struct proc *p1, struct proc *p2, void *stack, void *tcb, + void (*func)(void *), void *arg) +{ + struct pcb *pcb = &p2->p_addr->u_pcb; + struct pcb *pcb1 = &p1->p_addr->u_pcb; + struct trapframe *tf; + struct switchframe *sf; + + /* Ensure proper stack alignment. */ + CTASSERT((sizeof(struct trapframe) & STACKALIGNBYTES) == 0); + CTASSERT((sizeof(struct switchframe) & STACKALIGNBYTES) == 0); + + /* Save FPU and vector state to PCB if necessary. */ + if (pcb1->pcb_flags & PCB_FPU) + fpu_save(p1, pcb1->pcb_tf); + if (pcb1->pcb_flags & PCB_VECTOR) + vector_save(p1, pcb1->pcb_tf); + + /* Copy the pcb. */ + *pcb = *pcb1; + + /* If vector state exists, we need to copy it. */ + if (pcb1->pcb_flags & PCB_VECTOR) { + pcb->pcb_vstate = malloc(sizeof(struct vreg) + 32 * loongarch_vlenb, + M_SUBPROC, M_WAITOK); + memcpy(pcb->pcb_vstate, pcb1->pcb_vstate, + sizeof(struct vreg) + 32 * loongarch_vlenb); + } + + pmap_activate(p2); + + tf = (struct trapframe *)((u_long)p2->p_addr + + USPACE + - sizeof(struct trapframe) + - sizeof(register_t) /* for holding curcpu */ + - 0x10); + + tf = (struct trapframe *)STACKALIGN(tf); + pcb->pcb_tf = tf; + *tf = *p1->p_addr->u_pcb.pcb_tf; + + if (stack != NULL) + tf->tf_sp = STACKALIGN(stack); + if (tcb != NULL) + tf->tf_tp = (register_t)tcb; + + /* Arguments for child */ + tf->tf_a[0] = 0; + tf->tf_a[1] = 0; + tf->tf_sstatus |= (1 << 2); /* Enable interrupts. */ + tf->tf_sstatus &= ~(1 << 2); /* Enter user mode. */ + + sf = (struct switchframe *)tf - 1; + sf->sf_s[0] = 0; /* Terminate chain of call frames. */ + sf->sf_s[1] = (uint64_t)func; + sf->sf_s[2] = (uint64_t)arg; + sf->sf_ra = (u_int64_t)&proc_trampoline; + pcb->pcb_sp = (uint64_t)sf; +} + +void +cpu_exit(struct proc *p) +{ + struct pcb *pcb = &p->p_addr->u_pcb; + + if (pcb->pcb_flags & PCB_VECTOR) { + free(pcb->pcb_vstate, M_SUBPROC, + sizeof(struct vreg) + 32 * loongarch_vlenb); + pcb->pcb_vstate = NULL; + } +} + +struct kmem_va_mode kv_physwait = { + .kv_map = &phys_map, + .kv_wait = 1, +}; + +/* + * Map a user I/O request into kernel virtual address space. + * Note: the pages are already locked by uvm_vslock(), so we + * do not need to pass an access_type to pmap_enter(). + */ +void +vmapbuf(struct buf *bp, vsize_t len) +{ + vaddr_t faddr, taddr, off; + paddr_t fpa; + + if ((bp->b_flags & B_PHYS) == 0) + panic("vmapbuf"); + faddr = trunc_page((vaddr_t)(bp->b_saveaddr = bp->b_data)); + off = (vaddr_t)bp->b_data - faddr; + len = round_page(off + len); + taddr = (vaddr_t)km_alloc(len, &kv_physwait, &kp_none, &kd_waitok); + bp->b_data = (caddr_t)(taddr + off); + /* + * The region is locked, so we expect that pmap_pte() will return + * non-NULL. + * XXX: unwise to expect this in a multithreaded environment. + * anything can happen to a pmap between the time we lock a + * region, release the pmap lock, and then relock it for + * the pmap_extract(). + * + * no need to flush TLB since we expect nothing to be mapped + * where we just allocated (TLB will be flushed when our + * mapping is removed). + */ + while (len) { + (void) pmap_extract(vm_map_pmap(&bp->b_proc->p_vmspace->vm_map), + faddr, &fpa); + pmap_kenter_pa(taddr, fpa, PROT_READ | PROT_WRITE); + faddr += PAGE_SIZE; + taddr += PAGE_SIZE; + len -= PAGE_SIZE; + } + pmap_update(pmap_kernel()); +} + +/* + * Unmap a previously-mapped user I/O request. + */ +void +vunmapbuf(struct buf *bp, vsize_t len) +{ + vaddr_t addr, off; + + if ((bp->b_flags & B_PHYS) == 0) + panic("vunmapbuf"); + addr = trunc_page((vaddr_t)bp->b_data); + off = (vaddr_t)bp->b_data - addr; + len = round_page(off + len); + pmap_kremove(addr, len); + pmap_update(pmap_kernel()); + km_free((void *)addr, len, &kv_physwait, &kp_none); + bp->b_data = bp->b_saveaddr; + bp->b_saveaddr = NULL; +} diff --git sys/arch/loongarch64/stand/Makefile sys/arch/loongarch64/stand/Makefile new file mode 100644 index 00000000000..7fe46900923 --- /dev/null +++ sys/arch/loongarch64/stand/Makefile @@ -0,0 +1,5 @@ +# $OpenBSD: Makefile,v 1.1 2021/04/28 19:01:00 drahn Exp $ + +SUBDIR= efiboot + +.include diff --git sys/arch/loongarch64/stand/efiboot/Makefile sys/arch/loongarch64/stand/efiboot/Makefile new file mode 100644 index 00000000000..f4065167f1c --- /dev/null +++ sys/arch/loongarch64/stand/efiboot/Makefile @@ -0,0 +1,86 @@ +# $OpenBSD: Makefile,v 1.8 2024/06/30 18:17:10 deraadt Exp $ + +NOMAN= # + +.if ${MACHINE} == "loongarch64" + +PROG= BOOTLOONGARCH64.EFI +OBJFMT= binary +INSTALL_STRIP= +BINDIR= /usr/mdec +SRCS= start.S self_reloc.c efiboot.c conf.c exec.c efiacpi.c +SRCS+= efidev.c efipxe.c efirng.c fdt.c +SRCS+= softraid_loongarch64.c efiloongarch.c + +S= ${.CURDIR}/../../../.. +EFIDIR= ${S}/stand/efi + +OBJCOPY?= objcopy +OBJDUMP?= objdump + +LDFLAGS+=-nostdlib -T ${.CURDIR}/ldscript.loongarch64 -Bsymbolic -shared +LDFLAGS+=--pack-dyn-relocs=none --no-execute-only + +.PATH: ${S}/stand/boot +SRCS+= boot.c cmd.c vars.c + +.PATH: ${S}/lib/libsa +SRCS+= alloc.c ctime.c exit.c getchar.c hexdump.c \ + memcmp.c memcpy.c memmove.c memset.c \ + printf.c putchar.c snprintf.c strchr.c strcmp.c strerror.c strncmp.c \ + strncpy.c strtol.c strtoll.c +SRCS+= close.c closeall.c cons.c cread.c dev.c disklabel.c dkcksum.c fchmod.c \ + fstat.c lseek.c open.c read.c readdir.c stat.c +SRCS+= loadfile.c arc4.c +SRCS+= ufs.c ufs2.c +SRCS+= arp.c ether.c globals.c in_cksum.c net.c netif.c netudp.c tftp.c +SRCS+= aes_xts.c bcrypt_pbkdf.c blowfish.c explicit_bzero.c hmac_sha1.c \ + pkcs5_pbkdf2.c rijndael.c sha1.c sha2.c softraid.c + +.PATH: ${S}/lib/libkern/arch/loongarch64 ${S}/lib/libkern +SRCS+= divdi3.c moddi3.c qdivrem.c strlcat.c strlcpy.c strlen.c + +.PATH: ${S}/lib/libz +SRCS+= adler32.c crc32.c inflate.c inftrees.c + +CPPFLAGS+= -nostdinc +CPPFLAGS+= -I${S} -I. -I${.CURDIR} +CPPFLAGS+= -I${EFIDIR}/include -I${EFIDIR}/include/loongarch64 +CPPFLAGS+= -D_STANDALONE -DBOOT_STTY +CPPFLAGS+= -DSMALL -DSLOW -D__INTERNAL_LIBSA_CREAD +CPPFLAGS+= -DNEEDS_HEAP_H -DFWRANDOM +CPPFLAGS+= -march=loongarch64 --target=loongarch64 -mno-relax +COPTS+= -Wno-attributes -Wno-format +COPTS+= -ffreestanding -fno-stack-protector +COPTS+= -fshort-wchar -fPIC -fno-builtin +COPTS+= -Wall -Werror + +PROG.elf= ${PROG:S/.EFI/.elf/} +CLEANFILES+= ${PROG.elf} ${PROG.elf}.tmp + +${PROG}: ${PROG.elf} + ${OBJCOPY} -j .peheader -j .text -j .sdata -j .data \ + -j .dynamic -j .dynsym -j .dynstr -j .rel -j .rel.dyn \ + -j .rela -j .rela.dyn -j .reloc \ + --output-target=${OBJFMT} ${PROG.elf} ${.TARGET} + +.include + +${PROG.elf}: ${OBJS} + ${LD} ${LDFLAGS} -o ${.TARGET}.tmp ${OBJS} ${LDADD} + @if ${OBJDUMP} -t ${.TARGET}.tmp | grep 'UND'; then \ + (echo Undefined symbols; false); \ + fi + mv ${.TARGET}.tmp ${.TARGET} + +.if !make(clean) && !make(cleandir) && !make(includes) && !make(obj) +.BEGIN: + @([ -h machine ] || ln -s ${.CURDIR}/../../../${MACHINE}/include machine) +.NOPATH: machine +CLEANFILES+= machine +.endif + +.else +NOPROG=yes +.include +.endif diff --git sys/arch/loongarch64/stand/efiboot/acpi.dts sys/arch/loongarch64/stand/efiboot/acpi.dts new file mode 100644 index 00000000000..c22e2982069 --- /dev/null +++ sys/arch/loongarch64/stand/efiboot/acpi.dts @@ -0,0 +1,57 @@ +/dts-v1/; + +/ { + model = "ACPI"; + compatible = "openbsd,acpi"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + aliases { + serial0 = &uart0; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + status = "disabled"; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <0 0 0>, <0 0 0>, <0 0 0>, <0 0 0>; + interrupt-names = "sec-phys", "phys", "virt", "hyp-phys"; + status = "disabled"; + }; + + gic: interrupt-controller@0 { + compatible = "openbsd,gic"; + #interrupt-cells = <3>; + #address-cells = <2>; + #size-cells = <2>; + interrupt-controller; + ranges; + reg = <0x0 0x0 0x0 0x0>, <0x0 0x0 0x0 0x0>; + status = "disabled"; + }; + + uart0: serial@0 { + compatible = "openbsd,uart"; + reg = <0x0 0x0 0x0 0x0>; + status = "disabled"; + }; + + acpi@0 { + compatible = "openbsd,acpi-5.0"; + reg = <0x0 0x0 0x0 0x0>; + }; +}; diff --git sys/arch/loongarch64/stand/efiboot/conf.c sys/arch/loongarch64/stand/efiboot/conf.c new file mode 100644 index 00000000000..7a5c725a42d --- /dev/null +++ sys/arch/loongarch64/stand/efiboot/conf.c @@ -0,0 +1,81 @@ +/* $OpenBSD: conf.c,v 1.7 2026/07/13 17:49:21 jca Exp $ */ + +/* + * Copyright (c) 1996 Michael Shalayeff + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "disk.h" +#include "efiboot.h" +#include "efidev.h" +#include "efipxe.h" +#include "softraid_loongarch64.h" + +const char version[] = "1.10"; +int debug = 0; + +struct fs_ops file_system[] = { + { mtftp_open, mtftp_close, mtftp_read, mtftp_write, mtftp_seek, + mtftp_stat, mtftp_readdir }, + { efitftp_open,tftp_close, tftp_read, tftp_write, tftp_seek, + tftp_stat, tftp_readdir }, + { ufs_open, ufs_close, ufs_read, ufs_write, ufs_seek, + ufs_stat, ufs_readdir, ufs_fchmod }, + { ufs2_open, ufs2_close, ufs2_read, ufs2_write, ufs2_seek, + ufs2_stat, ufs2_readdir, ufs2_fchmod }, +}; +int nfsys = nitems(file_system); + +struct devsw devsw[] = { + { "tftp", tftpstrategy, tftpopen, tftpclose, tftpioctl }, + { "sd", efistrategy, efiopen, eficlose, efiioctl }, + { "sr", srstrategy, sropen, srclose, srioctl }, +}; +int ndevs = nitems(devsw); + +struct consdev constab[] = { + { efi_cons_probe, efi_cons_init, efi_cons_getc, efi_cons_putc }, + { efi_fb_probe, efi_fb_init, efi_cons_getc, efi_cons_putc }, + { NULL } +}; +struct consdev *cn_tab; + +struct netif_driver *netif_drivers[] = { + &efinet_driver, +}; +int n_netif_drivers = nitems(netif_drivers); diff --git sys/arch/loongarch64/stand/efiboot/disk.h sys/arch/loongarch64/stand/efiboot/disk.h new file mode 100644 index 00000000000..1492c4f5e31 --- /dev/null +++ sys/arch/loongarch64/stand/efiboot/disk.h @@ -0,0 +1,33 @@ +/* $OpenBSD: disk.h,v 1.1 2021/04/28 19:01:00 drahn Exp $ */ + +#ifndef _DISK_H +#define _DISK_H + +#include + +typedef struct efi_diskinfo { + EFI_BLOCK_IO *blkio; + UINT32 mediaid; +} *efi_diskinfo_t; + +struct diskinfo { + struct efi_diskinfo ed; + struct disklabel disklabel; + struct sr_boot_volume *sr_vol; + + u_int part; + u_int flags; +#define DISKINFO_FLAG_GOODLABEL (1 << 0) + + int (*diskio)(int, struct diskinfo *, u_int, int, void *); + int (*strategy)(void *, int, daddr_t, size_t, void *, size_t *); + + TAILQ_ENTRY(diskinfo) list; +}; +TAILQ_HEAD(disklist_lh, diskinfo); + +extern struct diskinfo *bootdev_dip; + +extern struct disklist_lh disklist; + +#endif /* _DISK_H */ diff --git sys/arch/loongarch64/stand/efiboot/dt_blob.S sys/arch/loongarch64/stand/efiboot/dt_blob.S new file mode 100644 index 00000000000..bf5089830e5 --- /dev/null +++ sys/arch/loongarch64/stand/efiboot/dt_blob.S @@ -0,0 +1,973 @@ +/* autogenerated by dtc, do not edit */ + + .globl dt_blob_start +dt_blob_start: +_dt_blob_start: + .globl dt_header +dt_header: +_dt_header: + /* magic */ + .byte 0xd0 + .byte 0x0d + .byte 0xfe + .byte 0xed + /* totalsize */ + .byte ((_dt_blob_abs_end - _dt_blob_start) >> 24) & 0xff + .byte ((_dt_blob_abs_end - _dt_blob_start) >> 16) & 0xff + .byte ((_dt_blob_abs_end - _dt_blob_start) >> 8) & 0xff + .byte (_dt_blob_abs_end - _dt_blob_start) & 0xff + /* off_dt_struct */ + .byte ((_dt_struct_start - _dt_blob_start) >> 24) & 0xff + .byte ((_dt_struct_start - _dt_blob_start) >> 16) & 0xff + .byte ((_dt_struct_start - _dt_blob_start) >> 8) & 0xff + .byte (_dt_struct_start - _dt_blob_start) & 0xff + /* off_dt_strings */ + .byte ((_dt_strings_start - _dt_blob_start) >> 24) & 0xff + .byte ((_dt_strings_start - _dt_blob_start) >> 16) & 0xff + .byte ((_dt_strings_start - _dt_blob_start) >> 8) & 0xff + .byte (_dt_strings_start - _dt_blob_start) & 0xff + /* off_mem_rsvmap */ + .byte ((_dt_reserve_map - _dt_blob_start) >> 24) & 0xff + .byte ((_dt_reserve_map - _dt_blob_start) >> 16) & 0xff + .byte ((_dt_reserve_map - _dt_blob_start) >> 8) & 0xff + .byte (_dt_reserve_map - _dt_blob_start) & 0xff + /* version */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x11 + /* last_comp_version */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x10 + /* boot_cpuid_phys */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + /* size_dt_strings */ + .byte ((_dt_strings_end - _dt_strings_start) >> 24) & 0xff + .byte ((_dt_strings_end - _dt_strings_start) >> 16) & 0xff + .byte ((_dt_strings_end - _dt_strings_start) >> 8) & 0xff + .byte (_dt_strings_end - _dt_strings_start) & 0xff + /* size_dt_struct */ + .byte ((_dt_struct_end - _dt_struct_start) >> 24) & 0xff + .byte ((_dt_struct_end - _dt_struct_start) >> 16) & 0xff + .byte ((_dt_struct_end - _dt_struct_start) >> 8) & 0xff + .byte (_dt_struct_end - _dt_struct_start) & 0xff + .balign 8, 0 + .globl dt_reserve_map +dt_reserve_map: +_dt_reserve_map: +/* Memory reserve map from source file */ + .long 0, 0 + .long 0, 0 + .globl dt_struct_start +dt_struct_start: +_dt_struct_start: + /* FDT_BEGIN_NODE */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x01 + .asciz "" + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x05 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x41 + .byte 0x43 + .byte 0x50 + .byte 0x49 + .byte 0x0 + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x0d + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x06 + .byte 0x6f + .byte 0x70 + .byte 0x65 + .byte 0x6e + .byte 0x62 + .byte 0x73 + .byte 0x64 + .byte 0x2c + .byte 0x61 + .byte 0x63 + .byte 0x70 + .byte 0x69 + .byte 0x0 + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x04 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x11 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x01 + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x04 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x22 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x02 + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x04 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x31 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x02 + .balign 4, 0 + /* FDT_BEGIN_NODE */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x01 + .asciz "chosen" + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x11 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x3d + .byte 0x73 + .byte 0x65 + .byte 0x72 + .byte 0x69 + .byte 0x61 + .byte 0x6c + .byte 0x30 + .byte 0x3a + .byte 0x31 + .byte 0x31 + .byte 0x35 + .byte 0x32 + .byte 0x30 + .byte 0x30 + .byte 0x6e + .byte 0x38 + .byte 0x0 + .balign 4, 0 + /* FDT_END_NODE */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x02 + /* FDT_BEGIN_NODE */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x01 + .asciz "aliases" + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x0a + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x49 + .byte 0x2f + .byte 0x73 + .byte 0x65 + .byte 0x72 + .byte 0x69 + .byte 0x61 + .byte 0x6c + .byte 0x40 + .byte 0x30 + .byte 0x0 + .balign 4, 0 + /* FDT_END_NODE */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x02 + /* FDT_BEGIN_NODE */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x01 + .asciz "cpus" + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x04 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x22 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x02 + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x04 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x31 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .balign 4, 0 + /* FDT_END_NODE */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x02 + /* FDT_BEGIN_NODE */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x01 + .asciz "psci" + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x0d + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x06 + .byte 0x61 + .byte 0x72 + .byte 0x6d + .byte 0x2c + .byte 0x70 + .byte 0x73 + .byte 0x63 + .byte 0x69 + .byte 0x2d + .byte 0x31 + .byte 0x2e + .byte 0x30 + .byte 0x0 + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x04 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x51 + .byte 0x73 + .byte 0x6d + .byte 0x63 + .byte 0x00 + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x09 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x58 + .byte 0x64 + .byte 0x69 + .byte 0x73 + .byte 0x61 + .byte 0x62 + .byte 0x6c + .byte 0x65 + .byte 0x64 + .byte 0x0 + .balign 4, 0 + /* FDT_END_NODE */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x02 + /* FDT_BEGIN_NODE */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x01 + .asciz "timer" + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x10 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x06 + .byte 0x61 + .byte 0x72 + .byte 0x6d + .byte 0x2c + .byte 0x61 + .byte 0x72 + .byte 0x6d + .byte 0x76 + .byte 0x38 + .byte 0x2d + .byte 0x74 + .byte 0x69 + .byte 0x6d + .byte 0x65 + .byte 0x72 + .byte 0x00 + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x30 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x5f + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x1c + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x6a + .byte 0x73 + .byte 0x65 + .byte 0x63 + .byte 0x2d + .byte 0x70 + .byte 0x68 + .byte 0x79 + .byte 0x73 + .byte 0x00 + .byte 0x70 + .byte 0x68 + .byte 0x79 + .byte 0x73 + .byte 0x00 + .byte 0x76 + .byte 0x69 + .byte 0x72 + .byte 0x74 + .byte 0x00 + .byte 0x68 + .byte 0x79 + .byte 0x70 + .byte 0x2d + .byte 0x70 + .byte 0x68 + .byte 0x79 + .byte 0x73 + .byte 0x00 + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x09 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x58 + .byte 0x64 + .byte 0x69 + .byte 0x73 + .byte 0x61 + .byte 0x62 + .byte 0x6c + .byte 0x65 + .byte 0x64 + .byte 0x0 + .balign 4, 0 + /* FDT_END_NODE */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x02 + .globl gic +gic: + /* FDT_BEGIN_NODE */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x01 + .asciz "interrupt-controller@0" + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x0c + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x06 + .byte 0x6f + .byte 0x70 + .byte 0x65 + .byte 0x6e + .byte 0x62 + .byte 0x73 + .byte 0x64 + .byte 0x2c + .byte 0x67 + .byte 0x69 + .byte 0x63 + .byte 0x00 + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x04 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x7a + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x04 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x22 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x02 + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x04 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x31 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x02 + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x8b + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0xa0 + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x20 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0xa7 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x09 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x58 + .byte 0x64 + .byte 0x69 + .byte 0x73 + .byte 0x61 + .byte 0x62 + .byte 0x6c + .byte 0x65 + .byte 0x64 + .byte 0x0 + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x04 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0xab + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x01 + .balign 4, 0 + /* FDT_END_NODE */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x02 + .globl gic_end +gic_end: + .globl uart0 +uart0: + /* FDT_BEGIN_NODE */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x01 + .asciz "serial@0" + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x0d + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x06 + .byte 0x6f + .byte 0x70 + .byte 0x65 + .byte 0x6e + .byte 0x62 + .byte 0x73 + .byte 0x64 + .byte 0x2c + .byte 0x75 + .byte 0x61 + .byte 0x72 + .byte 0x74 + .byte 0x0 + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x10 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0xa7 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x09 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x58 + .byte 0x64 + .byte 0x69 + .byte 0x73 + .byte 0x61 + .byte 0x62 + .byte 0x6c + .byte 0x65 + .byte 0x64 + .byte 0x0 + .balign 4, 0 + /* FDT_END_NODE */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x02 + .globl uart0_end +uart0_end: + /* FDT_BEGIN_NODE */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x01 + .asciz "acpi@0" + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x11 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x06 + .byte 0x6f + .byte 0x70 + .byte 0x65 + .byte 0x6e + .byte 0x62 + .byte 0x73 + .byte 0x64 + .byte 0x2c + .byte 0x61 + .byte 0x63 + .byte 0x70 + .byte 0x69 + .byte 0x2d + .byte 0x35 + .byte 0x2e + .byte 0x30 + .byte 0x0 + .balign 4, 0 + /* FDT_PROP */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x10 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0xa7 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .balign 4, 0 + /* FDT_END_NODE */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x02 + /* FDT_END_NODE */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x02 + /* FDT_END */ + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x09 + .globl dt_struct_end +dt_struct_end: +_dt_struct_end: + .globl dt_strings_start +dt_strings_start: +_dt_strings_start: + .asciz "model" + .asciz "compatible" + .asciz "interrupt-parent" + .asciz "#address-cells" + .asciz "#size-cells" + .asciz "stdout-path" + .asciz "serial0" + .asciz "method" + .asciz "status" + .asciz "interrupts" + .asciz "interrupt-names" + .asciz "#interrupt-cells" + .asciz "interrupt-controller" + .asciz "ranges" + .asciz "reg" + .asciz "phandle" + .globl dt_strings_end +dt_strings_end: +_dt_strings_end: + .globl dt_blob_end +dt_blob_end: +_dt_blob_end: + .space 16384, 0 + .globl dt_blob_abs_end +dt_blob_abs_end: +_dt_blob_abs_end: diff --git sys/arch/loongarch64/stand/efiboot/efiacpi.c sys/arch/loongarch64/stand/efiboot/efiacpi.c new file mode 100644 index 00000000000..346cde3ead1 --- /dev/null +++ sys/arch/loongarch64/stand/efiboot/efiacpi.c @@ -0,0 +1,856 @@ +/* $OpenBSD: efiacpi.c,v 1.20 2026/05/14 12:26:58 kettenis Exp $ */ + +/* + * Copyright (c) 2018 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include + +#include "fdt.h" +#include "libsa.h" + +#define efi_guidcmp(_a, _b) memcmp((_a), (_b), sizeof(EFI_GUID)) + +#define fdt_node_add_string_property(n, p, s) \ + fdt_node_add_property((n), (p), (s), strlen((s)) + 1) +#define fdt_node_set_string_property(n, p, s) \ + fdt_node_set_property((n), (p), (s), strlen((s)) + 1) + +extern EFI_SYSTEM_TABLE *ST; + +/* ACPI tables */ + +struct acpi_rsdp1 { + uint8_t signature[8]; +#define RSDP_SIG "RSD PTR " +#define rsdp_signature rsdp1.signature + uint8_t checksum; /* make sum == 0 */ +#define rsdp_checksum rsdp1.checksum + uint8_t oemid[6]; +#define rsdp_oemid rsdp1.oemid + uint8_t revision; /* 0 for 1, 2 for 2 */ +#define rsdp_revision rsdp1.revision + uint32_t rsdt; /* physical */ +#define rsdp_rsdt rsdp1.rsdt +} __packed; + +struct acpi_rsdp { + struct acpi_rsdp1 rsdp1; + /* + * The following values are only valid + * when rsdp_revision == 2 + */ + uint32_t rsdp_length; /* length of rsdp */ + uint64_t rsdp_xsdt; /* physical */ + uint8_t rsdp_extchecksum; /* entire table */ + uint8_t rsdp_reserved[3]; /* must be zero */ +} __packed; + +struct acpi_table_header { + uint8_t signature[4]; +#define hdr_signature hdr.signature + uint32_t length; +#define hdr_length hdr.length + uint8_t revision; +#define hdr_revision hdr.revision + uint8_t checksum; +#define hdr_checksum hdr.checksum + uint8_t oemid[6]; +#define hdr_oemid hdr.oemid + uint8_t oemtableid[8]; +#define hdr_oemtableid hdr.oemtableid + uint32_t oemrevision; +#define hdr_oemrevision hdr.oemrevision + uint8_t aslcompilerid[4]; +#define hdr_aslcompilerid hdr.aslcompilerid + uint32_t aslcompilerrevision; +#define hdr_aslcompilerrevision hdr.aslcompilerrevision +} __packed; + +struct acpi_xsdt { + struct acpi_table_header hdr; +#define XSDT_SIG "XSDT" + uint64_t table_offsets[1]; +} __packed; + +struct acpi_gas { + uint8_t address_space_id; +#define GAS_SYSTEM_MEMORY 0 +#define GAS_SYSTEM_IOSPACE 1 +#define GAS_PCI_CFG_SPACE 2 +#define GAS_EMBEDDED 3 +#define GAS_SMBUS 4 +#define GAS_FUNCTIONAL_FIXED 127 + uint8_t register_bit_width; + uint8_t register_bit_offset; + uint8_t access_size; +#define GAS_ACCESS_UNDEFINED 0 +#define GAS_ACCESS_BYTE 1 +#define GAS_ACCESS_WORD 2 +#define GAS_ACCESS_DWORD 3 +#define GAS_ACCESS_QWORD 4 + uint64_t address; +} __packed; + +struct acpi_fadt { + struct acpi_table_header hdr; +#define FADT_SIG "FACP" + uint32_t firmware_ctl; /* phys addr FACS */ + uint32_t dsdt; /* phys addr DSDT */ + uint8_t int_model; /* interrupt model (hdr_revision < 3) */ +#define FADT_INT_DUAL_PIC 0 +#define FADT_INT_MULTI_APIC 1 + uint8_t pm_profile; /* power mgmt profile */ +#define FADT_PM_UNSPEC 0 +#define FADT_PM_DESKTOP 1 +#define FADT_PM_MOBILE 2 +#define FADT_PM_WORKSTATION 3 +#define FADT_PM_ENT_SERVER 4 +#define FADT_PM_SOHO_SERVER 5 +#define FADT_PM_APPLIANCE 6 +#define FADT_PM_PERF_SERVER 7 + uint16_t sci_int; /* SCI interrupt */ + uint32_t smi_cmd; /* SMI command port */ + uint8_t acpi_enable; /* value to enable */ + uint8_t acpi_disable; /* value to disable */ + uint8_t s4bios_req; /* value for S4 */ + uint8_t pstate_cnt; /* value for performance (hdr_revision > 2) */ + uint32_t pm1a_evt_blk; /* power management 1a */ + uint32_t pm1b_evt_blk; /* power management 1b */ + uint32_t pm1a_cnt_blk; /* pm control 1a */ + uint32_t pm1b_cnt_blk; /* pm control 1b */ + uint32_t pm2_cnt_blk; /* pm control 2 */ + uint32_t pm_tmr_blk; + uint32_t gpe0_blk; + uint32_t gpe1_blk; + uint8_t pm1_evt_len; + uint8_t pm1_cnt_len; + uint8_t pm2_cnt_len; + uint8_t pm_tmr_len; + uint8_t gpe0_blk_len; + uint8_t gpe1_blk_len; + uint8_t gpe1_base; + uint8_t cst_cnt; /* (hdr_revision > 2) */ + uint16_t p_lvl2_lat; + uint16_t p_lvl3_lat; + uint16_t flush_size; + uint16_t flush_stride; + uint8_t duty_offset; + uint8_t duty_width; + uint8_t day_alrm; + uint8_t mon_alrm; + uint8_t century; + uint16_t iapc_boot_arch; /* (hdr_revision > 2) */ +#define FADT_LEGACY_DEVICES 0x0001 /* Legacy devices supported */ +#define FADT_i8042 0x0002 /* Keyboard controller present */ +#define FADT_NO_VGA 0x0004 /* Do not probe VGA */ + uint8_t reserved1; + uint32_t flags; +#define FADT_WBINVD 0x00000001 +#define FADT_WBINVD_FLUSH 0x00000002 +#define FADT_PROC_C1 0x00000004 +#define FADT_P_LVL2_UP 0x00000008 +#define FADT_PWR_BUTTON 0x00000010 +#define FADT_SLP_BUTTON 0x00000020 +#define FADT_FIX_RTC 0x00000040 +#define FADT_RTC_S4 0x00000080 +#define FADT_TMR_VAL_EXT 0x00000100 +#define FADT_DCK_CAP 0x00000200 +#define FADT_RESET_REG_SUP 0x00000400 +#define FADT_SEALED_CASE 0x00000800 +#define FADT_HEADLESS 0x00001000 +#define FADT_CPU_SW_SLP 0x00002000 +#define FADT_PCI_EXP_WAK 0x00004000 +#define FADT_USE_PLATFORM_CLOCK 0x00008000 +#define FADT_S4_RTC_STS_VALID 0x00010000 +#define FADT_REMOTE_POWER_ON_CAPABLE 0x00020000 +#define FADT_FORCE_APIC_CLUSTER_MODEL 0x00040000 +#define FADT_FORCE_APIC_PHYS_DEST_MODE 0x00080000 +#define FADT_HW_REDUCED_ACPI 0x00100000 +#define FADT_POWER_S0_IDLE_CAPABLE 0x00200000 + /* + * Following values only exist when rev > 1 + * If the extended addresses exists, they + * must be used in preference to the non- + * extended values above + */ + struct acpi_gas reset_reg; + uint8_t reset_value; + uint16_t arm_boot_arch; /* (hdr_revision > 3) */ +#define FADT_PSCI_COMPLIANT 0x0001 /* PSCI is implemented */ +#define FADT_PSCI_USE_HVC 0x0002 /* HVC used as PSCI conduit */ + uint8_t reserved2; + uint64_t x_firmware_ctl; + uint64_t x_dsdt; + struct acpi_gas x_pm1a_evt_blk; + struct acpi_gas x_pm1b_evt_blk; + struct acpi_gas x_pm1a_cnt_blk; + struct acpi_gas x_pm1b_cnt_blk; + struct acpi_gas x_pm2_cnt_blk; + struct acpi_gas x_pm_tmr_blk; + struct acpi_gas x_gpe0_blk; + struct acpi_gas x_gpe1_blk; + struct acpi_gas sleep_control_reg; + struct acpi_gas sleep_status_reg; +} __packed; + +struct acpi_gtdt { + struct acpi_table_header hdr; +#define GTDT_SIG "GTDT" + uint64_t cnt_ctrl_base; + uint32_t reserved; + uint32_t sec_el1_interrupt; + uint32_t sec_el1_flags; +#define ACPI_GTDT_TIMER_TRIGGER_EDGE 0x1 +#define ACPI_GTDT_TIMER_POLARITY_LOW 0x2 +#define ACPI_GTDT_TIMER_ALWAYS_ON 0x4 + uint32_t nonsec_el1_interrupt; + uint32_t nonsec_el1_flags; + uint32_t virt_el1_interrupt; + uint32_t virt_el1_flags; + uint32_t nonsec_el2_interrupt; + uint32_t nonsec_el2_flags; + uint64_t cnt_read_base; + uint32_t platform_timer_count; + uint32_t platform_timer_offset; + uint32_t virt_el2_interrupt; + uint32_t virt_el2_flags; +} __packed; + +struct acpi_madt { + struct acpi_table_header hdr; +#define MADT_SIG "APIC" + uint32_t local_apic_address; + uint32_t flags; +#define ACPI_APIC_PCAT_COMPAT 0x00000001 +} __packed; + +struct acpi_madt_gicc { + uint8_t apic_type; +#define ACPI_MADT_GICC 11 + uint8_t length; + uint16_t reserved1; + uint32_t gic_id; + uint32_t acpi_proc_uid; + uint32_t flags; +#define ACPI_PROC_ENABLE 0x00000001 + uint32_t parking_protocol_version; + uint32_t performance_interrupt; + uint64_t parked_address; + uint64_t base_address; + uint64_t gicv_base_address; + uint64_t gich_base_address; + uint32_t maintenance_interrupt; + uint64_t gicr_base_address; + uint64_t mpidr; + uint8_t efficiency_class; + uint8_t reserved2[3]; +} __packed; + +struct acpi_madt_gicd { + uint8_t apic_type; +#define ACPI_MADT_GICD 12 + uint8_t length; + uint16_t reserved1; + uint32_t gic_id; + uint64_t base_address; + uint32_t interrupt_base; + uint8_t version; + uint8_t reserved2[3]; +} __packed; + +struct acpi_madt_gic_msi { + uint8_t apic_type; +#define ACPI_MADT_GIC_MSI 13 + uint8_t length; + uint16_t reserved1; + uint32_t msi_frame_id; + uint64_t base_address; + uint32_t flags; +#define ACPI_MADT_GIC_MSI_SPI_SELECT 0x00000001 + uint16_t spi_count; + uint16_t spi_base; +} __packed; + +struct acpi_madt_gicr { + uint8_t apic_type; +#define ACPI_MADT_GICR 14 + uint8_t length; + uint16_t reserved1; + uint64_t discovery_base_address; + uint32_t discovery_length; +} __packed; + +struct acpi_madt_gic_its { + uint8_t apic_type; +#define ACPI_MADT_GIC_ITS 15 + uint8_t length; + uint16_t reserved1; + uint32_t gic_its_id; + uint64_t base_address; + uint32_t reserved2; +} __packed; + +union acpi_madt_entry { + struct acpi_madt_gicc madt_gicc; + struct acpi_madt_gicd madt_gicd; + struct acpi_madt_gic_msi madt_gic_msi; + struct acpi_madt_gicr madt_gicr; + struct acpi_madt_gic_its madt_gic_its; +} __packed; + +struct acpi_spcr { + struct acpi_table_header hdr; +#define SPCR_SIG "SPCR" + uint8_t interface_type; +#define SPCR_16550 0 +#define SPCR_16450 1 +#define SPCR_ARM_PL011 3 +#define SPCR_ARM_SBSA 14 + uint8_t reserved1[3]; + struct acpi_gas base_address; + uint8_t interrupt_type; + uint8_t irq; + uint32_t gsiv; + uint8_t baud_rate; + uint8_t parity; + uint8_t stop_bits; + uint8_t flow_control; + uint8_t terminal_type; + uint8_t reserved2; + uint16_t pci_device_id; + uint16_t pci_vendor_id; + uint8_t pci_bus; + uint8_t pci_device; + uint8_t pci_function; + uint32_t pci_flags; + uint8_t pci_segment; + uint32_t reserved3; +} __packed; + +struct acpi_dbg2 { + struct acpi_table_header hdr; +#define DBG2_SIG "DBG2" + uint32_t info_offset; + uint32_t info_count; +} __packed; + +struct acpi_dbg2_info { + uint8_t revision; + uint16_t length; + uint8_t num_address; + uint16_t name_length; + uint16_t name_offset; + uint16_t oem_data_length; + uint16_t oem_data_offset; + uint16_t port_type; +#define DBG2_SERIAL 0x8000 + uint16_t port_subtype; +#define DBG2_16550 0x0000 +#define DBG2_16450 0x0001 +#define DBG2_ARM_PL011 0x0003 +#define DBG2_ARM_SBSA 0x000e + uint16_t reserved; + uint16_t base_address_offset; + uint16_t address_size_offset; +} __packed; + +/* We'll never see ACPI 1.0 tables on ARM. */ +static EFI_GUID acpi_guid = ACPI_20_TABLE_GUID; + +static int psci = 0; + +void +efi_acpi_fadt(struct acpi_table_header *hdr) +{ + struct acpi_fadt *fadt = (struct acpi_fadt *)hdr; + void *node; + + /* + * The PSCI flags were introduced in ACPI 5.1. The relevant + * field is set to zero for ACPU 5.0. + */ + if (fadt->hdr_revision < 5) + return; + + psci = fadt->arm_boot_arch & FADT_PSCI_COMPLIANT; + + node = fdt_find_node("/psci"); + if (fadt->arm_boot_arch & FADT_PSCI_COMPLIANT) + fdt_node_set_string_property(node, "status", "okay"); + if (fadt->arm_boot_arch & FADT_PSCI_USE_HVC) + fdt_node_set_string_property(node, "method", "hvc"); +} + +void +efi_acpi_gtdt(struct acpi_table_header *hdr) +{ + struct acpi_gtdt *gtdt = (struct acpi_gtdt *)hdr; + const uint32_t map[] = { 0x4, 0x1, 0x8, 0x2 }; + const uint32_t mask = ACPI_GTDT_TIMER_TRIGGER_EDGE | + ACPI_GTDT_TIMER_POLARITY_LOW; + char interrupt_names[] = "sec-phys\0phys\0virt\0hyp-phys\0hyp-virt"; + uint32_t interrupts[15]; + void *node; + size_t len; + + node = fdt_find_node("/timer"); + + /* All interrupts are supposed to be PPIs. */ + interrupts[0] = htobe32(1); + interrupts[1] = htobe32(gtdt->sec_el1_interrupt - 16); + interrupts[2] = htobe32(map[gtdt->sec_el1_flags & mask]); + interrupts[3] = htobe32(1); + interrupts[4] = htobe32(gtdt->nonsec_el1_interrupt - 16); + interrupts[5] = htobe32(map[gtdt->nonsec_el1_flags & mask]); + interrupts[6] = htobe32(1); + interrupts[7] = htobe32(gtdt->virt_el1_interrupt - 16); + interrupts[8] = htobe32(map[gtdt->virt_el1_flags & mask]); + interrupts[9] = htobe32(1); + interrupts[10] = htobe32(gtdt->nonsec_el2_interrupt - 16); + interrupts[11] = htobe32(map[gtdt->nonsec_el2_flags & mask]); + len = 12 * sizeof(uint32_t); + + if (gtdt->hdr.revision > 2 && gtdt->hdr.length >= 104 && + gtdt->virt_el2_interrupt > 0) { + interrupts[12] = htobe32(1); + interrupts[13] = htobe32(gtdt->virt_el2_interrupt - 16); + interrupts[14] = htobe32(map[gtdt->virt_el2_flags & mask]); + len = 15 * sizeof(uint32_t); + + fdt_node_set_property(node, "interrupt-names", + interrupt_names, sizeof(interrupt_names)); + } + + fdt_node_set_property(node, "interrupts", interrupts, len); + fdt_node_set_string_property(node, "status", "okay"); +} + +static int gic_version; +static uint64_t gicc_base; +static uint64_t gicd_base; +static uint64_t gicr_base; +static uint64_t gicr_size; +static uint64_t gicr_stride; + +void +efi_acpi_madt_gicc(struct acpi_madt_gicc *gicc) +{ + uint64_t mpidr = gicc->mpidr; + void *node, *child; + uint64_t reg; + char name[32]; + + /* Skip disabled CPUs. */ + if ((gicc->flags & ACPI_PROC_ENABLE) == 0) + return; + + /* + * MPIDR field was introduced in ACPI 5.1. Fall back on the + * ACPI Processor UID on ACPI 5.0. + */ + mpidr = (gicc->length >= 76) ? gicc->mpidr : gicc->acpi_proc_uid; + + snprintf(name, sizeof(name), "cpu@%llx", mpidr); + reg = htobe64(mpidr); + + /* Create "cpu" node. */ + node = fdt_find_node("/cpus"); + fdt_node_add_node(node, name, &child); + fdt_node_add_string_property(child, "device_type", "cpu"); + fdt_node_add_string_property(child, "compatible", "arm,armv8"); + fdt_node_add_property(child, "reg", ®, sizeof(reg)); + if (gicc->parking_protocol_version == 0 || psci) + fdt_node_add_string_property(child, "enable-method", "psci"); + + /* Stash GIC information. */ + gicc_base = gicc->base_address; + + /* + * The redistributor base address may be specified per-CPU. + * In that case we will need to reconstruct the base, size and + * stride to use for the redistributor registers. + */ + if (gicc->gicr_base_address > 0) { + if (gicr_base > 0) { + uint32_t size; + + if (gicc->gicr_base_address < gicr_base) + size = gicr_base - gicc->gicr_base_address; + else + size = gicc->gicr_base_address - gicr_base; + if (gicr_stride == 0 || size < gicr_stride) + gicr_stride = size; + if (gicr_size == 0 || size > gicr_size) + gicr_size = size; + gicr_base = MIN(gicr_base, gicc->gicr_base_address); + } else { + gicr_base = gicc->gicr_base_address; + gicr_size = 0x20000; + } + } +} + +void +efi_acpi_madt_gicd(struct acpi_madt_gicd *gicd) +{ + /* Stash GIC information. */ + gic_version = gicd->version; + gicd_base = gicd->base_address; +} + +void +efi_acpi_madt_gic_msi(struct acpi_madt_gic_msi *msi) +{ + static uint32_t phandle = 2; + void *node, *child; + uint64_t reg[2]; + char name[32]; + + snprintf(name, sizeof(name), "v2m@%llx", msi->base_address); + reg[0] = htobe64(msi->base_address); + reg[1] = htobe64(0x1000); + + /* Create "v2m" node. */ + node = fdt_find_node("/interrupt-controller"); + fdt_node_add_node(node, name, &child); + fdt_node_add_string_property(child, "compatible", "arm,gic-v2m-frame"); + fdt_node_add_property(child, "msi-controller", NULL, 0); + fdt_node_add_property(child, "reg", reg, sizeof(reg)); + if (msi->flags & ACPI_MADT_GIC_MSI_SPI_SELECT) { + uint32_t spi_base = htobe32(msi->spi_base); + uint32_t spi_count = htobe32(msi->spi_count); + + fdt_node_add_property(child, "arm,msi-base-spi", + &spi_base, sizeof(spi_base)); + fdt_node_add_property(child, "arm,msi-num-spis", + &spi_count, sizeof(spi_count)); + } + fdt_node_add_property(child, "phandle", &phandle, sizeof(phandle)); + phandle++; +} + +void +efi_acpi_madt_gicr(struct acpi_madt_gicr *gicr) +{ + /* Stash GIC information. */ + gicr_base = gicr->discovery_base_address; + gicr_size = gicr->discovery_length; +} + +void +efi_acpi_madt_gic_its(struct acpi_madt_gic_its *its) +{ + static uint32_t phandle = 2; + void *node, *child; + uint64_t reg[2]; + uint32_t its_id; + char name[32]; + + snprintf(name, sizeof(name), "gic-its@%llx", its->base_address); + reg[0] = htobe64(its->base_address); + reg[1] = htobe64(0x20000); + its_id = htobe32(its->gic_its_id); + + /* Create "gic-its" node. */ + node = fdt_find_node("/interrupt-controller"); + fdt_node_add_node(node, name, &child); + fdt_node_add_string_property(child, "compatible", "arm,gic-v3-its"); + fdt_node_add_property(child, "msi-controller", NULL, 0); + fdt_node_add_property(child, "reg", reg, sizeof(reg)); + fdt_node_add_property(child, "phandle", &phandle, sizeof(phandle)); + fdt_node_add_property(child, "openbsd,gic-its-id", &its_id, + sizeof(its_id)); + phandle++; +} + +void +efi_acpi_madt(struct acpi_table_header *hdr) +{ + struct acpi_madt *madt = (struct acpi_madt *)hdr; + char *compat; + uint64_t reg[4]; + char *addr; + void *node; + + /* GIC support was introduced in ACPI 5.0. */ + if (madt->hdr_revision < 3) + return; + + addr = (char *)(madt + 1); + while (addr < (char *)madt + madt->hdr.length) { + union acpi_madt_entry *entry = (union acpi_madt_entry *)addr; + uint8_t length = entry->madt_gicc.length; + + if (length < 2) + return; + + if (addr + length > (char *)madt + madt->hdr_length) + return; + + switch (entry->madt_gicc.apic_type) { + case ACPI_MADT_GICC: + efi_acpi_madt_gicc(&entry->madt_gicc); + break; + case ACPI_MADT_GICD: + efi_acpi_madt_gicd(&entry->madt_gicd); + break; + case ACPI_MADT_GIC_MSI: + efi_acpi_madt_gic_msi(&entry->madt_gic_msi); + break; + case ACPI_MADT_GICR: + efi_acpi_madt_gicr(&entry->madt_gicr); + break; + case ACPI_MADT_GIC_ITS: + efi_acpi_madt_gic_its(&entry->madt_gic_its); + break; + } + + addr += length; + } + + /* + * Now that we've collected all the necessary information, fix + * up the "interrupt-controller" node. + */ + + switch (gic_version) { + case 0: + /* ACPI 5.0 doesn't provide a version; assume GICv2 */ + case 2: + /* GICv2 */ + compat = "arm,gic-400"; + reg[0] = htobe64(gicd_base); + reg[1] = htobe64(0x1000); + reg[2] = htobe64(gicc_base); + reg[3] = htobe64(0x100); + break; + case 3: + case 4: + /* GICv3 and GICv4 */ + compat = "arm,gic-v3"; + reg[0] = htobe64(gicd_base); + reg[1] = htobe64(0x10000); + reg[2] = htobe64(gicr_base); + reg[3] = htobe64(gicr_size + gicr_stride); + break; + default: + return; + } + + /* Update "interrupt-controller" node. */ + node = fdt_find_node("/interrupt-controller"); + fdt_node_set_string_property(node, "compatible", compat); + fdt_node_set_property(node, "reg", reg, sizeof(reg)); + if (gicr_stride > 0) { + uint64_t stride = htobe64(gicr_stride); + fdt_node_add_property(node, "redistributor-stride", + &stride, sizeof(stride)); + } + fdt_node_set_string_property(node, "status", "okay"); +} + +static int serial = 0; + +void +efi_acpi_serial(char *compat, struct acpi_gas *base_address, + uint32_t address_size) +{ + uint64_t reg[2], reg_shift, reg_io_width; + void *node; + + /* No idea how to support anything else on ARM. */ + if (base_address->address_space_id != GAS_SYSTEM_MEMORY) + return; + + switch (base_address->access_size) { + case GAS_ACCESS_BYTE: + reg_io_width = 1; + break; + case GAS_ACCESS_WORD: + reg_io_width = 2; + break; + case GAS_ACCESS_DWORD: + reg_io_width = 4; + break; + case GAS_ACCESS_QWORD: + reg_io_width = 8; + break; + default: + return; + } + reg_io_width = htobe32(reg_io_width); + + reg_shift = 0; + if (base_address->register_bit_width > 8) + reg_shift = 1; + if (base_address->register_bit_width > 16) + reg_shift = 2; + if (base_address->register_bit_width > 32) + reg_shift = 3; + reg_shift = htobe32(reg_shift); + + /* Update "serial" node. */ + node = fdt_find_node("/serial"); + fdt_node_set_string_property(node, "compatible", compat); + if (strcmp(compat, "snps,dw-apb-uart") == 0) { + fdt_node_add_property(node, "reg-shift", + ®_shift, sizeof(reg_shift)); + fdt_node_add_property(node, "reg-io-width", + ®_io_width, sizeof(reg_io_width)); + } + reg[0] = htobe64(base_address->address); + reg[1] = htobe64(address_size); + fdt_node_set_property(node, "reg", reg, sizeof(reg)); +} + +void +efi_acpi_spcr(struct acpi_table_header *hdr) +{ + struct acpi_spcr *spcr = (struct acpi_spcr *)hdr; + + /* Minimal revision required by Server Base Boot Requirements is 2. */ + if (spcr->hdr_revision < 2) + return; + + switch (spcr->interface_type) { + case SPCR_16550: + case SPCR_16450: + efi_acpi_serial("snps,dw-apb-uart", &spcr->base_address, 0x100); + break; + case SPCR_ARM_PL011: + case SPCR_ARM_SBSA: + efi_acpi_serial("arm,pl011", &spcr->base_address, 0x1000); + break; + default: + return; + } + serial = 1; +} + +void +efi_acpi_dbg2(struct acpi_table_header *hdr) +{ + struct acpi_dbg2 *dbg2 = (struct acpi_dbg2 *)hdr; + struct acpi_dbg2_info *info; + struct acpi_gas *base_address; + uint32_t address_size; + + info = (struct acpi_dbg2_info *)((char *)hdr + dbg2->info_offset); + + /* Only looking for serial ports. */ + if (info->port_type != DBG2_SERIAL) + return; + + base_address = (struct acpi_gas *) + ((char *)info + info->base_address_offset); + address_size = *(uint32_t *) + ((char *)info + info->address_size_offset); + + switch (info->port_subtype) { + case DBG2_16550: + case DBG2_16450: + efi_acpi_serial("snps,dw-apb-uart", base_address, address_size); + break; + case DBG2_ARM_PL011: + case DBG2_ARM_SBSA: + efi_acpi_serial("arm,pl011", base_address, address_size); + break; + default: + return; + } +} + +void * +efi_acpi(void) +{ + extern uint64_t dma_constraint[2]; + extern u_char dt_blob_start[]; + void *fdt = dt_blob_start; + struct acpi_table_header *hdr; + struct acpi_rsdp *rsdp = NULL; + struct acpi_xsdt *xsdt; + uint64_t reg[2]; + int i, ntables; + size_t len; + void *node; + + for (i = 0; i < ST->NumberOfTableEntries; i++) { + if (efi_guidcmp(&acpi_guid, + &ST->ConfigurationTable[i].VendorGuid) == 0) + rsdp = ST->ConfigurationTable[i].VendorTable; + } + + if (rsdp == NULL) + return NULL; + + if (memcmp(rsdp->rsdp_signature, RSDP_SIG, 8) != 0 || + rsdp->rsdp_revision < 2) + return NULL; + + xsdt = (struct acpi_xsdt *)rsdp->rsdp_xsdt; + len = xsdt->hdr.length; + ntables = (len - sizeof(struct acpi_table_header)) / + sizeof(xsdt->table_offsets[0]); + if (ntables == 0) + return NULL; + + if (!fdt_init(fdt)) + return NULL; + + for (i = 0; i < ntables; i++) { + hdr = (struct acpi_table_header *)xsdt->table_offsets[i]; + printf("%c%c%c%c ", hdr->signature[0], hdr->signature[1], + hdr->signature[2], hdr->signature[3]); + if (memcmp(hdr->signature, FADT_SIG, 4) == 0) + efi_acpi_fadt(hdr); + if (memcmp(hdr->signature, GTDT_SIG, 4) == 0) + efi_acpi_gtdt(hdr); + if (memcmp(hdr->signature, MADT_SIG, 4) == 0) + efi_acpi_madt(hdr); + if (memcmp(hdr->signature, SPCR_SIG, 4) == 0) + efi_acpi_spcr(hdr); + } + printf("\n"); + + for (i = 0; i < ntables; i++) { + hdr = (struct acpi_table_header *)xsdt->table_offsets[i]; + if (memcmp(hdr->signature, DBG2_SIG, 4) == 0 && !serial) + efi_acpi_dbg2(hdr); + } + + reg[0] = htobe64((uint64_t)rsdp); + reg[1] = htobe64(rsdp->rsdp_length); + + /* Update "acpi" node. */ + node = fdt_find_node("/acpi"); + fdt_node_set_property(node, "reg", reg, sizeof(reg)); + + /* Use framebuffer if SPCR is absent or unusable. */ + if (!serial) + cnset(ttydev("fb0")); + + /* Raspberry Pi 4 is "special". */ + if (memcmp(xsdt->hdr_oemid, "RPIFDN", 6) == 0 && + memcmp(xsdt->hdr_oemtableid, "RPI4", 4) == 0) + dma_constraint[1] = htobe64(0x3bffffff); + + fdt_finalize(); + + return fdt; +} diff --git sys/arch/loongarch64/stand/efiboot/efiboot.c sys/arch/loongarch64/stand/efiboot/efiboot.c new file mode 100644 index 00000000000..c8aeaea2750 --- /dev/null +++ sys/arch/loongarch64/stand/efiboot/efiboot.c @@ -0,0 +1,1160 @@ +/* $OpenBSD: efiboot.c,v 1.16 2026/07/19 12:04:08 kettenis Exp $ */ + +/* + * Copyright (c) 2015 YASUOKA Masahiko + * Copyright (c) 2016 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "libsa.h" +#include "disk.h" +#include "softraid_loongarch64.h" + +#include "efidev.h" +#include "efiboot.h" +#include "efidt.h" +#include "fdt.h" + +EFI_SYSTEM_TABLE *ST; +EFI_BOOT_SERVICES *BS; +EFI_RUNTIME_SERVICES *RS; +EFI_HANDLE IH, efi_bootdp; +void *fdt_sys = NULL; +void *fdt_override = NULL; +size_t fdt_override_size; + +EFI_PHYSICAL_ADDRESS heap; +UINTN heapsiz = 1 * 1024 * 1024; +EFI_MEMORY_DESCRIPTOR *mmap; +UINTN mmap_key; +UINTN mmap_ndesc; +UINTN mmap_descsiz; +UINT32 mmap_version; + +static EFI_GUID imgp_guid = LOADED_IMAGE_PROTOCOL; +static EFI_GUID blkio_guid = BLOCK_IO_PROTOCOL; +static EFI_GUID devp_guid = DEVICE_PATH_PROTOCOL; +static EFI_GUID gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; +static EFI_GUID fdt_guid = FDT_TABLE_GUID; +static EFI_GUID dt_fixup_guid = EFI_DT_FIXUP_PROTOCOL_GUID; + +#define efi_guidcmp(_a, _b) memcmp((_a), (_b), sizeof(EFI_GUID)) + +int efi_device_path_depth(EFI_DEVICE_PATH *dp, int); +int efi_device_path_ncmp(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *, int); +static void efi_heap_init(void); +static void efi_memprobe_internal(void); +static void efi_timer_init(void); +static void efi_timer_cleanup(void); +static EFI_STATUS efi_memprobe_find(UINTN, UINTN, EFI_PHYSICAL_ADDRESS *); +void *efi_fdt(void); +int fdt_load_override(char *); + +EFI_STATUS +efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) +{ + extern char *progname; + EFI_LOADED_IMAGE *imgp; + EFI_DEVICE_PATH *dp = NULL; + EFI_STATUS status; + int i; + + ST = systab; + BS = ST->BootServices; + RS = ST->RuntimeServices; + IH = image; + + /* disable reset by watchdog after 5 minutes */ + BS->SetWatchdogTimer(0, 0, 0, NULL); + + status = BS->HandleProtocol(image, &imgp_guid, (void **)&imgp); + if (status == EFI_SUCCESS) + status = BS->HandleProtocol(imgp->DeviceHandle, &devp_guid, + (void **)&dp); + if (status == EFI_SUCCESS) + efi_bootdp = dp; + + for (i = 0; i < ST->NumberOfTableEntries; i++) { + if (efi_guidcmp(&fdt_guid, + &ST->ConfigurationTable[i].VendorGuid) == 0) + fdt_sys = ST->ConfigurationTable[i].VendorTable; + } + fdt_init(fdt_sys); + + progname = "BOOTLOONGARCH64"; + + boot(0); + + return (EFI_SUCCESS); +} + +static SIMPLE_TEXT_OUTPUT_INTERFACE *conout; +static SIMPLE_INPUT_INTERFACE *conin; + +/* + * The device majors for these don't match the ones used by the + * kernel. That's fine. They're just used as an index into the cdevs + * array and never passed on to the kernel. + */ +static dev_t serial = makedev(0, 0); +static dev_t framebuffer = makedev(1, 0); + +static char framebuffer_path[128]; + +void +efi_cons_probe(struct consdev *cn) +{ + cn->cn_pri = CN_MIDPRI; + cn->cn_dev = serial; +} + +void +efi_cons_init(struct consdev *cp) +{ + conin = ST->ConIn; + conout = ST->ConOut; +} + +int +efi_cons_getc(dev_t dev) +{ + EFI_INPUT_KEY key; + EFI_STATUS status; +#if 0 + UINTN dummy; +#endif + static int lastchar = 0; + + if (lastchar) { + int r = lastchar; + if ((dev & 0x80) == 0) + lastchar = 0; + return (r); + } + + status = conin->ReadKeyStroke(conin, &key); + while (status == EFI_NOT_READY || key.UnicodeChar == 0) { + if (dev & 0x80) + return (0); + /* + * XXX The implementation of WaitForEvent() in U-boot + * is broken and neverreturns. + */ +#if 0 + BS->WaitForEvent(1, &conin->WaitForKey, &dummy); +#endif + status = conin->ReadKeyStroke(conin, &key); + } + + if (dev & 0x80) + lastchar = key.UnicodeChar; + + return (key.UnicodeChar); +} + +void +efi_cons_putc(dev_t dev, int c) +{ + CHAR16 buf[2]; + + if (c == '\n') + efi_cons_putc(dev, '\r'); + + buf[0] = c; + buf[1] = 0; + + conout->OutputString(conout, buf); +} + +void +efi_fb_probe(struct consdev *cn) +{ + cn->cn_pri = CN_LOWPRI; + cn->cn_dev = framebuffer; +} + +void +efi_fb_init(struct consdev *cn) +{ + conin = ST->ConIn; + conout = ST->ConOut; +} + +int +efi_fb_getc(dev_t dev) +{ + return efi_cons_getc(dev); +} + +void +efi_fb_putc(dev_t dev, int c) +{ + efi_cons_putc(dev, c); +} + +static void +efi_heap_init(void) +{ + EFI_STATUS status; + + status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, + EFI_SIZE_TO_PAGES(heapsiz), &heap); + if (status != EFI_SUCCESS) + panic("BS->AllocatePages()"); +} + +struct disklist_lh disklist; +struct diskinfo *bootdev_dip; + +void +efi_diskprobe(void) +{ + int i, bootdev = 0, depth = -1; + UINTN sz; + EFI_STATUS status; + EFI_HANDLE *handles = NULL; + EFI_BLOCK_IO *blkio; + EFI_BLOCK_IO_MEDIA *media; + struct diskinfo *di; + EFI_DEVICE_PATH *dp; + + TAILQ_INIT(&disklist); + + sz = 0; + status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, 0); + if (status == EFI_BUFFER_TOO_SMALL) { + handles = alloc(sz); + status = BS->LocateHandle(ByProtocol, &blkio_guid, 0, &sz, + handles); + } + if (handles == NULL || EFI_ERROR(status)) + return; + + if (efi_bootdp != NULL) + depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH); + + /* + * U-Boot incorrectly represents devices with a single + * MEDIA_DEVICE_PATH component. In that case include that + * component into the matching, otherwise we'll blindly select + * the first device. + */ + if (depth == 0) + depth = 1; + + for (i = 0; i < sz / sizeof(EFI_HANDLE); i++) { + status = BS->HandleProtocol(handles[i], &blkio_guid, + (void **)&blkio); + if (EFI_ERROR(status)) + panic("BS->HandleProtocol() returns %d", status); + + media = blkio->Media; + if (media->LogicalPartition || !media->MediaPresent) + continue; + di = alloc(sizeof(struct diskinfo)); + efid_init(di, blkio); + + if (efi_bootdp == NULL || depth == -1 || bootdev != 0) + goto next; + status = BS->HandleProtocol(handles[i], &devp_guid, + (void **)&dp); + if (EFI_ERROR(status)) + goto next; + if (efi_device_path_ncmp(efi_bootdp, dp, depth) == 0) { + TAILQ_INSERT_HEAD(&disklist, di, list); + bootdev_dip = di; + bootdev = 1; + continue; + } +next: + TAILQ_INSERT_TAIL(&disklist, di, list); + } + + free(handles, sz); + + /* Print available disks and probe for softraid. */ + i = 0; + printf("disks:"); + TAILQ_FOREACH(di, &disklist, list) { + printf(" sd%d%s", i, di == bootdev_dip ? "*" : ""); + i++; + } + srprobe(); + printf("\n"); +} + +/* + * Determine the number of nodes up to, but not including, the first + * node of the specified type. + */ +int +efi_device_path_depth(EFI_DEVICE_PATH *dp, int dptype) +{ + int i; + + for (i = 0; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp), i++) { + if (DevicePathType(dp) == dptype) + return (i); + } + + return (i); +} + +int +efi_device_path_ncmp(EFI_DEVICE_PATH *dpa, EFI_DEVICE_PATH *dpb, int deptn) +{ + int i, cmp; + + for (i = 0; i < deptn; i++) { + if (IsDevicePathEnd(dpa) || IsDevicePathEnd(dpb)) + return ((IsDevicePathEnd(dpa) && IsDevicePathEnd(dpb)) + ? 0 : (IsDevicePathEnd(dpa))? -1 : 1); + cmp = DevicePathNodeLength(dpa) - DevicePathNodeLength(dpb); + if (cmp) + return (cmp); + cmp = memcmp(dpa, dpb, DevicePathNodeLength(dpa)); + if (cmp) + return (cmp); + dpa = NextDevicePathNode(dpa); + dpb = NextDevicePathNode(dpb); + } + + return (0); +} + +void +efi_framebuffer(void) +{ + EFI_GRAPHICS_OUTPUT *gop; + EFI_STATUS status; + void *node, *child; + uint32_t acells, scells; + uint64_t base, size; + uint32_t reg[4]; + uint32_t width, height, stride; + char *format; + char *prop; + + /* + * Don't create a "simple-framebuffer" node if we already have + * one. Besides "/chosen", we also check under "/" since that + * is where the Raspberry Pi firmware puts it. + */ + node = fdt_find_node("/chosen"); + for (child = fdt_child_node(node); child; + child = fdt_next_node(child)) { + if (!fdt_node_is_compatible(child, "simple-framebuffer")) + continue; + if (!fdt_node_property(child, "status", &prop) || + strcmp(prop, "okay") == 0) { + strlcpy(framebuffer_path, "/chosen/", + sizeof(framebuffer_path)); + strlcat(framebuffer_path, fdt_node_name(child), + sizeof(framebuffer_path)); + return; + } + } + node = fdt_find_node("/"); + for (child = fdt_child_node(node); child; + child = fdt_next_node(child)) { + if (!fdt_node_is_compatible(child, "simple-framebuffer")) + continue; + if (!fdt_node_property(child, "status", &prop) || + strcmp(prop, "okay") == 0) { + strlcpy(framebuffer_path, "/", + sizeof(framebuffer_path)); + strlcat(framebuffer_path, fdt_node_name(child), + sizeof(framebuffer_path)); + return; + } + } + + status = BS->LocateProtocol(&gop_guid, NULL, (void **)&gop); + if (status != EFI_SUCCESS) + return; + + /* Paranoia! */ + if (gop == NULL || gop->Mode == NULL || gop->Mode->Info == NULL) + return; + + /* We only support 32-bit pixel modes for now. */ + switch (gop->Mode->Info->PixelFormat) { + case PixelRedGreenBlueReserved8BitPerColor: + format = "x8b8g8r8"; + break; + case PixelBlueGreenRedReserved8BitPerColor: + format = "x8r8g8b8"; + break; + default: + return; + } + + base = gop->Mode->FrameBufferBase; + size = gop->Mode->FrameBufferSize; + width = htobe32(gop->Mode->Info->HorizontalResolution); + height = htobe32(gop->Mode->Info->VerticalResolution); + stride = htobe32(gop->Mode->Info->PixelsPerScanLine * 4); + + node = fdt_find_node("/"); + if (fdt_node_property_int(node, "#address-cells", &acells) != 1) + acells = 1; + if (fdt_node_property_int(node, "#size-cells", &scells) != 1) + scells = 1; + if (acells > 2 || scells > 2) + return; + if (acells >= 1) + reg[0] = htobe32(base); + if (acells == 2) { + reg[1] = reg[0]; + reg[0] = htobe32(base >> 32); + } + if (scells >= 1) + reg[acells] = htobe32(size); + if (scells == 2) { + reg[acells + 1] = reg[acells]; + reg[acells] = htobe32(size >> 32); + } + + node = fdt_find_node("/chosen"); + fdt_node_add_node(node, "framebuffer", &child); + fdt_node_add_property(child, "status", "okay", strlen("okay") + 1); + fdt_node_add_property(child, "format", format, strlen(format) + 1); + fdt_node_add_property(child, "stride", &stride, 4); + fdt_node_add_property(child, "height", &height, 4); + fdt_node_add_property(child, "width", &width, 4); + fdt_node_add_property(child, "reg", reg, (acells + scells) * 4); + fdt_node_add_property(child, "compatible", + "simple-framebuffer", strlen("simple-framebuffer") + 1); + + strlcpy(framebuffer_path, "/chosen/framebuffer", + sizeof(framebuffer_path)); +} + +void +efi_console(void) +{ + void *node; + + if (cn_tab->cn_dev != framebuffer) + return; + + if (strlen(framebuffer_path) == 0) + return; + + /* Point stdout-path at the framebuffer node. */ + node = fdt_find_node("/chosen"); + fdt_node_add_property(node, "stdout-path", + framebuffer_path, strlen(framebuffer_path) + 1); +} + +uint64_t dma_constraint[2] = { 0, -1 }; + +void +efi_dma_constraint(void) +{ + void *node; + + /* + * SpacemiT K1 and StarFive JH71x0 have peripherals that only + * support 32-bit DMA. + */ + node = fdt_find_node("/"); + if (fdt_node_is_compatible(node, "spacemit,k1") || + fdt_node_is_compatible(node, "starfive,jh7100") || + fdt_node_is_compatible(node, "starfive,jh7110")) + dma_constraint[1] = htobe64(0xffffffff); + + /* Pass DMA constraint. */ + node = fdt_find_node("/chosen"); + fdt_node_add_property(node, "openbsd,dma-constraint", + dma_constraint, sizeof(dma_constraint)); +} + +int acpi = 0; +char *bootmac = NULL; + +void * +efi_makebootargs(char *bootargs, int howto) +{ + struct sr_boot_volume *bv; + u_char bootduid[8]; + u_char zero[8] = { 0 }; + uint64_t uefi_system_table = htobe64((uintptr_t)ST); + uint32_t boothowto = htobe32(howto); + int32_t hartid; + EFI_PHYSICAL_ADDRESS addr; + void *node, *fdt; + size_t len; + + fdt = efi_fdt(); + if (fdt == NULL || acpi) + fdt = efi_acpi(); + + if (!fdt_get_size(fdt)) + return NULL; + + len = roundup(fdt_get_size(fdt) + PAGE_SIZE, PAGE_SIZE); + if (BS->AllocatePages(AllocateAnyPages, EfiLoaderData, + EFI_SIZE_TO_PAGES(len), &addr) == EFI_SUCCESS) { + memcpy((void *)addr, fdt, fdt_get_size(fdt)); + ((struct fdt_head *)addr)->fh_size = htobe32(len); + fdt = (void *)addr; + } + + if (!fdt_init(fdt)) + return NULL; + + /* Create common nodes which might not exist when using mach dtb */ + node = fdt_find_node("/aliases"); + if (node == NULL) + fdt_node_add_node(fdt_find_node("/"), "aliases", &node); + node = fdt_find_node("/chosen"); + if (node == NULL) + fdt_node_add_node(fdt_find_node("/"), "chosen", &node); + + node = fdt_find_node("/chosen"); + hartid = efi_get_boot_hart_id(); + if (hartid >= 0) { + hartid = htobe32(hartid); + fdt_node_add_property(node, "boot-hartid", &hartid, 4); + } + + len = strlen(bootargs) + 1; + fdt_node_add_property(node, "bootargs", bootargs, len); + fdt_node_add_property(node, "openbsd,boothowto", + &boothowto, sizeof(boothowto)); + + /* Pass DUID of the boot disk. */ + if (bootdev_dip) { + memcpy(&bootduid, bootdev_dip->disklabel.d_uid, + sizeof(bootduid)); + if (memcmp(bootduid, zero, sizeof(bootduid)) != 0) { + fdt_node_add_property(node, "openbsd,bootduid", + bootduid, sizeof(bootduid)); + } + + if (bootdev_dip->sr_vol != NULL) { + bv = bootdev_dip->sr_vol; + fdt_node_add_property(node, "openbsd,sr-bootuuid", + &bv->sbv_uuid, sizeof(bv->sbv_uuid)); + if (bv->sbv_maskkey != NULL) + fdt_node_add_property(node, + "openbsd,sr-bootkey", bv->sbv_maskkey, + SR_CRYPTO_MAXKEYBYTES); + } + } + + sr_clear_keys(); + + /* Pass netboot interface address. */ + if (bootmac) + fdt_node_add_property(node, "openbsd,bootmac", bootmac, 6); + + /* Pass EFI system table. */ + fdt_node_add_property(node, "openbsd,uefi-system-table", + &uefi_system_table, sizeof(uefi_system_table)); + + /* Placeholders for EFI memory map. */ + fdt_node_add_property(node, "openbsd,uefi-mmap-start", zero, 8); + fdt_node_add_property(node, "openbsd,uefi-mmap-size", zero, 4); + fdt_node_add_property(node, "openbsd,uefi-mmap-desc-size", zero, 4); + fdt_node_add_property(node, "openbsd,uefi-mmap-desc-ver", zero, 4); + + efi_framebuffer(); + efi_console(); + efi_dma_constraint(); + + fdt_finalize(); + + return fdt; +} + +void +efi_updatefdt(void) +{ + uint64_t uefi_mmap_start = htobe64((uintptr_t)mmap); + uint32_t uefi_mmap_size = htobe32(mmap_ndesc * mmap_descsiz); + uint32_t uefi_mmap_desc_size = htobe32(mmap_descsiz); + uint32_t uefi_mmap_desc_ver = htobe32(mmap_version); + void *node; + + node = fdt_find_node("/chosen"); + if (!node) + return; + + /* Pass EFI memory map. */ + fdt_node_set_property(node, "openbsd,uefi-mmap-start", + &uefi_mmap_start, sizeof(uefi_mmap_start)); + fdt_node_set_property(node, "openbsd,uefi-mmap-size", + &uefi_mmap_size, sizeof(uefi_mmap_size)); + fdt_node_set_property(node, "openbsd,uefi-mmap-desc-size", + &uefi_mmap_desc_size, sizeof(uefi_mmap_desc_size)); + fdt_node_set_property(node, "openbsd,uefi-mmap-desc-ver", + &uefi_mmap_desc_ver, sizeof(uefi_mmap_desc_ver)); + + fdt_finalize(); +} + +u_long efi_loadaddr; + +void +machdep(void) +{ + EFI_PHYSICAL_ADDRESS addr; + + cninit(); + efi_heap_init(); + + /* + * The kernel expects to be loaded into a block of memory aligned + * on a 2MB boundary. We allocate a block of 64MB of memory, which + * gives us plenty of room for growth. + */ + if (efi_memprobe_find(EFI_SIZE_TO_PAGES(64 * 1024 * 1024), + 0x200000, &addr) != EFI_SUCCESS) + printf("Can't allocate memory\n"); + efi_loadaddr = addr; + + efi_timer_init(); + efi_diskprobe(); + efi_pxeprobe(); +} + +void +efi_cleanup(void) +{ + int retry; + EFI_STATUS status; + + efi_timer_cleanup(); + + /* retry once in case of failure */ + for (retry = 1; retry >= 0; retry--) { + efi_memprobe_internal(); /* sync the current map */ + efi_updatefdt(); + status = BS->ExitBootServices(IH, mmap_key); + if (status == EFI_SUCCESS) + break; + if (retry == 0) + panic("ExitBootServices failed (%d)", status); + } +} + +void +_rtt(void) +{ +#ifdef EFI_DEBUG + printf("Hit any key to reboot\n"); + efi_cons_getc(0); +#endif + RS->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); + for (;;) + continue; +} + +/* + * U-Boot only implements the GetTime() Runtime Service if it has been + * configured with CONFIG_DM_RTC. Most board configurations don't + * include that option, so we can't use it to implement our boot + * prompt timeout. Instead we use timer events to simulate a clock + * that ticks ever second. + */ + +EFI_EVENT timer; +int ticks; + +static VOID +efi_timer(EFI_EVENT event, VOID *context) +{ + ticks++; +} + +static void +efi_timer_init(void) +{ + EFI_STATUS status; + + status = BS->CreateEvent(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, + efi_timer, NULL, &timer); + if (status == EFI_SUCCESS) + status = BS->SetTimer(timer, TimerPeriodic, 10000000); + if (EFI_ERROR(status)) + printf("Can't create timer\n"); +} + +static void +efi_timer_cleanup(void) +{ + BS->CloseEvent(timer); +} + +time_t +getsecs(void) +{ + return ticks; +} + +/* + * Various device-related bits. + */ + +void +devboot(dev_t dev, char *p) +{ + struct sr_boot_volume *bv; + struct sr_boot_chunk *bc; + struct diskinfo *dip; + int sd_boot_vol = 0; + int sr_boot_vol = -1; + int part_type = FS_UNUSED; + + if (bootdev_dip == NULL) { + strlcpy(p, "tftp0a", 7); + return; + } + + TAILQ_FOREACH(dip, &disklist, list) { + if (bootdev_dip == dip) + break; + sd_boot_vol++; + } + + /* + * Determine the partition type for the 'a' partition of the + * boot device. + */ + if ((bootdev_dip->flags & DISKINFO_FLAG_GOODLABEL) != 0) + part_type = bootdev_dip->disklabel.d_partitions[0].p_fstype; + + /* + * See if we booted from a disk that is a member of a bootable + * softraid volume. + */ + SLIST_FOREACH(bv, &sr_volumes, sbv_link) { + SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) + if (bc->sbc_diskinfo == bootdev_dip) + sr_boot_vol = bv->sbv_unit; + if (sr_boot_vol != -1) + break; + } + + if (sr_boot_vol != -1 && part_type != FS_BSDFFS) { + strlcpy(p, "sr0a", 5); + p[2] = '0' + sr_boot_vol; + return; + } + + strlcpy(p, "sd0a", 5); + p[2] = '0' + sd_boot_vol; +} + +const char cdevs[][4] = { "com", "fb" }; +const int ncdevs = nitems(cdevs); + +int +cnspeed(dev_t dev, int sp) +{ + return 115200; +} + +char ttyname_buf[8]; + +char * +ttyname(int fd) +{ + snprintf(ttyname_buf, sizeof ttyname_buf, "%s%d", + cdevs[major(cn_tab->cn_dev)], minor(cn_tab->cn_dev)); + + return ttyname_buf; +} + +dev_t +ttydev(char *name) +{ + int i, unit = -1; + char *no = name + strlen(name) - 1; + + while (no >= name && *no >= '0' && *no <= '9') + unit = (unit < 0 ? 0 : (unit * 10)) + *no-- - '0'; + if (no < name || unit < 0) + return NODEV; + for (i = 0; i < ncdevs; i++) + if (strncmp(name, cdevs[i], no - name + 1) == 0) + return makedev(i, unit); + return NODEV; +} + +#define MAXDEVNAME 16 + +/* + * Parse a device spec. + * + * [A-Za-z]*[0-9]*[A-Za-z]:file + * dev uint part + */ +int +devparse(const char *fname, int *dev, int *unit, int *part, const char **file) +{ + const char *s; + + *unit = 0; /* default to wd0a */ + *part = 0; + *dev = 0; + + s = strchr(fname, ':'); + if (s != NULL) { + int devlen; + int i, u, p = 0; + struct devsw *dp; + char devname[MAXDEVNAME]; + + devlen = s - fname; + if (devlen > MAXDEVNAME) + return (EINVAL); + + /* extract device name */ + for (i = 0; isalpha(fname[i]) && (i < devlen); i++) + devname[i] = fname[i]; + devname[i] = 0; + + if (!isdigit(fname[i])) + return (EUNIT); + + /* device number */ + for (u = 0; isdigit(fname[i]) && (i < devlen); i++) + u = u * 10 + (fname[i] - '0'); + + if (!isalpha(fname[i])) + return (EPART); + + /* partition number */ + if (i < devlen) + p = DL_PARTNAME2NUM(fname[i++]); + + if (i != devlen) + return (ENXIO); + + /* check device name */ + for (dp = devsw, i = 0; i < ndevs; dp++, i++) { + if (dp->dv_name && !strcmp(devname, dp->dv_name)) + break; + } + + if (i >= ndevs) + return (ENXIO); + + *unit = u; + *part = p; + *dev = i; + fname = ++s; + } + + *file = fname; + + return (0); +} + +int +devopen(struct open_file *f, const char *fname, char **file) +{ + struct devsw *dp; + int dev, unit, part, error; + + error = devparse(fname, &dev, &unit, &part, (const char **)file); + if (error) + return (error); + + dp = &devsw[dev]; + f->f_dev = dp; + + if (strcmp("tftp", dp->dv_name) != 0) { + /* + * Clear bootmac, to signal that we loaded this file from a + * non-network device. + */ + bootmac = NULL; + } + + return (*dp->dv_open)(f, unit, part); +} + +static void +efi_memprobe_internal(void) +{ + EFI_STATUS status; + UINTN mapkey, mmsiz, siz; + UINT32 mmver; + EFI_MEMORY_DESCRIPTOR *mm; + int n; + + free(mmap, mmap_ndesc * mmap_descsiz); + + siz = 0; + status = BS->GetMemoryMap(&siz, NULL, &mapkey, &mmsiz, &mmver); + if (status != EFI_BUFFER_TOO_SMALL) + panic("cannot get the size of memory map"); + mm = alloc(siz); + status = BS->GetMemoryMap(&siz, mm, &mapkey, &mmsiz, &mmver); + if (status != EFI_SUCCESS) + panic("cannot get the memory map"); + n = siz / mmsiz; + mmap = mm; + mmap_key = mapkey; + mmap_ndesc = n; + mmap_descsiz = mmsiz; + mmap_version = mmver; +} + +/* + * 64-bit ARMs can have a much wider memory mapping, as in somewhere + * after the 32-bit region. To cope with our alignment requirement, + * use the memory table to find a place where we can fit. + */ +static EFI_STATUS +efi_memprobe_find(UINTN pages, UINTN align, EFI_PHYSICAL_ADDRESS *addr) +{ + EFI_MEMORY_DESCRIPTOR *mm; + int i, j; + + if (align < EFI_PAGE_SIZE) + return EFI_INVALID_PARAMETER; + + efi_memprobe_internal(); /* sync the current map */ + + for (i = 0, mm = mmap; i < mmap_ndesc; + i++, mm = NextMemoryDescriptor(mm, mmap_descsiz)) { + if (mm->Type != EfiConventionalMemory) + continue; + + if (mm->NumberOfPages < pages) + continue; + + for (j = 0; j < mm->NumberOfPages; j++) { + EFI_PHYSICAL_ADDRESS paddr; + + if (mm->NumberOfPages - j < pages) + break; + + paddr = mm->PhysicalStart + (j * EFI_PAGE_SIZE); + if (paddr & (align - 1)) + continue; + + if (BS->AllocatePages(AllocateAddress, EfiLoaderData, + pages, &paddr) == EFI_SUCCESS) { + *addr = paddr; + return EFI_SUCCESS; + } + } + } + return EFI_OUT_OF_RESOURCES; +} + +#define FW_PATH "/etc/firmware/dtb/" + +struct fdt_dtb { + const char *model; + const char *dtb; +} fdt_dtb[] = { + /* Keep the list below sorted alphabetically */ + { "ky x1 orangepi-rv2 board", + "spacemit/k1-orangepi-rv2.dtb" }, + { "Milk-V Jupiter", + "spacemit/k1-milkv-jupiter.dtb" }, + { "Milk-V(M1) Jupiter", + "spacemit/k1-milkv-jupiter.dtb" }, + { "spacemit k1-x deb1 board", + "spacemit/k1-bananapi-f3.dtb" }, + { "spacemit k1-x evb board", + "spacemit/k1-milkv-jupiter.dtb" }, + { "spacemit k3-pico-itx board", + "spacemit/k3-pico-itx.dtb" }, +}; + +void * +efi_fdt(void) +{ + void *node; + char *model = NULL; + size_t modellen; + char dtb[256]; + int i; + + /* 'mach dtb' has precedence */ + if (fdt_override != NULL) + return fdt_override; + + node = fdt_find_node("/"); + fdt_node_property(node, "model", &model); + + /* Return system provided one */ + if (model == NULL) + return fdt_sys; + + for (i = 0; i < nitems(fdt_dtb); i++) { + modellen = strlen(fdt_dtb[i].model); + if (strncmp(model, fdt_dtb[i].model, modellen) == 0) { + snprintf(dtb, sizeof(dtb), "%s%s", FW_PATH, + fdt_dtb[i].dtb); + fdt_load_override(dtb); + break; + } + } + + return fdt_override ? fdt_override : fdt_sys; +} + +int +fdt_load_override(char *file) +{ + EFI_DT_FIXUP_PROTOCOL *dt_fixup; + EFI_PHYSICAL_ADDRESS addr; + char path[MAXPATHLEN]; + EFI_STATUS status; + struct stat sb; + size_t dt_size; + UINTN sz; + int fd; + + if (file == NULL && fdt_override) { + BS->FreePages((uint64_t)fdt_override, + EFI_SIZE_TO_PAGES(fdt_override_size)); + fdt_override = NULL; + fdt_init(fdt_sys); + return 0; + } + + snprintf(path, sizeof(path), "%s:%s", cmd.bootdev, file); + + fd = open(path, O_RDONLY); + if (fd < 0 || fstat(fd, &sb) == -1) { + printf("cannot open %s\n", path); + return 0; + } + dt_size = sb.st_size; +retry: + if (efi_memprobe_find(EFI_SIZE_TO_PAGES(dt_size), + PAGE_SIZE, &addr) != EFI_SUCCESS) { + printf("cannot allocate memory for %s\n", path); + return 0; + } + if (read(fd, (void *)addr, sb.st_size) != sb.st_size) { + printf("cannot read from %s\n", path); + return 0; + } + + status = BS->LocateProtocol(&dt_fixup_guid, NULL, (void **)&dt_fixup); + if (status == EFI_SUCCESS) { + sz = dt_size; + status = dt_fixup->Fixup(dt_fixup, (void *)addr, &sz, + EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY); + if (status == EFI_BUFFER_TOO_SMALL) { + BS->FreePages(addr, EFI_SIZE_TO_PAGES(dt_size)); + lseek(fd, 0, SEEK_SET); + dt_size = sz; + goto retry; + } + if (status != EFI_SUCCESS) + panic("DT fixup failed: 0x%lx", status); + } + + if (!fdt_init((void *)addr)) { + printf("invalid device tree\n"); + BS->FreePages(addr, EFI_SIZE_TO_PAGES(dt_size)); + return 0; + } + + if (fdt_override) { + BS->FreePages((uint64_t)fdt_override, + EFI_SIZE_TO_PAGES(fdt_override_size)); + fdt_override = NULL; + } + + fdt_override = (void *)addr; + fdt_override_size = dt_size; + return 0; +} + +/* + * Commands + */ + +int Xacpi_efi(void); +int Xdtb_efi(void); +int Xexit_efi(void); +int Xpoweroff_efi(void); + +const struct cmd_table cmd_machine[] = { + { "acpi", CMDT_CMD, Xacpi_efi }, + { "dtb", CMDT_CMD, Xdtb_efi }, + { "exit", CMDT_CMD, Xexit_efi }, + { "poweroff", CMDT_CMD, Xpoweroff_efi }, + { NULL, 0 } +}; + +int +Xacpi_efi(void) +{ + acpi = 1; + return (0); +} + +int +Xdtb_efi(void) +{ + if (cmd.argc == 1) { + fdt_load_override(NULL); + return (0); + } + + if (cmd.argc != 2) { + printf("dtb file\n"); + return (0); + } + + return fdt_load_override(cmd.argv[1]); +} + +int +Xexit_efi(void) +{ + BS->Exit(IH, 0, 0, NULL); + for (;;) + continue; + return (0); +} + +int +Xpoweroff_efi(void) +{ + RS->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL); + return (0); +} diff --git sys/arch/loongarch64/stand/efiboot/efiboot.h sys/arch/loongarch64/stand/efiboot/efiboot.h new file mode 100644 index 00000000000..1dd3b5bf48b --- /dev/null +++ sys/arch/loongarch64/stand/efiboot/efiboot.h @@ -0,0 +1,33 @@ +/* $OpenBSD: efiboot.h,v 1.2 2024/03/26 22:26:04 kettenis Exp $ */ + +/* + * Copyright (c) 2015 YASUOKA Masahiko + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +void *efi_acpi(void); +void efi_cleanup(void); +void efi_diskprobe(void); +void efi_pxeprobe(void); +void *efi_makebootargs(char *, int); +void efi_cons_probe(struct consdev *); +void efi_cons_init(struct consdev *); +int efi_cons_getc(dev_t); +void efi_cons_putc(dev_t, int); +void efi_fb_probe(struct consdev *); +void efi_fb_init(struct consdev *); +int efi_fb_getc(dev_t); +void efi_fb_putc(dev_t, int); + +int32_t efi_get_boot_hart_id(void); diff --git sys/arch/loongarch64/stand/efiboot/efidev.c sys/arch/loongarch64/stand/efiboot/efidev.c new file mode 100644 index 00000000000..db846fe8a48 --- /dev/null +++ sys/arch/loongarch64/stand/efiboot/efidev.c @@ -0,0 +1,558 @@ +/* $OpenBSD: efidev.c,v 1.5 2023/10/26 14:08:48 jsg Exp $ */ + +/* + * Copyright (c) 2015 YASUOKA Masahiko + * Copyright (c) 2016 Mark Kettenis + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +#include +#include +#include +#include +#include + +#include "libsa.h" + +#include + +extern EFI_BOOT_SERVICES *BS; + +extern int debug; + +#include "disk.h" +#include "efidev.h" + +#define EFI_BLKSPERSEC(_ed) ((_ed)->blkio->Media->BlockSize / DEV_BSIZE) +#define EFI_SECTOBLK(_ed, _n) ((_n) * EFI_BLKSPERSEC(_ed)) + +static EFI_STATUS + efid_io(int, efi_diskinfo_t, u_int, int, void *); +static int efid_diskio(int, struct diskinfo *, u_int, int, void *); +const char * efi_getdisklabel(efi_diskinfo_t, struct disklabel *); +static int efi_getdisklabel_cd9660(efi_diskinfo_t, struct disklabel *); +static u_int findopenbsd(efi_diskinfo_t, const char **); +static u_int findopenbsd_gpt(efi_diskinfo_t, const char **); +static int gpt_chk_mbr(struct dos_partition *, u_int64_t); + +void +efid_init(struct diskinfo *dip, void *handle) +{ + EFI_BLOCK_IO *blkio = handle; + + memset(dip, 0, sizeof(struct diskinfo)); + dip->ed.blkio = blkio; + dip->ed.mediaid = blkio->Media->MediaId; + dip->diskio = efid_diskio; + dip->strategy = efistrategy; + + if (efi_getdisklabel(&dip->ed, &dip->disklabel) == NULL) + dip->flags |= DISKINFO_FLAG_GOODLABEL; +} + +static EFI_STATUS +efid_io(int rw, efi_diskinfo_t ed, u_int off, int nsect, void *buf) +{ + u_int blks, start, end; + EFI_PHYSICAL_ADDRESS addr; + EFI_STATUS status; + caddr_t data; + size_t size; + + /* block count of the intrinsic block size in DEV_BSIZE */ + blks = EFI_BLKSPERSEC(ed); + if (blks == 0) + /* block size < 512. HP Stream 13 actually has such a disk. */ + return (EFI_UNSUPPORTED); + + start = off / blks; + end = (off + nsect + blks - 1) / blks; + size = (end - start) * ed->blkio->Media->BlockSize; + + status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, + EFI_SIZE_TO_PAGES(size), &addr); + if (EFI_ERROR(status)) + goto on_eio; + data = (caddr_t)(uintptr_t)addr; + + switch (rw) { + case F_READ: + status = ed->blkio->ReadBlocks(ed->blkio, ed->mediaid, start, + size, data); + if (EFI_ERROR(status)) + goto on_eio; + memcpy(buf, data + DEV_BSIZE * (off - start * blks), + DEV_BSIZE * nsect); + break; + case F_WRITE: + if (ed->blkio->Media->ReadOnly) + goto on_eio; + if (off % blks != 0 || nsect % blks != 0) { + status = ed->blkio->ReadBlocks(ed->blkio, ed->mediaid, + start, size, data); + if (EFI_ERROR(status)) + goto on_eio; + } + memcpy(data + DEV_BSIZE * (off - start * blks), buf, + DEV_BSIZE * nsect); + status = ed->blkio->WriteBlocks(ed->blkio, ed->mediaid, start, + size, data); + if (EFI_ERROR(status)) + goto on_eio; + break; + } + +on_eio: + BS->FreePages(addr, EFI_SIZE_TO_PAGES(size)); + + return (status); +} + +static int +efid_diskio(int rw, struct diskinfo *dip, u_int off, int nsect, void *buf) +{ + EFI_STATUS status; + + status = efid_io(rw, &dip->ed, off, nsect, buf); + + return ((EFI_ERROR(status))? -1 : 0); +} + +/* + * Returns 0 if the MBR with the provided partition array is a GPT protective + * MBR, and returns 1 otherwise. A GPT protective MBR would have one and only + * one MBR partition, an EFI partition that either covers the whole disk or as + * much of it as is possible with a 32bit size field. + * + * Taken from kern/subr_disk.c. + * + * NOTE: MS always uses a size of UINT32_MAX for the EFI partition!** + */ +static int +gpt_chk_mbr(struct dos_partition *dp, u_int64_t dsize) +{ + struct dos_partition *dp2; + int efi, found, i; + u_int32_t psize; + + found = efi = 0; + for (dp2=dp, i=0; i < NDOSPART; i++, dp2++) { + if (dp2->dp_typ == DOSPTYP_UNUSED) + continue; + found++; + if (dp2->dp_typ != DOSPTYP_EFI) + continue; + if (letoh32(dp2->dp_start) != GPTSECTOR) + continue; + psize = letoh32(dp2->dp_size); + if (psize <= (dsize - GPTSECTOR) || psize == UINT32_MAX) + efi++; + } + if (found == 1 && efi == 1) + return (0); + + return (1); +} + +/* + * Try to find the disk address of the first MBR OpenBSD partition. + * + * N.B.: must boot from a partition within first 2^32-1 sectors! + * + * Called only if the MBR on sector 0 is *not* a protective MBR + * and *does* have a valid signature. + * + * We don't check the signatures of EBR's, and they cannot be + * protective MBR's so there is no need to check for that. + */ +static u_int +findopenbsd(efi_diskinfo_t ed, const char **err) +{ + EFI_STATUS status; + struct dos_mbr mbr; + struct dos_partition *dp; + u_int mbroff = DOSBBSECTOR; + u_int mbr_eoff = DOSBBSECTOR; /* Offset of MBR extended partition. */ + int i, maxebr = DOS_MAXEBR, nextebr; + +again: + if (!maxebr--) { + *err = "too many extended partitions"; + return (-1); + } + + /* Read MBR */ + bzero(&mbr, sizeof(mbr)); + status = efid_io(F_READ, ed, mbroff, 1, &mbr); + if (EFI_ERROR(status)) { + *err = "Disk I/O Error"; + return (-1); + } + + /* Search for OpenBSD partition */ + nextebr = 0; + for (i = 0; i < NDOSPART; i++) { + dp = &mbr.dmbr_parts[i]; + if (!dp->dp_size) + continue; +#ifdef BIOS_DEBUG + if (debug) + printf("found partition %u: " + "type %u (0x%x) offset %u (0x%x)\n", + (int)(dp - mbr.dmbr_parts), + dp->dp_typ, dp->dp_typ, + dp->dp_start, dp->dp_start); +#endif + if (dp->dp_typ == DOSPTYP_OPENBSD) { + if (dp->dp_start > (dp->dp_start + mbroff)) + continue; + return (dp->dp_start + mbroff); + } + + /* + * Record location of next ebr if and only if this is the first + * extended partition in this boot record! + */ + if (!nextebr && (dp->dp_typ == DOSPTYP_EXTEND || + dp->dp_typ == DOSPTYP_EXTENDL)) { + nextebr = dp->dp_start + mbr_eoff; + if (nextebr < dp->dp_start) + nextebr = (u_int)-1; + if (mbr_eoff == DOSBBSECTOR) + mbr_eoff = dp->dp_start; + } + } + + if (nextebr && nextebr != (u_int)-1) { + mbroff = nextebr; + goto again; + } + + return (-1); +} + +/* + * Try to find the disk address of the first GPT OpenBSD partition. + * + * N.B.: must boot from a partition within first 2^32-1 sectors! + * + * Called only if the MBR on sector 0 *is* a protective MBR + * with a valid signature and sector 1 is a valid GPT header. + */ +static u_int +findopenbsd_gpt(efi_diskinfo_t ed, const char **err) +{ + EFI_STATUS status; + struct gpt_header gh; + int i, part, found; + uint64_t lba; + uint32_t orig_csum, new_csum; + uint32_t ghsize, ghpartsize, ghpartnum, ghpartspersec; + uint32_t gpsectors; + const char openbsd_uuid_code[] = GPT_UUID_OPENBSD; + struct gpt_partition gp; + static struct uuid *openbsd_uuid = NULL, openbsd_uuid_space; + static u_char buf[4096]; + + /* Prepare OpenBSD UUID */ + if (openbsd_uuid == NULL) { + /* XXX: should be replaced by uuid_dec_be() */ + memcpy(&openbsd_uuid_space, openbsd_uuid_code, + sizeof(openbsd_uuid_space)); + openbsd_uuid_space.time_low = + betoh32(openbsd_uuid_space.time_low); + openbsd_uuid_space.time_mid = + betoh16(openbsd_uuid_space.time_mid); + openbsd_uuid_space.time_hi_and_version = + betoh16(openbsd_uuid_space.time_hi_and_version); + + openbsd_uuid = &openbsd_uuid_space; + } + + if (EFI_BLKSPERSEC(ed) > 8) { + *err = "disk sector > 4096 bytes\n"; + return (-1); + } + + /* GPT Header */ + lba = GPTSECTOR; + status = efid_io(F_READ, ed, EFI_SECTOBLK(ed, lba), EFI_BLKSPERSEC(ed), + buf); + if (EFI_ERROR(status)) { + *err = "Disk I/O Error"; + return (-1); + } + memcpy(&gh, buf, sizeof(gh)); + + /* Check signature */ + if (letoh64(gh.gh_sig) != GPTSIGNATURE) { + *err = "bad GPT signature\n"; + return (-1); + } + + if (letoh32(gh.gh_rev) != GPTREVISION) { + *err = "bad GPT revision\n"; + return (-1); + } + + ghsize = letoh32(gh.gh_size); + if (ghsize < GPTMINHDRSIZE || ghsize > sizeof(struct gpt_header)) { + *err = "bad GPT header size\n"; + return (-1); + } + + /* Check checksum */ + orig_csum = gh.gh_csum; + gh.gh_csum = 0; + new_csum = crc32(0, (unsigned char *)&gh, ghsize); + gh.gh_csum = orig_csum; + if (letoh32(orig_csum) != new_csum) { + *err = "bad GPT header checksum\n"; + return (-1); + } + + lba = letoh64(gh.gh_part_lba); + ghpartsize = letoh32(gh.gh_part_size); + ghpartspersec = ed->blkio->Media->BlockSize / ghpartsize; + ghpartnum = letoh32(gh.gh_part_num); + gpsectors = (ghpartnum + ghpartspersec - 1) / ghpartspersec; + new_csum = crc32(0L, Z_NULL, 0); + found = 0; + for (i = 0; i < gpsectors; i++, lba++) { + status = efid_io(F_READ, ed, EFI_SECTOBLK(ed, lba), + EFI_BLKSPERSEC(ed), buf); + if (EFI_ERROR(status)) { + *err = "Disk I/O Error"; + return (-1); + } + for (part = 0; part < ghpartspersec; part++) { + if (ghpartnum == 0) + break; + new_csum = crc32(new_csum, buf + part * sizeof(gp), + sizeof(gp)); + ghpartnum--; + if (found) + continue; + memcpy(&gp, buf + part * sizeof(gp), sizeof(gp)); + if (memcmp(&gp.gp_type, openbsd_uuid, + sizeof(struct uuid)) == 0) + found = 1; + } + } + if (new_csum != letoh32(gh.gh_part_csum)) { + *err = "bad GPT entries checksum\n"; + return (-1); + } + if (found) { + lba = letoh64(gp.gp_lba_start); + /* Bootloaders do not current handle addresses > UINT_MAX! */ + if (lba > UINT_MAX || EFI_SECTOBLK(ed, lba) > UINT_MAX) { + *err = "OpenBSD Partition LBA > 2**32 - 1"; + return (-1); + } + return (u_int)lba; + } + + return (-1); +} + +const char * +efi_getdisklabel(efi_diskinfo_t ed, struct disklabel *label) +{ + u_int start = 0; + uint8_t buf[DEV_BSIZE]; + struct dos_partition dosparts[NDOSPART]; + EFI_STATUS status; + const char *err = NULL; + int error; + + /* + * Read sector 0. Ensure it has a valid MBR signature. + * + * If it's a protective MBR then try to find the disklabel via + * GPT. If it's not a protective MBR, try to find the disklabel + * via MBR. + */ + memset(buf, 0, sizeof(buf)); + status = efid_io(F_READ, ed, DOSBBSECTOR, 1, buf); + if (EFI_ERROR(status)) + return ("Disk I/O Error"); + + /* Check MBR signature. */ + if (buf[510] != 0x55 || buf[511] != 0xaa) { + if (efi_getdisklabel_cd9660(ed, label) == 0) + return (NULL); + return ("invalid MBR signature"); + } + + memcpy(dosparts, buf+DOSPARTOFF, sizeof(dosparts)); + + /* check for GPT protective MBR. */ + if (gpt_chk_mbr(dosparts, ed->blkio->Media->LastBlock + 1) == 0) { + start = findopenbsd_gpt(ed, &err); + if (start == (u_int)-1) { + if (err != NULL) + return (err); + return ("no OpenBSD GPT partition"); + } + } else { + start = findopenbsd(ed, &err); + if (start == (u_int)-1) { + if (err != NULL) + return (err); + return "no OpenBSD MBR partition\n"; + } + } + + /* Load BSD disklabel */ +#ifdef BIOS_DEBUG + if (debug) + printf("loading disklabel @ %u\n", start + DOS_LABELSECTOR); +#endif + /* read disklabel */ + error = efid_io(F_READ, ed, EFI_SECTOBLK(ed, start) + DOS_LABELSECTOR, + 1, buf); + + if (error) + return "failed to read disklabel"; + + /* Fill in disklabel */ + return (getdisklabel(buf, label)); +} + +static int +efi_getdisklabel_cd9660(efi_diskinfo_t ed, struct disklabel *label) +{ + uint8_t buf[DEV_BSIZE]; + EFI_STATUS status; + + status = efid_io(F_READ, ed, 64, 1, buf); + if (EFI_ERROR(status)) + return -1; + if (buf[0] != ISO_VD_PRIMARY || bcmp(buf + 1, ISO_STANDARD_ID, 5) != 0) + return -1; + + /* Create an imaginary disk label */ + label->d_secsize = 2048; + label->d_ntracks = 1; + label->d_nsectors = 100; + label->d_ncylinders = 1; + label->d_secpercyl = label->d_ntracks * label->d_nsectors; + + strncpy(label->d_typename, "ATAPI CD-ROM", sizeof(label->d_typename)); + label->d_type = DTYPE_ATAPI; + + strncpy(label->d_packname, "fictitious", sizeof(label->d_packname)); + DL_SETDSIZE(label, 100); + + /* 'a' partition covering the "whole" disk */ + DL_SETPOFFSET(&label->d_partitions[0], 0); + DL_SETPSIZE(&label->d_partitions[0], 100); + label->d_partitions[0].p_fstype = FS_UNUSED; + + /* The raw partition is special */ + DL_SETPOFFSET(&label->d_partitions[RAW_PART], 0); + DL_SETPSIZE(&label->d_partitions[RAW_PART], 100); + label->d_partitions[RAW_PART].p_fstype = FS_UNUSED; + + label->d_npartitions = MAXPARTITIONS; + + label->d_magic = DISKMAGIC; + label->d_magic2 = DISKMAGIC; + label->d_checksum = dkcksum(label); + + return (0); +} + +int +efiopen(struct open_file *f, ...) +{ + struct diskinfo *dip = NULL; + va_list ap; + u_int unit, part; + int i = 0; + + va_start(ap, f); + unit = va_arg(ap, u_int); + part = va_arg(ap, u_int); + va_end(ap); + + if (part >= MAXPARTITIONS) + return (ENXIO); + + TAILQ_FOREACH(dip, &disklist, list) { + if (i == unit) + break; + i++; + } + + if (dip == NULL) + return (ENXIO); + + if ((dip->flags & DISKINFO_FLAG_GOODLABEL) == 0) + return (ENXIO); + + dip->part = part; + bootdev_dip = dip; + f->f_devdata = dip; + + return 0; +} + +int +efistrategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf, + size_t *rsize) +{ + struct diskinfo *dip = (struct diskinfo *)devdata; + int error = 0; + size_t nsect; + + nsect = (size + DEV_BSIZE - 1) / DEV_BSIZE; + blk += DL_SECTOBLK(&dip->disklabel, + dip->disklabel.d_partitions[dip->part].p_offset); + + if (blk < 0) + error = EINVAL; + else + error = efid_diskio(rw, dip, blk, nsect, buf); + + if (rsize != NULL) + *rsize = nsect * DEV_BSIZE; + + return (error); +} + +int +eficlose(struct open_file *f) +{ + f->f_devdata = NULL; + + return 0; +} + +int +efiioctl(struct open_file *f, u_long cmd, void *data) +{ + return 0; +} diff --git sys/arch/loongarch64/stand/efiboot/efidev.h sys/arch/loongarch64/stand/efiboot/efidev.h new file mode 100644 index 00000000000..b7e5aa86430 --- /dev/null +++ sys/arch/loongarch64/stand/efiboot/efidev.h @@ -0,0 +1,36 @@ +/* $OpenBSD: efidev.h,v 1.1 2021/04/28 19:01:00 drahn Exp $ */ + +/* + * Copyright (c) 1996 Michael Shalayeff + * Copyright (c) 2015 YASUOKA Masahiko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +/* efidev.c */ +void efid_init(struct diskinfo *, void *handle); +int efiopen(struct open_file *, ...); +int efistrategy(void *, int, daddr_t, size_t, void *, size_t *); +int eficlose(struct open_file *); +int efiioctl(struct open_file *, u_long, void *); diff --git sys/arch/loongarch64/stand/efiboot/efidt.h sys/arch/loongarch64/stand/efiboot/efidt.h new file mode 100644 index 00000000000..8a2ab0d2c34 --- /dev/null +++ sys/arch/loongarch64/stand/efiboot/efidt.h @@ -0,0 +1,44 @@ +/* $OpenBSD: efidt.h,v 1.1 2024/06/17 09:12:45 kettenis Exp $ */ + +/* + * Copyright (c) 2024 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include + +#define EFI_DT_FIXUP_PROTOCOL_GUID \ + { 0xe617d64c, 0xfe08, 0x46da, \ + { 0xf4, 0xdc, 0xbb, 0xd5, 0x87, 0x0c, 0x73, 0x00 } } + +INTERFACE_DECL(_EFI_DT_FIXUP_PROTOCOL); + +typedef EFI_STATUS +(EFIAPI *EFI_DT_FIXUP) ( + IN struct _EFI_DT_FIXUP_PROTOCOL *This, + IN VOID *Fdt, + IN OUT UINTN *BufferSize, + IN UINT32 Flags + ); + +#define EFI_DT_APPLY_FIXUPS 0x00000001 +#define EFI_DT_RESERVE_MEMORY 0x00000002 + +typedef struct _EFI_DT_FIXUP_PROTOCOL { + UINT64 Revision; + EFI_DT_FIXUP Fixup; +} EFI_DT_FIXUP_PROTOCOL; diff --git sys/arch/loongarch64/stand/efiboot/efiloongarch.c sys/arch/loongarch64/stand/efiboot/efiloongarch.c new file mode 100644 index 00000000000..c0461ca2fcd --- /dev/null +++ sys/arch/loongarch64/stand/efiboot/efiloongarch.c @@ -0,0 +1,67 @@ +/* $OpenBSD: efiloongarch.c,v 1.1 2024/03/26 22:26:04 kettenis Exp $ */ + +/* + * Copyright (c) 2024 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include + +#include "libsa.h" + +#include "efiboot.h" + +extern EFI_BOOT_SERVICES *BS; + +/* RISC-V UEFI Boot Protocol */ + +#define LOONGARCH_EFI_BOOT_PROTOCOL_GUID \ + { 0xccd15fec, 0x6f73, 0x4eec, { 0x83, 0x95, 0x3e, 0x69, 0xe4, 0xb9, 0x40, 0xbf } } + +INTERFACE_DECL(_LOONGARCH_EFI_BOOT_PROTOCOL); + +typedef +EFI_STATUS +(EFIAPI *EFI_GET_BOOT_HARTID) ( + IN struct _LOONGARCH_EFI_BOOT_PROTOCOL *This, + OUT UINTN *BootHartId + ); + +typedef struct _LOONGARCH_EFI_BOOT_PROTOCOL { + UINT64 Revision; + EFI_GET_BOOT_HARTID GetBootHartId; +} LOONGARCH_EFI_BOOT_PROTOCOL; + +static EFI_GUID loongarch_guid = LOONGARCH_EFI_BOOT_PROTOCOL_GUID; + +int32_t +efi_get_boot_hart_id(void) +{ + EFI_STATUS status; + LOONGARCH_EFI_BOOT_PROTOCOL *loongarch = NULL; + UINTN hartid; + + status = BS->LocateProtocol(&loongarch_guid, NULL, (void **)&loongarch); + if (loongarch == NULL || EFI_ERROR(status)) + return -1; + + status = loongarch->GetBootHartId(loongarch, &hartid); + if (status == EFI_SUCCESS) + return hartid; + + return -1; +} diff --git sys/arch/loongarch64/stand/efiboot/efipxe.c sys/arch/loongarch64/stand/efiboot/efipxe.c new file mode 100644 index 00000000000..01764f6cbb0 --- /dev/null +++ sys/arch/loongarch64/stand/efiboot/efipxe.c @@ -0,0 +1,518 @@ +/* $OpenBSD: efipxe.c,v 1.3 2021/12/11 20:11:18 naddy Exp $ */ +/* + * Copyright (c) 2017 Patrick Wildt + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include "efiboot.h" +#include "disk.h" + +extern EFI_BOOT_SERVICES *BS; +extern EFI_DEVICE_PATH *efi_bootdp; + +extern char *bootmac; +static UINT8 boothw[16]; +struct in_addr bootip, servip; +extern struct in_addr gateip; +static EFI_GUID devp_guid = DEVICE_PATH_PROTOCOL; +static EFI_GUID net_guid = EFI_SIMPLE_NETWORK_PROTOCOL; +static EFI_GUID pxe_guid = EFI_PXE_BASE_CODE_PROTOCOL; +static EFI_SIMPLE_NETWORK *NET = NULL; +static EFI_PXE_BASE_CODE *PXE = NULL; +static EFI_PHYSICAL_ADDRESS txbuf; +static int use_mtftp = 0; + +extern int efi_device_path_depth(EFI_DEVICE_PATH *dp, int); +extern int efi_device_path_ncmp(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *, int); + +int efinet_probe(struct netif *, void *); +int efinet_match(struct netif *, void *); +void efinet_init(struct iodesc *, void *); +int efinet_get(struct iodesc *, void *, size_t, time_t); +int efinet_put(struct iodesc *, void *, size_t); +void efinet_end(struct netif *); + +/* + * TFTP initial probe. This function discovers PXE handles and tries + * to figure out if there has already been a successful PXE handshake. + * If so, set the PXE variable. + */ +void +efi_pxeprobe(void) +{ + EFI_SIMPLE_NETWORK *net; + EFI_PXE_BASE_CODE *pxe; + EFI_DEVICE_PATH *dp0; + EFI_HANDLE *handles; + EFI_STATUS status; + UINTN nhandles; + int i, depth; + + if (efi_bootdp == NULL) + return; + + status = BS->LocateHandleBuffer(ByProtocol, &pxe_guid, NULL, + &nhandles, &handles); + if (status != EFI_SUCCESS) + return; + + for (i = 0; i < nhandles; i++) { + EFI_PXE_BASE_CODE_DHCPV4_PACKET *dhcp; + + status = BS->HandleProtocol(handles[i], &devp_guid, + (void **)&dp0); + if (status != EFI_SUCCESS) + continue; + + depth = efi_device_path_depth(efi_bootdp, MESSAGING_DEVICE_PATH); + if (depth == -1 || efi_device_path_ncmp(efi_bootdp, dp0, depth)) + continue; + + status = BS->HandleProtocol(handles[i], &net_guid, + (void **)&net); + if (status != EFI_SUCCESS) + continue; + + status = BS->HandleProtocol(handles[i], &pxe_guid, + (void **)&pxe); + if (status != EFI_SUCCESS) + continue; + + if (pxe->Mode == NULL) + continue; + + if (pxe->Mtftp != NULL) { + status = pxe->Mtftp(NULL, 0, NULL, FALSE, NULL, NULL, + NULL, NULL, NULL, FALSE); + if (status != EFI_UNSUPPORTED) + use_mtftp = 1; + } + + dhcp = (EFI_PXE_BASE_CODE_DHCPV4_PACKET *)&pxe->Mode->DhcpAck; + memcpy(&bootip, dhcp->BootpYiAddr, sizeof(bootip)); + memcpy(&servip, dhcp->BootpSiAddr, sizeof(servip)); + memcpy(&gateip, dhcp->BootpSiAddr, sizeof(gateip)); + memcpy(boothw, dhcp->BootpHwAddr, sizeof(boothw)); + bootmac = boothw; + NET = net; + PXE = pxe; + break; + } +} + +/* + * TFTP filesystem layer implementation. + */ +struct mtftp_handle { + unsigned char *inbuf; /* input buffer */ + size_t inbufsize; + off_t inbufoff; +}; + +int +mtftp_open(char *path, struct open_file *f) +{ + struct mtftp_handle *tftpfile; + EFI_PHYSICAL_ADDRESS addr; + EFI_IP_ADDRESS dstip; + EFI_STATUS status; + UINT64 size; + + if (strcmp("tftp", f->f_dev->dv_name) != 0) + return ENXIO; + + if (PXE == NULL) + return ENXIO; + + if (!use_mtftp) + return ENXIO; + + tftpfile = alloc(sizeof(*tftpfile)); + if (tftpfile == NULL) + return ENOMEM; + memset(tftpfile, 0, sizeof(*tftpfile)); + + memcpy(&dstip, &servip, sizeof(servip)); + status = PXE->Mtftp(PXE, EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, NULL, + FALSE, &size, NULL, &dstip, path, NULL, FALSE); + if (status != EFI_SUCCESS) { + free(tftpfile, sizeof(*tftpfile)); + return ENOENT; + } + tftpfile->inbufsize = size; + + if (tftpfile->inbufsize == 0) + goto out; + + status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, + EFI_SIZE_TO_PAGES(tftpfile->inbufsize), &addr); + if (status != EFI_SUCCESS) { + free(tftpfile, sizeof(*tftpfile)); + return ENOMEM; + } + tftpfile->inbuf = (unsigned char *)((paddr_t)addr); + + status = PXE->Mtftp(PXE, EFI_PXE_BASE_CODE_TFTP_READ_FILE, + tftpfile->inbuf, FALSE, &size, NULL, &dstip, path, NULL, FALSE); + if (status != EFI_SUCCESS) { + free(tftpfile, sizeof(*tftpfile)); + return ENXIO; + } +out: + f->f_fsdata = tftpfile; + return 0; +} + +int +mtftp_close(struct open_file *f) +{ + struct mtftp_handle *tftpfile = f->f_fsdata; + + if (tftpfile->inbuf != NULL) + BS->FreePages((paddr_t)tftpfile->inbuf, + EFI_SIZE_TO_PAGES(tftpfile->inbufsize)); + free(tftpfile, sizeof(*tftpfile)); + return 0; +} + +int +mtftp_read(struct open_file *f, void *addr, size_t size, size_t *resid) +{ + struct mtftp_handle *tftpfile = f->f_fsdata; + size_t toread; + + if (size > tftpfile->inbufsize - tftpfile->inbufoff) + toread = tftpfile->inbufsize - tftpfile->inbufoff; + else + toread = size; + + if (toread != 0) { + memcpy(addr, tftpfile->inbuf + tftpfile->inbufoff, toread); + tftpfile->inbufoff += toread; + } + + if (resid != NULL) + *resid = size - toread; + return 0; +} + +int +mtftp_write(struct open_file *f, void *start, size_t size, size_t *resid) +{ + return EROFS; +} + +off_t +mtftp_seek(struct open_file *f, off_t offset, int where) +{ + struct mtftp_handle *tftpfile = f->f_fsdata; + + switch(where) { + case SEEK_CUR: + if (tftpfile->inbufoff + offset < 0 || + tftpfile->inbufoff + offset > tftpfile->inbufsize) { + errno = EOFFSET; + break; + } + tftpfile->inbufoff += offset; + return (tftpfile->inbufoff); + case SEEK_SET: + if (offset < 0 || offset > tftpfile->inbufsize) { + errno = EOFFSET; + break; + } + tftpfile->inbufoff = offset; + return (tftpfile->inbufoff); + case SEEK_END: + tftpfile->inbufoff = tftpfile->inbufsize; + return (tftpfile->inbufoff); + default: + errno = EINVAL; + } + return((off_t)-1); +} + +int +mtftp_stat(struct open_file *f, struct stat *sb) +{ + struct mtftp_handle *tftpfile = f->f_fsdata; + + sb->st_mode = 0444; + sb->st_nlink = 1; + sb->st_uid = 0; + sb->st_gid = 0; + sb->st_size = tftpfile->inbufsize; + + return 0; +} + +int +mtftp_readdir(struct open_file *f, char *name) +{ + return EOPNOTSUPP; +} + +/* + * Overload generic TFTP implementation to check that + * we actually have a driver. + */ +int +efitftp_open(char *path, struct open_file *f) +{ + if (strcmp("tftp", f->f_dev->dv_name) != 0) + return ENXIO; + + if (NET == NULL || PXE == NULL) + return ENXIO; + + if (use_mtftp) + return ENXIO; + + return tftp_open(path, f); +} + +/* + * Dummy network device. + */ +int tftpdev_sock = -1; + +int +tftpopen(struct open_file *f, ...) +{ + EFI_STATUS status; + u_int unit; + va_list ap; + + va_start(ap, f); + unit = va_arg(ap, u_int); + va_end(ap); + + /* No PXE set -> no PXE available */ + if (PXE == NULL) + return 1; + + if (unit != 0) + return 1; + + if (!use_mtftp) { + status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, + EFI_SIZE_TO_PAGES(RECV_SIZE), &txbuf); + if (status != EFI_SUCCESS) + return ENOMEM; + + if ((tftpdev_sock = netif_open("efinet")) < 0) { + BS->FreePages(txbuf, EFI_SIZE_TO_PAGES(RECV_SIZE)); + return ENXIO; + } + + f->f_devdata = &tftpdev_sock; + } + + return 0; +} + +int +tftpclose(struct open_file *f) +{ + int ret = 0; + + if (!use_mtftp) { + ret = netif_close(*(int *)f->f_devdata); + BS->FreePages(txbuf, EFI_SIZE_TO_PAGES(RECV_SIZE)); + txbuf = 0; + } + + return ret; +} + +int +tftpioctl(struct open_file *f, u_long cmd, void *data) +{ + return EOPNOTSUPP; +} + +int +tftpstrategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf, + size_t *rsize) +{ + return EOPNOTSUPP; +} + +/* + * Simple Network Protocol driver. + */ +struct netif_stats efinet_stats; +struct netif_dif efinet_ifs[] = { + { 0, 1, &efinet_stats, 0, 0, }, +}; + +struct netif_driver efinet_driver = { + "efinet", + efinet_match, + efinet_probe, + efinet_init, + efinet_get, + efinet_put, + efinet_end, + efinet_ifs, + nitems(efinet_ifs) +}; + +int +efinet_match(struct netif *nif, void *v) +{ + return 1; +} + +int +efinet_probe(struct netif *nif, void *v) +{ + if (strncmp(v, efinet_driver.netif_bname, 3)) + return -1; + + return 0; +} + +void +efinet_init(struct iodesc *desc, void *v) +{ + EFI_SIMPLE_NETWORK *net = NET; + EFI_STATUS status; + + if (net == NULL) + return; + + if (net->Mode->State == EfiSimpleNetworkStopped) { + status = net->Start(net); + if (status != EFI_SUCCESS) + return; + } + + if (net->Mode->State != EfiSimpleNetworkInitialized) { + status = net->Initialize(net, 0, 0); + if (status != EFI_SUCCESS) + return; + } + + net->ReceiveFilters(net, EFI_SIMPLE_NETWORK_RECEIVE_UNICAST | + EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST, + 0, FALSE, 0, NULL); + + memcpy(desc->myea, net->Mode->CurrentAddress.Addr, 6); + memcpy(&desc->myip, &bootip, sizeof(bootip)); + desc->xid = 1; +} + +int +efinet_get(struct iodesc *desc, void *pkt, size_t len, time_t tmo) +{ + EFI_SIMPLE_NETWORK *net = NET; + EFI_STATUS status; + UINTN bufsz, pktsz; + time_t t; + char *buf, *ptr; + ssize_t ret = -1; + + if (net == NULL) + return ret; + + bufsz = net->Mode->MaxPacketSize + ETHER_HDR_LEN + ETHER_CRC_LEN; + buf = alloc(bufsz + ETHER_ALIGN); + if (buf == NULL) + return ret; + ptr = buf + ETHER_ALIGN; + + t = getsecs(); + status = EFI_NOT_READY; + while ((getsecs() - t) < tmo) { + pktsz = bufsz; + status = net->Receive(net, NULL, &pktsz, ptr, NULL, NULL, NULL); + if (status == EFI_SUCCESS) + break; + if (status != EFI_NOT_READY) + break; + } + + if (status == EFI_SUCCESS) { + memcpy(pkt, ptr, min((ssize_t)pktsz, len)); + ret = min((ssize_t)pktsz, len); + } + + free(buf, bufsz + ETHER_ALIGN); + return ret; +} + +int +efinet_put(struct iodesc *desc, void *pkt, size_t len) +{ + EFI_SIMPLE_NETWORK *net = NET; + EFI_STATUS status; + void *buf = NULL; + int ret = -1; + + if (net == NULL) + goto out; + + if (len > RECV_SIZE) + goto out; + + memcpy((void *)txbuf, pkt, len); + status = net->Transmit(net, 0, len, (void *)txbuf, NULL, NULL, NULL); + if (status != EFI_SUCCESS) + goto out; + + buf = NULL; + while (status == EFI_SUCCESS) { + status = net->GetStatus(net, NULL, &buf); + if (buf) + break; + } + + if (status == EFI_SUCCESS) + ret = len; + +out: + return ret; +} + +void +efinet_end(struct netif *nif) +{ + EFI_SIMPLE_NETWORK *net = NET; + + if (net == NULL) + return; + + net->Shutdown(net); +} diff --git sys/arch/loongarch64/stand/efiboot/efipxe.h sys/arch/loongarch64/stand/efiboot/efipxe.h new file mode 100644 index 00000000000..3a0529a0cc5 --- /dev/null +++ sys/arch/loongarch64/stand/efiboot/efipxe.h @@ -0,0 +1,33 @@ +/* $OpenBSD: efipxe.h,v 1.1 2021/04/28 19:01:00 drahn Exp $ */ +/* + * Copyright (c) 2017 Patrick Wildt + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +extern struct netif_driver efinet_driver; + +int efitftp_open(char *path, struct open_file *f); + +int mtftp_open(char *, struct open_file *); +int mtftp_close(struct open_file *); +int mtftp_read(struct open_file *, void *, size_t, size_t *); +int mtftp_write(struct open_file *, void *, size_t, size_t *); +off_t mtftp_seek(struct open_file *, off_t, int); +int mtftp_stat(struct open_file *, struct stat *); +int mtftp_readdir(struct open_file *, char *); + +int tftpopen(struct open_file *, ...); +int tftpclose(struct open_file *); +int tftpioctl(struct open_file *, u_long, void *); +int tftpstrategy(void *, int, daddr_t, size_t, void *, size_t *); diff --git sys/arch/loongarch64/stand/efiboot/efirng.c sys/arch/loongarch64/stand/efiboot/efirng.c new file mode 100644 index 00000000000..03bf3e7008c --- /dev/null +++ sys/arch/loongarch64/stand/efiboot/efirng.c @@ -0,0 +1,89 @@ +/* $OpenBSD: efirng.c,v 1.2 2021/06/25 17:49:49 krw Exp $ */ + +/* + * Copyright (c) 2018 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include + +#include "libsa.h" + +extern EFI_BOOT_SERVICES *BS; + +/* Random Number Generator Protocol */ + +#define EFI_RNG_PROTOCOL_GUID \ + { 0x3152bca5, 0xeade, 0x433d, {0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44} } + +INTERFACE_DECL(_EFI_RNG_PROTOCOL); + +typedef EFI_GUID EFI_RNG_ALGORITHM; + +typedef +EFI_STATUS +(EFIAPI *EFI_RNG_GET_INFO) ( + IN struct _EFI_RNG_PROTOCOL *This, + IN OUT UINTN *RNGAlgorithmListSize, + OUT EFI_RNG_ALGORITHM *RNGAlgorithmList + ); + +typedef +EFI_STATUS +(EFIAPI *EFI_RNG_GET_RNG) ( + IN struct _EFI_RNG_PROTOCOL *This, + IN EFI_RNG_ALGORITHM *RNGAlgorithm, OPTIONAL + IN UINTN RNGValueLength, + OUT UINT8 *RNGValue + ); + +typedef struct _EFI_RNG_PROTOCOL { + EFI_RNG_GET_INFO GetInfo; + EFI_RNG_GET_RNG GetRNG; +} EFI_RNG_PROTOCOL; + +static EFI_GUID rng_guid = EFI_RNG_PROTOCOL_GUID; + +int +fwrandom(char *buf, size_t buflen) +{ + EFI_STATUS status; + EFI_RNG_PROTOCOL *rng = NULL; + UINT8 *random; + size_t i; + int ret = 0; + + status = BS->LocateProtocol(&rng_guid, NULL, (void **)&rng); + if (rng == NULL || EFI_ERROR(status)) + return -1; + + random = alloc(buflen); + + status = rng->GetRNG(rng, NULL, buflen, random); + if (EFI_ERROR(status)) { + printf("RNG GetRNG() failed (%d)\n", status); + ret = -1; + goto out; + } + + for (i = 0; i < buflen; i++) + buf[i] ^= random[i]; + +out: + free(random, buflen); + return ret; +} diff --git sys/arch/loongarch64/stand/efiboot/exec.c sys/arch/loongarch64/stand/efiboot/exec.c new file mode 100644 index 00000000000..48bbc2fc185 --- /dev/null +++ sys/arch/loongarch64/stand/efiboot/exec.c @@ -0,0 +1,89 @@ +/* $OpenBSD: exec.c,v 1.1 2021/04/28 19:01:00 drahn Exp $ */ + +/* + * Copyright (c) 2006, 2016 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "efiboot.h" +#include "libsa.h" +#include "fdt.h" + +typedef void (*startfuncp)(void *, void *, void *) __attribute__ ((noreturn)); + +unsigned int cpu_get_dcache_line_size(void); +void cpu_flush_dcache(vaddr_t, vsize_t); +void cpu_inval_icache(void); + +void +cpu_flush_dcache(vaddr_t addr, vsize_t len) +{ + __asm volatile("dbar 0" ::: "memory"); +} + +void +cpu_inval_icache(void) +{ + __asm volatile("ibar 0" ::: "memory"); +} + +void +run_loadfile(uint64_t *marks, int howto) +{ + char args[256]; + char *cp; + void *fdt; + + strlcpy(args, cmd.path, sizeof(args)); + cp = args + strlen(args); + + *cp++ = ' '; + *cp = '-'; + if (howto & RB_ASKNAME) + *++cp = 'a'; + if (howto & RB_CONFIG) + *++cp = 'c'; + if (howto & RB_SINGLE) + *++cp = 's'; + if (howto & RB_KDB) + *++cp = 'd'; + if (*cp == '-') + *--cp = 0; + else + *++cp = 0; + + fdt = efi_makebootargs(args, howto); + + efi_cleanup(); + + cpu_flush_dcache(marks[MARK_ENTRY], marks[MARK_END] - marks[MARK_ENTRY]); + cpu_inval_icache(); + + cpu_flush_dcache((vaddr_t)fdt, fdt_get_size(fdt)); + + (*(startfuncp)(marks[MARK_ENTRY]))((void *)marks[MARK_END], 0, fdt); + + /* NOTREACHED */ +} diff --git sys/arch/loongarch64/stand/efiboot/fdt.c sys/arch/loongarch64/stand/efiboot/fdt.c new file mode 100644 index 00000000000..fa603c1001a --- /dev/null +++ sys/arch/loongarch64/stand/efiboot/fdt.c @@ -0,0 +1,656 @@ +/* $OpenBSD: fdt.c,v 1.4 2023/02/13 16:16:03 kettenis Exp $ */ + +/* + * Copyright (c) 2009 Dariusz Swiderski + * Copyright (c) 2009, 2016 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include + +#include "fdt.h" + +unsigned int fdt_check_head(void *); +char *fdt_get_str(uint32_t); +void *skip_property(uint32_t *); +void *skip_props(uint32_t *); +void *skip_node_name(uint32_t *); +void *skip_node(void *); +void *skip_nops(uint32_t *); +void *fdt_parent_node_recurse(void *, void *); + +static int tree_inited = 0; +static struct fdt tree; + +unsigned int +fdt_check_head(void *fdt) +{ + struct fdt_head *fh; + uint32_t *ptr, *tok; + + fh = fdt; + ptr = (uint32_t *)fdt; + + if (betoh32(fh->fh_magic) != FDT_MAGIC) + return 0; + + if (betoh32(fh->fh_version) > FDT_CODE_VERSION) + return 0; + + tok = skip_nops(ptr + (betoh32(fh->fh_struct_off) / 4)); + if (betoh32(*tok) != FDT_NODE_BEGIN) + return 0; + + /* check for end signature on version 17 blob */ + if ((betoh32(fh->fh_version) >= 17) && + (betoh32(*(ptr + (betoh32(fh->fh_struct_off) / 4) + + (betoh32(fh->fh_struct_size) / 4) - 1)) != FDT_END)) + return 0; + + return betoh32(fh->fh_version); +} + +/* + * Initializes internal structures of module. + * Has to be called once. + */ +int +fdt_init(void *fdt) +{ + int version; + + memset(&tree, 0, sizeof(struct fdt)); + tree_inited = 0; + + if (!fdt) + return 0; + + if (!(version = fdt_check_head(fdt))) + return 0; + + tree.header = (struct fdt_head *)fdt; + tree.tree = (char *)fdt + betoh32(tree.header->fh_struct_off); + tree.strings = (char *)fdt + betoh32(tree.header->fh_strings_off); + tree.memory = (char *)fdt + betoh32(tree.header->fh_reserve_off); + tree.end = (char *)fdt + betoh32(tree.header->fh_size); + tree.version = version; + tree.strings_size = betoh32(tree.header->fh_strings_size); + if (tree.version >= 17) + tree.struct_size = betoh32(tree.header->fh_struct_size); + tree_inited = 1; + + return version; +} + +void +fdt_finalize(void) +{ + char *start = (char *)tree.header; + + tree.header->fh_size = htobe32(tree.end - start); + tree.header->fh_struct_off = htobe32(tree.tree - start); + tree.header->fh_strings_off = htobe32(tree.strings - start); + tree.header->fh_reserve_off = htobe32(tree.memory - start); + tree.header->fh_strings_size = htobe32(tree.strings_size); + if (tree.version >= 17) + tree.header->fh_struct_size = htobe32(tree.struct_size); +} + +/* + * Return the size of the FDT. + */ +size_t +fdt_get_size(void *fdt) +{ + if (!fdt) + return 0; + + if (!fdt_check_head(fdt)) + return 0; + + return betoh32(((struct fdt_head *)fdt)->fh_size); +} + +/* + * Retrieve string pointer from strings table. + */ +char * +fdt_get_str(uint32_t num) +{ + if (num > tree.strings_size) + return NULL; + return (tree.strings) ? (tree.strings + num) : NULL; +} + +int +fdt_add_str(char *name) +{ + size_t len = roundup(strlen(name) + 1, sizeof(uint32_t)); + char *end = tree.strings + tree.strings_size; + + if (end + len > tree.end) + panic("FDT overflow"); + + tree.strings_size += len; + memset(end, 0, len); + memcpy(end, name, strlen(name)); + + return (end - tree.strings); +} + +/* + * Utility functions for skipping parts of tree. + */ + +void * +skip_nops(uint32_t *ptr) +{ + while (betoh32(*ptr) == FDT_NOP) + ptr++; + + return ptr; +} + +void * +skip_property(uint32_t *ptr) +{ + uint32_t size; + + size = betoh32(*(ptr + 1)); + /* move forward by magic + size + nameid + rounded up property size */ + ptr += 3 + roundup(size, sizeof(uint32_t)) / sizeof(uint32_t); + + return skip_nops(ptr); +} + +void * +skip_props(uint32_t *ptr) +{ + while (betoh32(*ptr) == FDT_PROPERTY) { + ptr = skip_property(ptr); + } + return ptr; +} + +void * +skip_node_name(uint32_t *ptr) +{ + /* skip name, aligned to 4 bytes, this is NULL term., so must add 1 */ + ptr += roundup(strlen((char *)ptr) + 1, + sizeof(uint32_t)) / sizeof(uint32_t); + + return skip_nops(ptr); +} + +/* + * Retrieves node property, the returned pointer is inside the fdt tree, + * so we should not modify content pointed by it directly. + */ +int +fdt_node_property(void *node, char *name, char **out) +{ + uint32_t *ptr; + uint32_t nameid; + char *tmp; + + if (!tree_inited) + return 0; + + ptr = (uint32_t *)node; + + if (betoh32(*ptr) != FDT_NODE_BEGIN) + return 0; + + ptr = skip_node_name(ptr + 1); + + while (betoh32(*ptr) == FDT_PROPERTY) { + nameid = betoh32(*(ptr + 2)); /* id of name in strings table */ + tmp = fdt_get_str(nameid); + if (!strcmp(name, tmp)) { + *out = (char *)(ptr + 3); /* beginning of the value */ + return betoh32(*(ptr + 1)); /* size of value */ + } + ptr = skip_property(ptr); + } + return 0; +} + +int +fdt_node_set_property(void *node, char *name, void *data, int len) +{ + char *end = tree.strings + tree.strings_size; + uint32_t *ptr, *next; + uint32_t nameid; + uint32_t curlen; + size_t delta; + char *tmp; + + if (!tree_inited) + return 0; + + ptr = (uint32_t *)node; + + if (betoh32(*ptr) != FDT_NODE_BEGIN) + return 0; + + ptr = skip_node_name(ptr + 1); + + while (betoh32(*ptr) == FDT_PROPERTY) { + nameid = betoh32(*(ptr + 2)); /* id of name in strings table */ + tmp = fdt_get_str(nameid); + next = skip_property(ptr); + if (!strcmp(name, tmp)) { + curlen = betoh32(*(ptr + 1)); + delta = roundup(len, sizeof(uint32_t)) - + roundup(curlen, sizeof(uint32_t)); + if (end + delta > tree.end) + panic("FDT overflow"); + + memmove((char *)next + delta, next, + end - (char *)next); + tree.struct_size += delta; + tree.strings += delta; + *(ptr + 1) = htobe32(len); + memcpy(ptr + 3, data, len); + return 1; + } + ptr = next; + } + return 0; +} + +int +fdt_node_add_property(void *node, char *name, void *data, int len) +{ + char *end = tree.strings + tree.strings_size; + char *dummy; + + if (!tree_inited) + return 0; + + if (!fdt_node_property(node, name, &dummy)) { + uint32_t *ptr = (uint32_t *)node; + + if (betoh32(*ptr) != FDT_NODE_BEGIN) + return 0; + + if (end + 3 * sizeof(uint32_t) > tree.end) + panic("FDT overflow"); + + ptr = skip_node_name(ptr + 1); + + memmove(ptr + 3, ptr, end - (char *)ptr); + tree.struct_size += 3 * sizeof(uint32_t); + tree.strings += 3 * sizeof(uint32_t); + *ptr++ = htobe32(FDT_PROPERTY); + *ptr++ = htobe32(0); + *ptr++ = htobe32(fdt_add_str(name)); + } + + return fdt_node_set_property(node, name, data, len); +} + +int +fdt_node_add_node(void *node, char *name, void **child) +{ + size_t len = roundup(strlen(name) + 1, sizeof(uint32_t)) + 8; + char *end = tree.strings + tree.strings_size; + uint32_t *ptr = (uint32_t *)node; + + if (!tree_inited) + return 0; + + if (betoh32(*ptr) != FDT_NODE_BEGIN) + return 0; + + if (end + len > tree.end) + panic("FDT overflow"); + + ptr = skip_node_name(ptr + 1); + ptr = skip_props(ptr); + + /* skip children */ + while (betoh32(*ptr) == FDT_NODE_BEGIN) + ptr = skip_node(ptr); + + memmove((char *)ptr + len, ptr, end - (char *)ptr); + tree.struct_size += len; + tree.strings += len; + + *child = ptr; + *ptr++ = htobe32(FDT_NODE_BEGIN); + memset(ptr, 0, len - 8); + memcpy(ptr, name, strlen(name)); + ptr += (len - 8) / sizeof(uint32_t); + *ptr++ = htobe32(FDT_NODE_END); + + return 1; +} + +/* + * Retrieves next node, skipping all the children nodes of the pointed node, + * returns pointer to next node, no matter if it exists or not. + */ +void * +skip_node(void *node) +{ + uint32_t *ptr = node; + + ptr++; + + ptr = skip_node_name(ptr); + ptr = skip_props(ptr); + + /* skip children */ + while (betoh32(*ptr) == FDT_NODE_BEGIN) + ptr = skip_node(ptr); + + return skip_nops(ptr + 1); +} + +/* + * Retrieves next node, skipping all the children nodes of the pointed node, + * returns pointer to next node if exists, otherwise returns NULL. + * If passed 0 will return first node of the tree (root). + */ +void * +fdt_next_node(void *node) +{ + uint32_t *ptr; + + if (!tree_inited) + return NULL; + + ptr = node; + + if (node == NULL) { + ptr = skip_nops((uint32_t *)tree.tree); + return (betoh32(*ptr) == FDT_NODE_BEGIN) ? ptr : NULL; + } + + if (betoh32(*ptr) != FDT_NODE_BEGIN) + return NULL; + + ptr++; + + ptr = skip_node_name(ptr); + ptr = skip_props(ptr); + + /* skip children */ + while (betoh32(*ptr) == FDT_NODE_BEGIN) + ptr = skip_node(ptr); + + if (betoh32(*ptr) != FDT_NODE_END) + return NULL; + + ptr = skip_nops(ptr + 1); + + if (betoh32(*ptr) != FDT_NODE_BEGIN) + return NULL; + + return ptr; +} + +/* + * Retrieves node property as integers and puts them in the given + * integer array. + */ +int +fdt_node_property_ints(void *node, char *name, int *out, int outlen) +{ + int *data; + int i, inlen; + + inlen = fdt_node_property(node, name, (char **)&data) / sizeof(int); + if (inlen <= 0) + return -1; + + for (i = 0; i < inlen && i < outlen; i++) + out[i] = betoh32(data[i]); + + return i; +} + +/* + * Retrieves node property as an integer. + */ +int +fdt_node_property_int(void *node, char *name, int *out) +{ + return fdt_node_property_ints(node, name, out, 1); +} + +/* + * Retrieves next node, skipping all the children nodes of the pointed node + */ +void * +fdt_child_node(void *node) +{ + uint32_t *ptr; + + if (!tree_inited) + return NULL; + + ptr = node; + + if (betoh32(*ptr) != FDT_NODE_BEGIN) + return NULL; + + ptr++; + + ptr = skip_node_name(ptr); + ptr = skip_props(ptr); + /* check if there is a child node */ + return (betoh32(*ptr) == FDT_NODE_BEGIN) ? (ptr) : NULL; +} + +/* + * Retrieves node name. + */ +char * +fdt_node_name(void *node) +{ + uint32_t *ptr; + + if (!tree_inited) + return NULL; + + ptr = node; + + if (betoh32(*ptr) != FDT_NODE_BEGIN) + return NULL; + + return (char *)(ptr + 1); +} + +void * +fdt_find_node(char *name) +{ + void *node = fdt_next_node(0); + const char *p = name; + + if (!tree_inited) + return NULL; + + if (*p != '/') + return NULL; + + while (*p) { + void *child; + const char *q; + + while (*p == '/') + p++; + if (*p == 0) + return node; + q = strchr(p, '/'); + if (q == NULL) + q = p + strlen(p); + + for (child = fdt_child_node(node); child; + child = fdt_next_node(child)) { + if (strncmp(p, fdt_node_name(child), q - p) == 0) { + node = child; + break; + } + } + + if (child == NULL) + return NULL; /* No match found. */ + + p = q; + } + + return node; +} + +void * +fdt_parent_node_recurse(void *pnode, void *child) +{ + void *node = fdt_child_node(pnode); + void *tmp; + + while (node && (node != child)) { + if ((tmp = fdt_parent_node_recurse(node, child))) + return tmp; + node = fdt_next_node(node); + } + return (node) ? pnode : NULL; +} + +void * +fdt_parent_node(void *node) +{ + void *pnode = fdt_next_node(0); + + if (!tree_inited) + return NULL; + + if (node == pnode) + return NULL; + + return fdt_parent_node_recurse(pnode, node); +} + +int +fdt_node_is_compatible(void *node, const char *name) +{ + char *data; + int len; + + len = fdt_node_property(node, "compatible", &data); + while (len > 0) { + if (strcmp(data, name) == 0) + return 1; + len -= strlen(data) + 1; + data += strlen(data) + 1; + } + + return 0; +} + +#ifdef DEBUG +/* + * Debug methods for printing whole tree, particular nodes and properties + */ +void * +fdt_print_property(void *node, int level) +{ + uint32_t *ptr; + char *tmp, *value; + int cnt; + uint32_t nameid, size; + + ptr = (uint32_t *)node; + + if (!tree_inited) + return NULL; + + if (betoh32(*ptr) != FDT_PROPERTY) + return ptr; /* should never happen */ + + /* extract property name_id and size */ + size = betoh32(*++ptr); + nameid = betoh32(*++ptr); + + for (cnt = 0; cnt < level; cnt++) + printf("\t"); + + tmp = fdt_get_str(nameid); + printf("\t%s : ", tmp ? tmp : "NO_NAME"); + + ptr++; + value = (char *)ptr; + + if (!strcmp(tmp, "device_type") || !strcmp(tmp, "compatible") || + !strcmp(tmp, "model") || !strcmp(tmp, "bootargs") || + !strcmp(tmp, "linux,stdout-path")) { + printf("%s", value); + } else if (!strcmp(tmp, "clock-frequency") || + !strcmp(tmp, "timebase-frequency")) { + printf("%d", betoh32(*((unsigned int *)value))); + } else { + for (cnt = 0; cnt < size; cnt++) { + if ((cnt % sizeof(uint32_t)) == 0) + printf(" "); + printf("%x%x", value[cnt] >> 4, value[cnt] & 0xf); + } + } + ptr += roundup(size, sizeof(uint32_t)) / sizeof(uint32_t); + printf("\n"); + + return ptr; +} + +void +fdt_print_node(void *node, int level) +{ + uint32_t *ptr; + int cnt; + + ptr = (uint32_t *)node; + + if (betoh32(*ptr) != FDT_NODE_BEGIN) + return; + + ptr++; + + for (cnt = 0; cnt < level; cnt++) + printf("\t"); + printf("%s :\n", fdt_node_name(node)); + ptr = skip_node_name(ptr); + + while (betoh32(*ptr) == FDT_PROPERTY) + ptr = fdt_print_property(ptr, level); +} + +void +fdt_print_node_recurse(void *node, int level) +{ + void *child; + + fdt_print_node(node, level); + for (child = fdt_child_node(node); child; child = fdt_next_node(child)) + fdt_print_node_recurse(child, level + 1); +} + +void +fdt_print_tree(void) +{ + fdt_print_node_recurse(fdt_next_node(0), 0); +} +#endif diff --git sys/arch/loongarch64/stand/efiboot/fdt.h sys/arch/loongarch64/stand/efiboot/fdt.h new file mode 100644 index 00000000000..283a8dccbd9 --- /dev/null +++ sys/arch/loongarch64/stand/efiboot/fdt.h @@ -0,0 +1,71 @@ +/* $OpenBSD: fdt.h,v 1.1 2021/04/28 19:01:00 drahn Exp $ */ + +/* + * Copyright (c) 2009 Dariusz Swiderski + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +struct fdt_head { + uint32_t fh_magic; + uint32_t fh_size; + uint32_t fh_struct_off; + uint32_t fh_strings_off; + uint32_t fh_reserve_off; + uint32_t fh_version; + uint32_t fh_comp_ver; /* last compatible version */ + uint32_t fh_boot_cpu_id; /* fh_version >=2 */ + uint32_t fh_strings_size; /* fh_version >=3 */ + uint32_t fh_struct_size; /* fh_version >=17 */ +}; + +struct fdt { + struct fdt_head *header; + char *tree; + char *strings; + char *memory; + char *end; + int version; + int strings_size; + int struct_size; +}; + +#define FDT_MAGIC 0xd00dfeed +#define FDT_NODE_BEGIN 0x01 +#define FDT_NODE_END 0x02 +#define FDT_PROPERTY 0x03 +#define FDT_NOP 0x04 +#define FDT_END 0x09 + +#define FDT_CODE_VERSION 0x11 + +int fdt_init(void *); +void fdt_finalize(void); +size_t fdt_get_size(void *); +void *fdt_next_node(void *); +void *fdt_child_node(void *); +char *fdt_node_name(void *); +void *fdt_find_node(char *); +int fdt_node_property(void *, char *, char **); +int fdt_node_property_int(void *, char *, int *); +int fdt_node_property_ints(void *, char *, int *, int); +int fdt_node_set_property(void *, char *, void *, int); +int fdt_node_add_property(void *, char *, void *, int); +int fdt_node_add_node(void *, char *, void **); +void *fdt_parent_node(void *); +int fdt_node_is_compatible(void *, const char *); +#ifdef DEBUG +void *fdt_print_property(void *, int); +void fdt_print_node(void *, int); +void fdt_print_tree(void); +#endif diff --git sys/arch/loongarch64/stand/efiboot/heap.h sys/arch/loongarch64/stand/efiboot/heap.h new file mode 100644 index 00000000000..960c7e7d129 --- /dev/null +++ sys/arch/loongarch64/stand/efiboot/heap.h @@ -0,0 +1,29 @@ +/* $OpenBSD: heap.h,v 1.1 2021/04/28 19:01:00 drahn Exp $ */ + +/* + * Copyright (c) 2015 YASUOKA Masahiko + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include + +static char *top = NULL; +#define NEEDS_HEAP_INIT 1 + +static void +heap_init(void) +{ + extern EFI_PHYSICAL_ADDRESS heap; + if (top == NULL) + top = (char *)(uintptr_t)heap; +} diff --git sys/arch/loongarch64/stand/efiboot/ldscript.loongarch64 sys/arch/loongarch64/stand/efiboot/ldscript.loongarch64 new file mode 100644 index 00000000000..4968bf85841 --- /dev/null +++ sys/arch/loongarch64/stand/efiboot/ldscript.loongarch64 @@ -0,0 +1,83 @@ +/* $OpenBSD: ldscript.loongarch64,v 1.1 2021/04/28 19:01:00 drahn Exp $ */ + +OUTPUT_ARCH(elf64-littleloongarch) +ENTRY(_start) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = 0; + ImageBase = .; + .text : { + *(.peheader) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + *(.plt) + } =0xD4200000 + . = ALIGN(16); + .data : { + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.rodata1) + *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) + *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) + *(.opd) + *(.data .data.* .gnu.linkonce.d.*) + *(.data1) + *(.plabel) + + . = ALIGN(16); + __bss_start = .; + *(.sbss .sbss.* .gnu.linkonce.sb.*) + *(.scommon) + *(.dynbss) + *(.bss *.bss.*) + *(COMMON) + . = ALIGN(16); + __bss_end = .; + } + . = ALIGN(16); + set_Xcommand_set : { + __start_set_Xcommand_set = .; + *(set_Xcommand_set) + __stop_set_Xcommand_set = .; + } + set_Xficl_compile_set : { + __start_set_Xficl_compile_set = .; + *(set_Xficl_compile_set) + __stop_set_Xficl_compile_set = .; + } + . = ALIGN(16); + __gp = .; + .sdata : { + *(.got.plt .got) + *(.sdata .sdata.* .gnu.linkonce.s.*) + *(dynsbss) + *(.scommon) + } + . = ALIGN(16); + .dynamic : { *(.dynamic) } + . = ALIGN(16); + .rela.dyn : { + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.got) + *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) + *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) + *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) + *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + *(.rela.plt) + *(.relset_*) + *(.rela.dyn .rela.dyn.*) + } + . = ALIGN(16); + .reloc : { *(.reloc) } + . = ALIGN(16); + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + _edata = .; + + /* Unused sections */ + .hash : { *(.hash) } +} diff --git sys/arch/loongarch64/stand/efiboot/libsa.h sys/arch/loongarch64/stand/efiboot/libsa.h new file mode 100644 index 00000000000..65108b549e7 --- /dev/null +++ sys/arch/loongarch64/stand/efiboot/libsa.h @@ -0,0 +1,30 @@ +/* $OpenBSD: libsa.h,v 1.2 2023/02/23 19:48:22 miod Exp $ */ + +/* + * Copyright (c) 2008 Mark Kettenis + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#ifdef DEBUG +#define DPRINTF(x) printf x; +#else +#define DPRINTF(x) +#endif + +void machdep(void); +void devboot(dev_t, char *); + +#define MACHINE_CMD cmd_machine diff --git sys/arch/loongarch64/stand/efiboot/self_reloc.c sys/arch/loongarch64/stand/efiboot/self_reloc.c new file mode 100644 index 00000000000..31ba98dc7a0 --- /dev/null +++ sys/arch/loongarch64/stand/efiboot/self_reloc.c @@ -0,0 +1,130 @@ +/* $OpenBSD: self_reloc.c,v 1.1 2021/04/28 19:01:00 drahn Exp $ */ +/*- + * Copyright (c) 2008-2010 Rui Paulo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#if defined(__aarch64__) || defined(__amd64__) || defined(__riscv) || defined(__loongarch64) +#define ELFSIZE 64 +#define ElfW_Rel Elf64_Rela +#define ElfW_Dyn Elf64_Dyn +#define ELFW_R_TYPE ELF64_R_TYPE +#define ELF_RELA +#elif defined(__arm__) || defined(__i386__) +#define ELFSIZE 32 +#define ElfW_Rel Elf32_Rel +#define ElfW_Dyn Elf32_Dyn +#define ELFW_R_TYPE ELF32_R_TYPE +#else +#error architecture not supported +#endif + +#include + +#if defined(__aarch64__) +#define RELOC_TYPE_NONE R_AARCH64_NONE +#define RELOC_TYPE_RELATIVE R_AARCH64_RELATIVE +#elif defined(__amd64__) +#define RELOC_TYPE_NONE R_X86_64_NONE +#define RELOC_TYPE_RELATIVE R_X86_64_RELATIVE +#elif defined(__arm__) +#define RELOC_TYPE_NONE R_ARM_NONE +#define RELOC_TYPE_RELATIVE R_ARM_RELATIVE +#elif defined(__i386__) +#define RELOC_TYPE_NONE R_386_NONE +#define RELOC_TYPE_RELATIVE R_386_RELATIVE +#elif defined(__riscv) +#define RELOC_TYPE_NONE R_RISCV_NONE +#define RELOC_TYPE_RELATIVE R_RISCV_RELATIVE +#elif defined(__loongarch64) +#define RELOC_TYPE_NONE R_LARCH_NONE +#define RELOC_TYPE_RELATIVE R_LARCH_RELATIVE +#endif + +/* + * A simple elf relocator. + */ +void +self_reloc(Elf_Addr baseaddr, ElfW_Dyn *dynamic) +{ + Elf_Word relsz, relent; + Elf_Addr *newaddr; + ElfW_Rel *rel = NULL; + ElfW_Dyn *dynp; + + /* + * Find the relocation address, its size and the relocation entry. + */ + relsz = 0; + relent = 0; + for (dynp = dynamic; dynp->d_tag != DT_NULL; dynp++) { + switch (dynp->d_tag) { + case DT_REL: + case DT_RELA: + rel = (ElfW_Rel *)(dynp->d_un.d_ptr + baseaddr); + break; + case DT_RELSZ: + case DT_RELASZ: + relsz = dynp->d_un.d_val; + break; + case DT_RELENT: + case DT_RELAENT: + relent = dynp->d_un.d_val; + break; + default: + break; + } + } + + /* + * Perform the actual relocation. We rely on the object having been + * linked at 0, so that the difference between the load and link + * address is the same as the load address. + */ + for (; relsz > 0; relsz -= relent) { + switch (ELFW_R_TYPE(rel->r_info)) { + case RELOC_TYPE_NONE: + /* No relocation needs be performed. */ + break; + + case RELOC_TYPE_RELATIVE: + newaddr = (Elf_Addr *)(rel->r_offset + baseaddr); +#ifdef ELF_RELA + /* Addend relative to the base address. */ + *newaddr = baseaddr + rel->r_addend; +#else + /* Address relative to the base address. */ + *newaddr += baseaddr; +#endif + break; + default: + /* XXX: do we need other relocations ? */ + break; + } + rel = (ElfW_Rel *) ((caddr_t) rel + relent); + } +} diff --git sys/arch/loongarch64/stand/efiboot/softraid_loongarch64.c sys/arch/loongarch64/stand/efiboot/softraid_loongarch64.c new file mode 100644 index 00000000000..4c99a2adf27 --- /dev/null +++ sys/arch/loongarch64/stand/efiboot/softraid_loongarch64.c @@ -0,0 +1,667 @@ +/* $OpenBSD: softraid_loongarch64.c,v 1.6 2025/11/18 15:24:09 krw Exp $ */ + +/* + * Copyright (c) 2012 Joel Sing + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include "libsa.h" +#include "disk.h" +#include "efidev.h" +#include "softraid_loongarch64.h" + +static int gpt_chk_mbr(struct dos_partition *, u_int64_t); +static uint64_t findopenbsd_gpt(struct sr_boot_volume *, const char **); + +void +srprobe_meta_opt_load(struct sr_metadata *sm, struct sr_meta_opt_head *som) +{ + struct sr_meta_opt_hdr *omh; + struct sr_meta_opt_item *omi; +#if 0 + u_int8_t checksum[MD5_DIGEST_LENGTH]; +#endif + int i; + + /* Process optional metadata. */ + omh = (struct sr_meta_opt_hdr *)((u_int8_t *)(sm + 1) + + sizeof(struct sr_meta_chunk) * sm->ssdi.ssd_chunk_no); + for (i = 0; i < sm->ssdi.ssd_opt_no; i++) { + +#ifdef BIOS_DEBUG + printf("Found optional metadata of type %u, length %u\n", + omh->som_type, omh->som_length); +#endif + + /* Unsupported old fixed length optional metadata. */ + if (omh->som_length == 0) { + omh = (struct sr_meta_opt_hdr *)((void *)omh + + SR_OLD_META_OPT_SIZE); + continue; + } + + /* Load variable length optional metadata. */ + omi = alloc(sizeof(struct sr_meta_opt_item)); + bzero(omi, sizeof(struct sr_meta_opt_item)); + SLIST_INSERT_HEAD(som, omi, omi_link); + omi->omi_som = alloc(omh->som_length); + bzero(omi->omi_som, omh->som_length); + bcopy(omh, omi->omi_som, omh->som_length); + +#if 0 + /* XXX - Validate checksum. */ + bcopy(&omi->omi_som->som_checksum, &checksum, + MD5_DIGEST_LENGTH); + bzero(&omi->omi_som->som_checksum, MD5_DIGEST_LENGTH); + sr_checksum(sc, omi->omi_som, + &omi->omi_som->som_checksum, omh->som_length); + if (bcmp(&checksum, &omi->omi_som->som_checksum, + sizeof(checksum))) + panic("%s: invalid optional metadata checksum", + DEVNAME(sc)); +#endif + + omh = (struct sr_meta_opt_hdr *)((void *)omh + + omh->som_length); + } +} + +void +srprobe_keydisk_load(struct sr_metadata *sm) +{ + struct sr_meta_opt_hdr *omh; + struct sr_meta_keydisk *skm; + struct sr_boot_keydisk *kd; + int i; + + /* Process optional metadata. */ + omh = (struct sr_meta_opt_hdr *)((u_int8_t *)(sm + 1) + + sizeof(struct sr_meta_chunk) * sm->ssdi.ssd_chunk_no); + for (i = 0; i < sm->ssdi.ssd_opt_no; i++) { + + /* Unsupported old fixed length optional metadata. */ + if (omh->som_length == 0) { + omh = (struct sr_meta_opt_hdr *)((void *)omh + + SR_OLD_META_OPT_SIZE); + continue; + } + + if (omh->som_type != SR_OPT_KEYDISK) { + omh = (struct sr_meta_opt_hdr *)((void *)omh + + omh->som_length); + continue; + } + + kd = alloc(sizeof(struct sr_boot_keydisk)); + bcopy(&sm->ssdi.ssd_uuid, &kd->kd_uuid, sizeof(kd->kd_uuid)); + skm = (struct sr_meta_keydisk*)omh; + bcopy(&skm->skm_maskkey, &kd->kd_key, sizeof(kd->kd_key)); + SLIST_INSERT_HEAD(&sr_keydisks, kd, kd_link); + } +} + +void +srprobe(void) +{ + struct sr_boot_volume *bv, *bv1, *bv2; + struct sr_boot_chunk *bc, *bc1, *bc2; + struct sr_meta_chunk *mc; + struct sr_metadata *md; + struct diskinfo *dip; + struct partition *pp; + int i, error, volno; + daddr_t off; + + /* Probe for softraid volumes. */ + SLIST_INIT(&sr_volumes); + SLIST_INIT(&sr_keydisks); + + md = alloc(SR_META_SIZE * DEV_BSIZE); + + TAILQ_FOREACH(dip, &disklist, list) { + + /* Make sure disklabel has been read. */ + if ((dip->flags & DISKINFO_FLAG_GOODLABEL) == 0) + continue; + + for (i = 0; i < MAXPARTITIONS; i++) { + + pp = &dip->disklabel.d_partitions[i]; + if (pp->p_fstype != FS_RAID || pp->p_size == 0) + continue; + + /* Read softraid metadata. */ + bzero(md, SR_META_SIZE * DEV_BSIZE); + off = DL_SECTOBLK(&dip->disklabel, DL_GETPOFFSET(pp)); + off += SR_META_OFFSET; + error = dip->diskio(F_READ, dip, off, SR_META_SIZE, md); + if (error) + continue; + + /* Is this valid softraid metadata? */ + if (md->ssdi.ssd_magic != SR_MAGIC) + continue; + + /* XXX - validate checksum. */ + + /* Handle key disks separately... */ + if (md->ssdi.ssd_level == SR_KEYDISK_LEVEL) { + srprobe_keydisk_load(md); + continue; + } + + /* Locate chunk-specific metadata for this chunk. */ + mc = (struct sr_meta_chunk *)(md + 1); + mc += md->ssdi.ssd_chunk_id; + + bc = alloc(sizeof(struct sr_boot_chunk)); + bc->sbc_diskinfo = dip; + bc->sbc_disk = 0; + bc->sbc_part = DL_PARTNUM2NAME(i); + + bc->sbc_mm = 0; + + bc->sbc_chunk_id = md->ssdi.ssd_chunk_id; + bc->sbc_ondisk = md->ssd_ondisk; + bc->sbc_state = mc->scm_status; + + SLIST_FOREACH(bv, &sr_volumes, sbv_link) { + if (bcmp(&md->ssdi.ssd_uuid, &bv->sbv_uuid, + sizeof(md->ssdi.ssd_uuid)) == 0) + break; + } + + if (bv == NULL) { + bv = alloc(sizeof(struct sr_boot_volume)); + bzero(bv, sizeof(struct sr_boot_volume)); + bv->sbv_level = md->ssdi.ssd_level; + bv->sbv_volid = md->ssdi.ssd_volid; + bv->sbv_chunk_no = md->ssdi.ssd_chunk_no; + bv->sbv_flags = md->ssdi.ssd_vol_flags; + bv->sbv_size = md->ssdi.ssd_size; + bv->sbv_secsize = md->ssdi.ssd_secsize; + bv->sbv_data_blkno = md->ssd_data_blkno; + bcopy(&md->ssdi.ssd_uuid, &bv->sbv_uuid, + sizeof(md->ssdi.ssd_uuid)); + SLIST_INIT(&bv->sbv_chunks); + SLIST_INIT(&bv->sbv_meta_opt); + + /* Load optional metadata for this volume. */ + srprobe_meta_opt_load(md, &bv->sbv_meta_opt); + + /* Maintain volume order. */ + bv2 = NULL; + SLIST_FOREACH(bv1, &sr_volumes, sbv_link) { + if (bv1->sbv_volid > bv->sbv_volid) + break; + bv2 = bv1; + } + if (bv2 == NULL) + SLIST_INSERT_HEAD(&sr_volumes, bv, + sbv_link); + else + SLIST_INSERT_AFTER(bv2, bv, sbv_link); + } + + /* Maintain chunk order. */ + bc2 = NULL; + SLIST_FOREACH(bc1, &bv->sbv_chunks, sbc_link) { + if (bc1->sbc_chunk_id > bc->sbc_chunk_id) + break; + bc2 = bc1; + } + if (bc2 == NULL) + SLIST_INSERT_HEAD(&bv->sbv_chunks, + bc, sbc_link); + else + SLIST_INSERT_AFTER(bc2, bc, sbc_link); + + bv->sbv_chunks_found++; + } + } + + /* + * Assemble RAID volumes. + */ + volno = 0; + SLIST_FOREACH(bv, &sr_volumes, sbv_link) { + + /* Skip if this is a hotspare "volume". */ + if (bv->sbv_level == SR_HOTSPARE_LEVEL && + bv->sbv_chunk_no == 1) + continue; + + /* Determine current ondisk version. */ + bv->sbv_ondisk = 0; + SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) { + if (bc->sbc_ondisk > bv->sbv_ondisk) + bv->sbv_ondisk = bc->sbc_ondisk; + } + SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) { + if (bc->sbc_ondisk != bv->sbv_ondisk) + bc->sbc_state = BIOC_SDOFFLINE; + } + + /* XXX - Check for duplicate chunks. */ + + /* + * Validate that volume has sufficient chunks for + * read-only access. + * + * XXX - check chunk states. + */ + bv->sbv_state = BIOC_SVOFFLINE; + switch (bv->sbv_level) { + case 0: + case 'C': + case 'c': + if (bv->sbv_chunk_no == bv->sbv_chunks_found) + bv->sbv_state = BIOC_SVONLINE; + break; + + case 1: + case 0x1C: + if (bv->sbv_chunk_no == bv->sbv_chunks_found) + bv->sbv_state = BIOC_SVONLINE; + else if (bv->sbv_chunks_found > 0) + bv->sbv_state = BIOC_SVDEGRADED; + break; + } + + bv->sbv_unit = volno++; + if (bv->sbv_state != BIOC_SVOFFLINE) + printf(" sr%d%s", bv->sbv_unit, + bv->sbv_flags & BIOC_SCBOOTABLE ? "*" : ""); + } + + explicit_bzero(md, SR_META_SIZE * DEV_BSIZE); + free(md, SR_META_SIZE * DEV_BSIZE); +} + +int +sr_strategy(struct sr_boot_volume *bv, int rw, daddr_t blk, size_t size, + void *buf, size_t *rsize) +{ + struct diskinfo *sr_dip, *dip; + struct sr_boot_chunk *bc; + struct aes_xts_ctx ctx; + size_t i, j, nsect; + daddr_t blkno; + u_char iv[8]; + u_char *bp; + int err; + + /* We only support read-only softraid. */ + if (rw != F_READ) + return ENOTSUP; + + /* Partition offset within softraid volume. */ + sr_dip = (struct diskinfo *)bv->sbv_diskinfo; + blk += DL_SECTOBLK(&sr_dip->disklabel, + sr_dip->disklabel.d_partitions[DL_PARTNAME2NUM(bv->sbv_part)].p_offset); + + if (bv->sbv_level == 0) { + return ENOTSUP; + } else if (bv->sbv_level == 1) { + + /* Select first online chunk. */ + SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) + if (bc->sbc_state == BIOC_SDONLINE) + break; + if (bc == NULL) + return EIO; + + dip = (struct diskinfo *)bc->sbc_diskinfo; + blk += bv->sbv_data_blkno; + + /* XXX - If I/O failed we should try another chunk... */ + return dip->strategy(dip, rw, blk, size, buf, rsize); + + } else if (bv->sbv_level == 'C' || bv->sbv_level == 0x1C) { + + /* Select first online chunk. */ + SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) + if (bc->sbc_state == BIOC_SDONLINE) + break; + if (bc == NULL) + return EIO; + + dip = (struct diskinfo *)bc->sbc_diskinfo; + + /* XXX - select correct key. */ + aes_xts_setkey(&ctx, (u_char *)bv->sbv_keys, 64); + + nsect = (size + DEV_BSIZE - 1) / DEV_BSIZE; + for (i = 0; i < nsect; i++) { + blkno = blk + i; + bp = ((u_char *)buf) + i * DEV_BSIZE; + err = dip->strategy(dip, rw, bv->sbv_data_blkno + blkno, + DEV_BSIZE, bp, NULL); + if (err != 0) + return err; + + bcopy(&blkno, iv, sizeof(blkno)); + aes_xts_reinit(&ctx, iv); + for (j = 0; j < DEV_BSIZE; j += AES_XTS_BLOCKSIZE) + aes_xts_decrypt(&ctx, bp + j); + } + if (rsize != NULL) + *rsize = nsect * DEV_BSIZE; + + return err; + + } else + return ENOTSUP; +} + +/* + * Returns 0 if the MBR with the provided partition array is a GPT protective + * MBR, and returns 1 otherwise. A GPT protective MBR would have one and only + * one MBR partition, an EFI partition that either covers the whole disk or as + * much of it as is possible with a 32bit size field. + * + * Taken from kern/subr_disk.c. + * + * NOTE: MS always uses a size of UINT32_MAX for the EFI partition!** + */ +static int +gpt_chk_mbr(struct dos_partition *dp, u_int64_t dsize) +{ + struct dos_partition *dp2; + int efi, found, i; + u_int32_t psize; + + found = efi = 0; + for (dp2=dp, i=0; i < NDOSPART; i++, dp2++) { + if (dp2->dp_typ == DOSPTYP_UNUSED) + continue; + found++; + if (dp2->dp_typ != DOSPTYP_EFI) + continue; + if (letoh32(dp2->dp_start) != GPTSECTOR) + continue; + psize = letoh32(dp2->dp_size); + if (psize <= (dsize - GPTSECTOR) || psize == UINT32_MAX) + efi++; + } + if (found == 1 && efi == 1) + return (0); + + return (1); +} + +static uint64_t +findopenbsd_gpt(struct sr_boot_volume *bv, const char **err) +{ + struct gpt_header gh; + int i, part, found; + uint64_t lba; + uint32_t orig_csum, new_csum; + uint32_t ghsize, ghpartsize, ghpartnum, ghpartspersec; + uint32_t gpsectors; + const char openbsd_uuid_code[] = GPT_UUID_OPENBSD; + struct gpt_partition gp; + static struct uuid *openbsd_uuid = NULL, openbsd_uuid_space; + u_char *buf; + + /* Prepare OpenBSD UUID */ + if (openbsd_uuid == NULL) { + /* XXX: should be replaced by uuid_dec_be() */ + memcpy(&openbsd_uuid_space, openbsd_uuid_code, + sizeof(openbsd_uuid_space)); + openbsd_uuid_space.time_low = + betoh32(openbsd_uuid_space.time_low); + openbsd_uuid_space.time_mid = + betoh16(openbsd_uuid_space.time_mid); + openbsd_uuid_space.time_hi_and_version = + betoh16(openbsd_uuid_space.time_hi_and_version); + + openbsd_uuid = &openbsd_uuid_space; + } + + if (bv->sbv_secsize > 4096) { + *err = "disk sector > 4096 bytes\n"; + return (-1); + } + buf = alloc(bv->sbv_secsize); + if (buf == NULL) { + *err = "out of memory\n"; + return (-1); + } + bzero(buf, bv->sbv_secsize); + + /* GPT Header */ + lba = GPTSECTOR; + sr_strategy(bv, F_READ, lba * (bv->sbv_secsize / DEV_BSIZE), DEV_BSIZE, + buf, NULL); + memcpy(&gh, buf, sizeof(gh)); + + /* Check signature */ + if (letoh64(gh.gh_sig) != GPTSIGNATURE) { + *err = "bad GPT signature\n"; + free(buf, bv->sbv_secsize); + return (-1); + } + + if (letoh32(gh.gh_rev) != GPTREVISION) { + *err = "bad GPT revision\n"; + free(buf, bv->sbv_secsize); + return (-1); + } + + ghsize = letoh32(gh.gh_size); + if (ghsize < GPTMINHDRSIZE || ghsize > sizeof(struct gpt_header)) { + *err = "bad GPT header size\n"; + free(buf, bv->sbv_secsize); + return (-1); + } + + /* Check checksum */ + orig_csum = gh.gh_csum; + gh.gh_csum = 0; + new_csum = crc32(0, (unsigned char *)&gh, ghsize); + gh.gh_csum = orig_csum; + if (letoh32(orig_csum) != new_csum) { + *err = "bad GPT header checksum\n"; + free(buf, bv->sbv_secsize); + return (-1); + } + + lba = letoh64(gh.gh_part_lba); + ghpartsize = letoh32(gh.gh_part_size); + ghpartspersec = bv->sbv_secsize / ghpartsize; + ghpartnum = letoh32(gh.gh_part_num); + gpsectors = (ghpartnum + ghpartspersec - 1) / ghpartspersec; + new_csum = crc32(0L, Z_NULL, 0); + found = 0; + for (i = 0; i < gpsectors; i++, lba++) { + sr_strategy(bv, F_READ, lba * (bv->sbv_secsize / DEV_BSIZE), + bv->sbv_secsize, buf, NULL); + for (part = 0; part < ghpartspersec; part++) { + if (ghpartnum == 0) + break; + new_csum = crc32(new_csum, buf + part * sizeof(gp), + sizeof(gp)); + ghpartnum--; + if (found) + continue; + memcpy(&gp, buf + part * sizeof(gp), sizeof(gp)); + if (memcmp(&gp.gp_type, openbsd_uuid, + sizeof(struct uuid)) == 0) + found = 1; + } + } + + free(buf, bv->sbv_secsize); + + if (new_csum != letoh32(gh.gh_part_csum)) { + *err = "bad GPT entries checksum\n"; + return (-1); + } + if (found) + return (letoh64(gp.gp_lba_start)); + + return (-1); +} + +const char * +sr_getdisklabel(struct sr_boot_volume *bv, struct disklabel *label) +{ + struct dos_partition *dp; + struct dos_mbr mbr; + const char *err = NULL; + u_int start = 0; + char buf[DEV_BSIZE]; + int i; + + /* Check for MBR to determine partition offset. */ + bzero(&mbr, sizeof(mbr)); + sr_strategy(bv, F_READ, DOSBBSECTOR, sizeof(mbr), &mbr, NULL); + if (gpt_chk_mbr(mbr.dmbr_parts, bv->sbv_size / + (bv->sbv_secsize / DEV_BSIZE)) == 0) { + start = findopenbsd_gpt(bv, &err); + if (start == (u_int)-1) { + if (err != NULL) + return (err); + return "no OpenBSD partition\n"; + } + } else if (mbr.dmbr_sign == DOSMBR_SIGNATURE) { + + /* Search for OpenBSD partition */ + for (i = 0; i < NDOSPART; i++) { + dp = &mbr.dmbr_parts[i]; + if (!dp->dp_size) + continue; + if (dp->dp_typ == DOSPTYP_OPENBSD) { + start = dp->dp_start; + break; + } + } + } + + /* Read the disklabel. */ + sr_strategy(bv, F_READ, + start * (bv->sbv_secsize / DEV_BSIZE) + DOS_LABELSECTOR, + sizeof(buf), buf, NULL); + +#ifdef BIOS_DEBUG + printf("sr_getdisklabel: magic %lx\n", + ((struct disklabel *)buf)->d_magic); + for (i = 0; i < MAXPARTITIONS16; i++) + printf("part %c: type = %d, size = %d, offset = %d\n", + DL_PARTNUM2NAME(i), + (int)((struct disklabel *)buf)->d_partitions[i].p_fstype, + (int)((struct disklabel *)buf)->d_partitions[i].p_size, + (int)((struct disklabel *)buf)->d_partitions[i].p_offset); +#endif + + /* Fill in disklabel */ + return (getdisklabel(buf, label)); +} + +int +sropen(struct open_file *f, ...) +{ + struct diskinfo *dip = NULL; + struct sr_boot_volume *bv; + va_list ap; + u_int unit, part; + + va_start(ap, f); + unit = va_arg(ap, u_int); + part = va_arg(ap, u_int); + va_end(ap); + + /* Create a fake diskinfo for this softraid volume. */ + SLIST_FOREACH(bv, &sr_volumes, sbv_link) + if (bv->sbv_unit == unit) + break; + if (bv == NULL) { + printf("Unknown device: sr%d\n", unit); + return EADAPT; + } + + if ((bv->sbv_level == 'C' || bv->sbv_level == 0x1C) + && bv->sbv_keys == NULL) + if (sr_crypto_unlock_volume(bv) != 0) + return EPERM; + + if (bv->sbv_diskinfo == NULL) { + dip = alloc(sizeof(struct diskinfo)); + bzero(dip, sizeof(*dip)); + dip->diskio = srdiskio; + dip->strategy = srstrategy; + bv->sbv_diskinfo = dip; + dip->sr_vol = bv; + } + + dip = bv->sbv_diskinfo; + + if ((dip->flags & DISKINFO_FLAG_GOODLABEL) == 0) { + /* Attempt to read disklabel. */ + bv->sbv_part = 'c'; + if (sr_getdisklabel(bv, &dip->disklabel)) + return ERDLAB; + dip->flags |= DISKINFO_FLAG_GOODLABEL; + } + + bv->sbv_part = DL_PARTNUM2NAME(part); + + bootdev_dip = dip; + f->f_devdata = dip; + + return 0; +} + +int +srstrategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf, + size_t *rsize) +{ + struct diskinfo *dip = (struct diskinfo *)devdata; + return sr_strategy(dip->sr_vol, rw, blk, size, buf, rsize); +} + +int +srdiskio(int rw, struct diskinfo *dip, u_int off, int nsect, void *buf) +{ + return dip->diskio(rw, dip, off, nsect, buf); +} + +int +srclose(struct open_file *f) +{ + f->f_devdata = NULL; + + return 0; +} + +int +srioctl(struct open_file *f, u_long cmd, void *data) +{ + return 0; +} diff --git sys/arch/loongarch64/stand/efiboot/softraid_loongarch64.h sys/arch/loongarch64/stand/efiboot/softraid_loongarch64.h new file mode 100644 index 00000000000..1bdae875cdc --- /dev/null +++ sys/arch/loongarch64/stand/efiboot/softraid_loongarch64.h @@ -0,0 +1,33 @@ +/* $OpenBSD: softraid_loongarch64.h,v 1.2 2023/01/16 21:30:46 kn Exp $ */ + +/* + * Copyright (c) 2012 Joel Sing + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SOFTRAID_LOONGARCH64_H_ +#define _SOFTRAID_LOONGARCH64_H_ + +void srprobe(void); + +const char *sr_getdisklabel(struct sr_boot_volume *, struct disklabel *); +int sr_strategy(struct sr_boot_volume *, int, daddr_t, size_t, + void *, size_t *); +int sropen(struct open_file *, ...); +int srstrategy(void *, int, daddr_t, size_t, void *, size_t *); +int srdiskio(int, struct diskinfo *, u_int, int, void *); +int srclose(struct open_file *); +int srioctl(struct open_file *, u_long, void *); + +#endif /* _SOFTRAID_LOONGARCH64_H */ diff --git sys/arch/loongarch64/stand/efiboot/start.S sys/arch/loongarch64/stand/efiboot/start.S new file mode 100644 index 00000000000..7d1258a3acc --- /dev/null +++ sys/arch/loongarch64/stand/efiboot/start.S @@ -0,0 +1,175 @@ +/* $OpenBSD: start.S,v 1.1 2021/04/28 19:01:00 drahn Exp $ */ +/*- + * Copyright (c) 2014 Andrew Turner + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: head/sys/boot/efi/loader/arch/arm64/start.S 282727 2015-05-10 13:24:26Z ian $ + */ + +/* + * We need to be a PE32+ file for EFI. On some architectures we can use + * objcopy to create the correct file, however on arm64 we need to do + * it ourselves. + */ + +#define IMAGE_FILE_MACHINE_LOONGARCH64 0x6264 + +#define IMAGE_SCN_CNT_CODE 0x00000020 +#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define IMAGE_SCN_MEM_READ 0x40000000 + + .section .peheader, "a" +efi_start: + /* The MS-DOS Stub, only used to get the offset of the COFF header */ + .ascii "MZ" + .short 0 + .space 0x38 + .long pe_sig - efi_start + + /* The PE32 Signature. Needs to be 8-byte aligned */ + .align 3 +pe_sig: + .ascii "PE" + .short 0 +coff_head: + .short IMAGE_FILE_MACHINE_LOONGARCH64 /* RISCV64 file */ + .short 2 /* 2 Sections */ + .long 0 /* Timestamp */ + .long 0 /* No symbol table */ + .long 0 /* No symbols */ + .short section_table - optional_header /* Optional header size */ + .short 0 /* Characteristics TODO: Fill in */ + +optional_header: + .short 0x020b /* PE32+ (64-bit addressing) */ + .byte 0 /* Major linker version */ + .byte 0 /* Minor linker version */ + .long _edata - _end_header /* Code size */ + .long 0 /* No initialized data */ + .long 0 /* No uninitialized data */ + .long _start - efi_start /* Entry point */ + .long _end_header - efi_start /* Start of code */ + +optional_windows_header: + .quad 0 /* Image base */ + .long 32 /* Section Alignment */ + .long 8 /* File alignment */ + .short 0 /* Major OS version */ + .short 0 /* Minor OS version */ + .short 0 /* Major image version */ + .short 0 /* Minor image version */ + .short 0 /* Major subsystem version */ + .short 0 /* Minor subsystem version */ + .long 0 /* Win32 version */ + .long _edata - efi_start /* Image size */ + .long _end_header - efi_start /* Header size */ + .long 0 /* Checksum */ + .short 0xa /* Subsystem (EFI app) */ + .short 0 /* DLL Characteristics */ + .quad 0 /* Stack reserve */ + .quad 0 /* Stack commit */ + .quad 0 /* Heap reserve */ + .quad 0 /* Heap commit */ + .long 0 /* Loader flags */ + .long 6 /* Number of RVAs */ + + /* RVAs: */ + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + +section_table: + /* We need a .reloc section for EFI */ + .ascii ".reloc" + .byte 0 + .byte 0 /* Pad to 8 bytes */ + .long 0 /* Virtual size */ + .long 0 /* Virtual address */ + .long 0 /* Size of raw data */ + .long 0 /* Pointer to raw data */ + .long 0 /* Pointer to relocations */ + .long 0 /* Pointer to line numbers */ + .short 0 /* Number of relocations */ + .short 0 /* Number of line numbers */ + .long (IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | \ + IMAGE_SCN_MEM_DISCARDABLE) /* Characteristics */ + + /* The contents of the loader */ + .ascii ".text" + .byte 0 + .byte 0 + .byte 0 /* Pad to 8 bytes */ + .long _edata - _end_header /* Virtual size */ + .long _end_header - efi_start /* Virtual address */ + .long _edata - _end_header /* Size of raw data */ + .long _end_header - efi_start /* Pointer to raw data */ + .long 0 /* Pointer to relocations */ + .long 0 /* Pointer to line numbers */ + .short 0 /* Number of relocations */ + .short 0 /* Number of line numbers */ + .long (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | \ + IMAGE_SCN_MEM_READ) /* Characteristics */ +_end_header: + + .text + .globl _start +_start: + /* Save the boot params to the stack */ + addi.d $sp, $sp, -16 + st.d $a0, $sp, 0 + st.d $a1, $sp, 8 + + la $a0, __bss_start + la $a1, __bss_end + + b 2f + +1: + st.d $zero, $a0, 0 + addi.d $a0, $a0, 8 +2: + bltu $a0, $a1, 1b + + la $a0, ImageBase + la $a1, _DYNAMIC + + bl self_reloc + + ld.d $a0, $sp, 0 + ld.d $a1, $sp, 8 + addi.d $sp, $sp, 16 + + bl efi_main + +1: b 1b + + .data + .align 4 +#include "dt_blob.S" + diff --git sys/stand/efi/include/loongarch64/efibind.h sys/stand/efi/include/loongarch64/efibind.h new file mode 100644 index 00000000000..1ea88acdf36 --- /dev/null +++ sys/stand/efi/include/loongarch64/efibind.h @@ -0,0 +1,22 @@ +/* Public Domain. */ + +#include + +typedef int8_t INT8; +typedef uint8_t UINT8; +typedef int16_t INT16; +typedef uint16_t UINT16; +typedef int32_t INT32; +typedef uint32_t UINT32; +typedef int64_t INT64; +typedef uint64_t UINT64; + +typedef void VOID; + +typedef int64_t INTN; +typedef uint64_t UINTN; + +#define INTERFACE_DECL(x) struct x +#define EFIAPI + +#define EFIERR(x) (0x8000000000000000 | x) diff --git sys/sys/exec.h sys/sys/exec.h index ea2c98be2ef..09df4e021e8 100644 --- sys/sys/exec.h +++ sys/sys/exec.h @@ -241,6 +241,7 @@ extern int stackgap_random; #define MID_HPUX800 0x20B /* hp800 HP-UX binary pa1.0 */ #define MID_HPPA11 0x210 /* hp700 HP-UX binary pa1.1 */ #define MID_HPPA20 0x214 /* hp700 HP-UX binary pa2.0 */ +#define MID_LOONGARCH64 162 /* LoongArch64 temporary */ #include diff --git sys/sys/exec_elf.h sys/sys/exec_elf.h index eda016fcd9c..f8b9af672ca 100644 --- sys/sys/exec_elf.h +++ sys/sys/exec_elf.h @@ -192,6 +192,7 @@ typedef struct { #define EM_VAX 75 /* DEC VAX */ #define EM_AARCH64 183 /* ARM 64-bit architecture (AArch64) */ #define EM_RISCV 243 /* RISC-V */ +#define EM_LOONGARCH 258 /* LoongArch */ /* Non-standard */ #define EM_ALPHA_EXP 0x9026 /* DEC ALPHA */ diff --git usr.bin/gprof/loongarch64.c usr.bin/gprof/loongarch64.c new file mode 100644 index 00000000000..8da3dddaf4b --- /dev/null +++ usr.bin/gprof/loongarch64.c @@ -0,0 +1,8 @@ +/* $OpenBSD: riscv64.c,v 1.1 2021/04/29 18:48:30 drahn Exp $ */ +#include "gprof.h" + +void +findcall(nltype *parentp, unsigned long p_lowpc, unsigned long p_highpc) +{ + /* not supported. */ +} diff --git usr.bin/gprof/loongarch64.h usr.bin/gprof/loongarch64.h new file mode 100644 index 00000000000..e35e7cd72a3 --- /dev/null +++ usr.bin/gprof/loongarch64.h @@ -0,0 +1,46 @@ +/* $OpenBSD: riscv64.h,v 1.1 2021/04/29 18:48:30 drahn Exp $ */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)sparc.h 8.1 (Berkeley) 6/6/93 + */ + +/* + * offset (in bytes) of the code from the entry address of a routine. + * (see asgnsamples for use and explanation.) + */ +#define OFFSET_OF_CODE 0 +#define UNITS_TO_CODE (OFFSET_OF_CODE / sizeof(UNIT)) + +enum opermodes { dummy }; +typedef enum opermodes operandenum;