diff options
-rw-r--r-- | .gitignore | 6 | ||||
-rw-r--r-- | 3rd-party/.gitignore | 1 | ||||
-rw-r--r-- | 3rd-party/MS-LCID.txt | 4073 | ||||
-rw-r--r-- | CMakeLists.txt | 32 | ||||
-rw-r--r-- | HACKING.md | 10 | ||||
-rw-r--r-- | PLAN.md | 2 | ||||
-rw-r--r-- | cmd/sbc_harness/CMakeLists.txt | 23 | ||||
-rw-r--r-- | cmd/sbc_harness/config/config.h (renamed from config.h) | 6 | ||||
-rw-r--r-- | cmd/sbc_harness/config/tusb_config.h (renamed from libusb/tusb_config.h) | 0 | ||||
-rw-r--r-- | cmd/sbc_harness/main.c (renamed from cmd/harness/main.c) | 0 | ||||
-rw-r--r-- | cmd/sbc_harness/usb_keyboard.c (renamed from cmd/harness/usb_keyboard.c) | 0 | ||||
-rw-r--r-- | cmd/sbc_harness/usb_keyboard.h (renamed from cmd/harness/usb_keyboard.h) | 0 | ||||
-rw-r--r-- | cmd/srv9p/CMakeLists.txt | 15 | ||||
l--------- | cmd/srv9p/config/config.h | 1 | ||||
-rw-r--r-- | lib9p/.editorconfig | 2 | ||||
-rw-r--r-- | lib9p/.gitignore | 2 | ||||
-rw-r--r-- | lib9p/9P2000.e.txt | 4 | ||||
-rw-r--r-- | lib9p/9P2000.u.txt | 25 | ||||
-rw-r--r-- | lib9p/9p.c (renamed from lib9p/defs.c) | 39 | ||||
-rw-r--r-- | lib9p/9p.h | 15 | ||||
-rw-r--r-- | lib9p/CMakeLists.txt | 34 | ||||
-rwxr-xr-x | lib9p/defs.gen | 456 | ||||
-rw-r--r-- | lib9p/defs.h | 74 | ||||
-rw-r--r-- | lib9p/include/lib9p/9p.h | 72 | ||||
-rw-r--r-- | lib9p/include/lib9p/_types.h | 285 | ||||
-rwxr-xr-x | lib9p/include/lib9p/linux-errno.h.gen (renamed from lib9p/linux-errno.h.gen) | 0 | ||||
-rw-r--r-- | lib9p/include/lib9p/srv.h | 16 | ||||
-rw-r--r-- | lib9p/internal.h | 79 | ||||
-rw-r--r-- | lib9p/misc.txt | 24 | ||||
-rw-r--r-- | lib9p/srv.h | 16 | ||||
-rw-r--r-- | lib9p/types.c | 1331 | ||||
-rwxr-xr-x | lib9p/types.gen | 611 | ||||
-rw-r--r-- | libcr/CMakeLists.txt | 10 | ||||
-rw-r--r-- | libcr/coroutine.c | 2 | ||||
-rw-r--r-- | libcr/include/libcr/coroutine.h (renamed from libcr/coroutine.h) | 2 | ||||
-rw-r--r-- | libcr_ipc/CMakeLists.txt | 10 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/chan.h (renamed from libcr_ipc/coroutine_chan.h) | 0 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/rpc.h (renamed from libcr_ipc/coroutine_rpc.h) | 0 | ||||
-rw-r--r-- | libcr_ipc/include/libcr_ipc/sema.h (renamed from libcr_ipc/coroutine_sema.h) | 0 | ||||
-rw-r--r-- | libcr_ipc/sema.c (renamed from libcr_ipc/coroutine_sema.c) | 0 | ||||
-rw-r--r-- | libnetio/CMakeLists.txt | 10 | ||||
-rw-r--r-- | libusb/CMakeLists.txt | 23 | ||||
-rw-r--r-- | libusb/include/libusb/tusb_helpers.h (renamed from libusb/tusb_helpers.h) | 0 | ||||
-rwxr-xr-x | libusb/include/libusb/tusb_helpers.h.gen (renamed from libusb/tusb_helpers.h.gen) | 20 | ||||
-rw-r--r-- | libusb/include/libusb/usb_common.h (renamed from libusb/usb_common.h) | 0 |
45 files changed, 6655 insertions, 676 deletions
@@ -2,8 +2,4 @@ *.log .mypy_cache/ -/build/ - -/tusb_helpers.h - -/srv9p +build/ diff --git a/3rd-party/.gitignore b/3rd-party/.gitignore deleted file mode 100644 index 4305236..0000000 --- a/3rd-party/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/MS-LCID.txt diff --git a/3rd-party/MS-LCID.txt b/3rd-party/MS-LCID.txt new file mode 100644 index 0000000..6bc95b1 --- /dev/null +++ b/3rd-party/MS-LCID.txt @@ -0,0 +1,4073 @@ +[MS-LCID]: +Windows Language Code Identifier (LCID) Reference + + +Intellectual Property Rights Notice for Open Specifications Documentation + Technical Documentation. Microsoft publishes Open Specifications documentation (“this + documentation”) for protocols, file formats, data portability, computer languages, and standards + support. Additionally, overview documents cover inter-protocol relationships and interactions. + Copyrights. This documentation is covered by Microsoft copyrights. Regardless of any other + terms that are contained in the terms of use for the Microsoft website that hosts this + documentation, you can make copies of it in order to develop implementations of the technologies + that are described in this documentation and can distribute portions of it in your implementations + that use these technologies or in your documentation as necessary to properly document the + implementation. You can also distribute in your implementation, with or without modification, any + schemas, IDLs, or code samples that are included in the documentation. This permission also + applies to any documents that are referenced in the Open Specifications documentation. + No Trade Secrets. Microsoft does not claim any trade secret rights in this documentation. + Patents. Microsoft has patents that might cover your implementations of the technologies + described in the Open Specifications documentation. Neither this notice nor Microsoft's delivery of + this documentation grants any licenses under those patents or any other Microsoft patents. + However, a given Open Specifications document might be covered by the Microsoft Open + Specifications Promise or the Microsoft Community Promise. If you would prefer a written license, + or if the technologies described in this documentation are not covered by the Open Specifications + Promise or Community Promise, as applicable, patent licenses are available by contacting + iplg@microsoft.com. + License Programs. To see all of the protocols in scope under a specific license program and the + associated patents, visit the Patent Map. + Trademarks. The names of companies and products contained in this documentation might be + covered by trademarks or similar intellectual property rights. This notice does not grant any + licenses under those rights. For a list of Microsoft trademarks, visit + www.microsoft.com/trademarks. + Fictitious Names. The example companies, organizations, products, domain names, email + addresses, logos, people, places, and events that are depicted in this documentation are fictitious. + No association with any real company, organization, product, domain name, email address, logo, + person, place, or event is intended or should be inferred. +Reservation of Rights. All other rights are reserved, and this notice does not grant any rights other +than as specifically described above, whether by implication, estoppel, or otherwise. + +Tools. The Open Specifications documentation does not require the use of Microsoft programming +tools or programming environments in order for you to develop an implementation. If you have access +to Microsoft programming tools and environments, you are free to take advantage of them. Certain +Open Specifications documents are intended for use in conjunction with publicly available standards +specifications and network programming art and, as such, assume that the reader either is familiar +with the aforementioned material or has immediate access to it. + +Support. For questions and support, please contact dochelp@microsoft.com. + + + + + 1 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 +Revision Summary + + Revision Revision + Date History Class Comments + + 2/14/2008 2.1.3 Editorial Changed language and formatting in the technical content. + + 3/14/2008 2.1.4 Editorial Changed language and formatting in the technical content. + + 6/20/2008 2.1.5 Editorial Changed language and formatting in the technical content. + + 7/25/2008 2.1.6 Editorial Changed language and formatting in the technical content. + + 8/29/2008 2.2 Minor Clarified the meaning of the technical content. + + 10/24/2008 2.2.1 Editorial Changed language and formatting in the technical content. + + 12/5/2008 2.3 Minor Clarified the meaning of the technical content. + + 1/16/2009 2.3.1 Editorial Changed language and formatting in the technical content. + + 2/27/2009 2.3.2 Editorial Changed language and formatting in the technical content. + + 4/10/2009 2.4 Minor Clarified the meaning of the technical content. + + 5/22/2009 2.4.1 Editorial Changed language and formatting in the technical content. + + 7/2/2009 2.4.2 Editorial Changed language and formatting in the technical content. + + 8/14/2009 2.4.3 Editorial Changed language and formatting in the technical content. + + 9/25/2009 3.0 Major Updated and revised the technical content. + + 11/6/2009 3.0.1 Editorial Changed language and formatting in the technical content. + + 12/18/2009 3.0.2 Editorial Changed language and formatting in the technical content. + + 1/29/2010 3.1 Minor Clarified the meaning of the technical content. + + 3/12/2010 3.1.1 Editorial Changed language and formatting in the technical content. + + 4/23/2010 3.1.2 Editorial Changed language and formatting in the technical content. + + 6/4/2010 3.1.3 Editorial Changed language and formatting in the technical content. + + No changes to the meaning, language, or formatting of the + 7/16/2010 3.1.3 None + technical content. + + No changes to the meaning, language, or formatting of the + 8/27/2010 3.1.3 None + technical content. + + No changes to the meaning, language, or formatting of the + 10/8/2010 3.1.3 None + technical content. + + No changes to the meaning, language, or formatting of the + 11/19/2010 3.1.3 None + technical content. + + No changes to the meaning, language, or formatting of the + 1/7/2011 3.1.3 None + technical content. + + No changes to the meaning, language, or formatting of the + 2/11/2011 3.1.3 None + technical content. + + No changes to the meaning, language, or formatting of the + 3/25/2011 3.1.3 None + technical content. + + + 2 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Revision Revision + Date History Class Comments + + No changes to the meaning, language, or formatting of the + 5/6/2011 3.1.3 None + technical content. + + 6/17/2011 3.2 Minor Clarified the meaning of the technical content. + + No changes to the meaning, language, or formatting of the + 9/23/2011 3.2 None + technical content. + + 12/16/2011 4.0 Major Updated and revised the technical content. + + No changes to the meaning, language, or formatting of the + 3/30/2012 4.0 None + technical content. + + 7/12/2012 5.0 Major Updated and revised the technical content. + + No changes to the meaning, language, or formatting of the + 10/25/2012 5.0 None + technical content. + + No changes to the meaning, language, or formatting of the + 1/31/2013 5.0 None + technical content. + + 8/8/2013 6.0 Major Updated and revised the technical content. + + 11/14/2013 6.1 Minor Clarified the meaning of the technical content. + + No changes to the meaning, language, or formatting of the + 2/13/2014 6.1 None + technical content. + + No changes to the meaning, language, or formatting of the + 5/15/2014 6.1 None + technical content. + + 6/30/2015 7.0 Major Significantly changed the technical content. + + No changes to the meaning, language, or formatting of the + 10/16/2015 7.0 None + technical content. + + 7/14/2016 8.0 Major Significantly changed the technical content. + + 3/16/2017 9.0 Major Significantly changed the technical content. + + No changes to the meaning, language, or formatting of the + 6/1/2017 9.0 None + technical content. + + 9/15/2017 10.0 Major Significantly changed the technical content. + + 12/1/2017 11.0 Major Significantly changed the technical content. + + 9/12/2018 12.0 Major Significantly changed the technical content. + + 3/13/2019 13.0 Major Significantly changed the technical content. + + 3/4/2020 14.0 Major Significantly changed the technical content. + + 4/7/2021 14.1 Minor Clarified the meaning of the technical content. + + 6/25/2021 15.0 Major Significantly changed the technical content. + + 4/23/2024 16.0 Major Significantly changed the technical content. + + + + + 3 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 +Table of Contents + 1 Introduction ............................................................................................................ 5 + 1.1 Glossary ........................................................................................................... 5 + 1.2 References ........................................................................................................ 6 + 1.2.1 Normative References ................................................................................... 6 + 1.2.2 Informative References ................................................................................. 6 + 1.3 Overview .......................................................................................................... 6 + 1.4 Relationship to Protocols and Other Structures ...................................................... 7 + 1.5 Applicability Statement ....................................................................................... 7 + 1.6 Versioning and Localization ................................................................................. 7 + 1.7 Vendor-Extensible Fields ..................................................................................... 7 + 2 Structures ............................................................................................................... 8 + 2.1 Language Code Identifiers ................................................................................... 8 + 2.2 LCID Structure ................................................................................................... 8 + 2.2.1 Locale Names without LCIDs ........................................................................ 25 + 3 Structure Examples ............................................................................................... 27 + 4 Security Considerations ......................................................................................... 28 + 5 Appendix A: Product Behavior ............................................................................... 29 + 6 Change Tracking .................................................................................................... 60 + 7 Index ..................................................................................................................... 61 + + + + + 4 / 61 + [MS-LCID] - v20240423 + Windows Language Code Identifier (LCID) Reference + Copyright © 2024 Microsoft Corporation + Release: April 23, 2024 +1 Introduction +This document provides an overview of language code identifiers (LCIDs), also known as culture +identifiers, which are being deprecated, and the preferred alternate system of locale codes, which +specify a set of locale identifiers that designate culture-specific information such as how text is sorted, +how a date is formatted, and the display format for numbers and currency. + +Sections 1.7 and 2 of this specification are normative. All other sections and examples in this +specification are informative. + + +1.1 Glossary + +This document uses the following terms: + + alternate sort: Specifies an alternate collation for a language that has multiple methods for + sorting data. For example, German has both "Dictionary" and "Phone Book" sorts. "Dictionary" + sorting (de-DE) is the default for German, but developers can specify the alternate "Phone + Book" sort (de-DE_phoneb) explicitly. + + Chinese BIG5 order: Ideographs are ordered according to the code point values of the Taiwanese + BIG5 industrial standard. + + Chinese radical/stroke order: Ideographs are ordered according to radical stroke count. + + Chinese Unicode order: Deprecated. Identical to the default sort information used for English. + + Georgian modern order: An order for the Georgian language that places archaic characters that + are no longer used at the end of the alphabet. + + Georgian traditional order: An order for the Georgian language that intersperses archaic + characters that are no longer used among the rest of the alphabet in their traditional places. + + German phone book order: An order that equates Ä, Ö, and Ü with AE, OE, and UE, respectively + (commonly used in German phone books). + + Hungarian default order: The typical expected alphabetical order for the Hungarian language. + + Hungarian technical order: A sort order that places capital letters before lowercase ones, unlike + most sorts, which sort lowercase first. + + Japanese radical/stroke sort order: Ideographs are ordered by their radical and stroke + components, much like an ideographic dictionary might do. + + Japanese Unicode order: Deprecated. Identical to the default sort information used for English, + except that the backslash (\) is equal to the currency symbol, 0x00A5, the yen sign. + + Japanese XJIS order: Ideographs are ordered according to the code point values of the [JIS X + 208] and [JIS X 212] government standards. + + Korean KSC order: Ideographs are ordered according to the Korean Hangul pronunciation, as + specified in the Korean [KSC5601] government standard. + + Korean Unicode order: Deprecated. Identical to the default sort information used for English, + except that the backslash (\) is equal to the currency symbol, 0x20A9, the won sign. + + neutral locale: A locale describing a language without any region-specific information. + + PRC Chinese phonetic order: Ideographs are ordered according to their A to Z pronunciation + order. + + + 5 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + PRC Chinese stroke count order: Ideographs are ordered according to their stroke count. + + specific locale: A locale describing a language that has a qualifying regional variant. For example, + variants for English can be en-US or en-GB. + + Traditional Chinese Bopomofo order: Ideographs are ordered by their most common Mandarin + pronunciation, using the Chinese Bopomofo order of the pronunciations. + + MAY, SHOULD, MUST, SHOULD NOT, MUST NOT: These terms (in all caps) are used as defined + in [RFC2119]. All statements of optional behavior use either MAY, SHOULD, or SHOULD NOT. + + +1.2 References + +Links to a document in the Microsoft Open Specifications library point to the correct section in the +most recently published version of the referenced document. However, because individual documents +in the library are not updated at the same time, the section numbers in the documents may not +match. You can confirm the correct section numbering by checking the Errata. + + +1.2.1 Normative References + +We conduct frequent surveys of the normative references to assure their continued availability. If you +have any issue with finding a normative reference, please contact dochelp@microsoft.com. We will +assist you in finding the relevant information. + +[ISO-15924] International Organization for Standardization, "ISO 15924 Registration Authority", +http://www.unicode.org/iso15924/ + +[ISO-3166] International Organization for Standardization, "Codes for the representation of names of +countries and their subdivisions -- Part1: Country codes", ISO 3166-1:2013, November 2013, +http://www.iso.org/iso/home/store/catalogue_tc/catalogue_detail.htm?csnumber=63545 + +Note There is a charge to download the specification. + +[ISO-639] International Organization for Standardization, "Codes for the representation of names of +languages -- Part 2: Alpha-3 code", ISO 639-2:1998, +http://www.iso.org/iso/iso_catalogue/catalogue_tc/catalogue_detail.htm?csnumber=4767 + +Note There is a charge to download this specification. + +[MS-DTYP] Microsoft Corporation, "Windows Data Types". + +[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC +2119, March 1997, https://www.rfc-editor.org/info/rfc2119 + +[RFC5646] Phillips, A, and Davis, M., "Tags for Identifying Languages", BCP 47, RFC 4646, September +2006, https://www.rfc-editor.org/info/rfc5646 + + +1.2.2 Informative References + +[KSC5601] Korea Industrial Standards Association, "Code for Information Interchange (Hangul and +Hanja)", Korean Industrial Standard, 1987, Ref. No. KS C 5601-1987. + + +1.3 Overview + +The LCID structure is used to identify specific languages for the purpose of customizing software for +particular languages and cultures. For example, it can specify the way dates, times, and numbers are +formatted as strings. It can also specify paper sizes and preferred sort order based on language +elements. + + 6 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 +LCIDs are being deprecated, and implementers are strongly encouraged to use locale names instead. +LCIDs can be used for backward compatibility, but as noted in section 2.2.1, there is no guarantee of +LCID uniqueness when used with valid locale names not otherwise associated with an LCID. + + +1.4 Relationship to Protocols and Other Structures + +This structure is related to protocols and structures that need to make special cases for specific +languages and cultures. + + +1.5 Applicability Statement + +This structure applies in scenarios where special cases need to be made for specific languages and +cultures. + + +1.6 Versioning and Localization + +This structure serves to identify particular languages, locales, and cultures. + + +1.7 Vendor-Extensible Fields + +None. + + + + + 7 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 +2 Structures + +2.1 Language Code Identifiers + +LCIDs are identifiers used to specify localizable information. They are also known as culture identifiers +in the Microsoft .NET Framework environment. + +The name of a culture consists of its [ISO-639] language code, its [ISO-3166] country/region code, +and an optional [ISO-15924] script tag for the written language. For example, the name of the culture +in which the language is Bosnian (as written in Latin script and used in the Bosnia and Herzegovina +region) is bs-Latn-BA.<1><2><3> + + +2.2 LCID Structure + +This protocol references commonly used data types as defined in [MS-DTYP]. + +An LCID is a 4-byte value. The value supplied in an LCID is a standard numeric substitution for the +international [RFC5646] string. + +The following diagram is shown in host byte order. + + 1 2 3 +0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + + Reserved Sort ID Language ID + + +Reserved (12 bits): This field is reserved for future use. It MUST be 0. + +Sort ID (4 bits): The sort order. In most cases, this value can be 0x0, which indicates a default sort + (SORT_DEFAULT). However, other values can be used when an alternate sort is required. These + alternate values are listed in the following table. For example, 0x0407 (German - Germany) + becomes 0x10407 when SORT_GERMAN_PHONE_BOOK is used. + + Value Meaning + + SORT_CHINESE_BIG5 Chinese BIG5 order + 0x0 Default sort for Simplified Chinese locales + Use with zh-TW, zh-HK, or zh-MO + + SORT_CHINESE_PRCP PRC Chinese phonetic order + 0x0 Default sort for Traditional Chinese locales. + Use with zn-CN or zh-SG + + SORT_DEFAULT Default sort order + 0x0 + + SORT_GEORGIAN_TRADITIONAL Georgian traditional order + 0x0 Default sort for Georgian, use with ka-GE + + SORT_HUNGARIAN_DEFAULT Hungarian default order + 0x0 Default sort for Hungarian, use with hu-HU + + SORT_JAPANESE_XJIS Japanese XJIS order + 0x0 Use with ja-JP + + SORT_KOREAN_KSC Korean KSC order + + + 8 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Value Meaning + + 0x0 Default sort for Korean, use with ko-KR + + SORT_CHINESE_UNICODE Chinese Unicode order<4> + 0x1 Do not use, deprecated + + SORT_GEORGIAN_MODERN Georgian modern order + 0x1 Use with ka-GE, resolves to ka-GE_modern + + SORT_GERMAN_PHONE_BOOK German phone book order + 0x1 Use with de-DE, resolves to de-DE_phoneb + + SORT_HUNGARIAN_TECHNICAL Hungarian technical order + 0x1 Use with hu-HU, resolves to hu-HU_technl + + SORT_JAPANESE_UNICODE Japanese Unicode order<5> + 0x1 Do not use, deprecated + + SORT_KOREAN_UNICODE Korean Unicode order<6> + 0x1 Do not use, deprecated + + SORT_CHINESE_PRC PRC Chinese stroke count order + 0x2 Use with zh-CN, resolves to zh-CN_stroke + Use with zh-SG, resolves to zh-SG_stroke + + SORT_CHINESE_BOPOMOFO Traditional Chinese Bopomofo order + 0x3 Use with zh-TW, resolves to zh-TW_pronun + + SORT_CHINESE_RADICALSTROKE Chinese radical/stroke order<7> + 0x4 Use with zh-HK, resolves to zh-HK_radstr + Use with zh-MO, resolves to zh-MO_radstr + Use with zh-TW, resolves to zh-TW_radstr + + SORT_JAPANESE_RADICALSTROKE Japanese radical/stroke sort order + 0x4 Use with ja-JP, resolves to ja-JP_radstr + + +Language ID (2 bytes): The language component of the LCID.<8> + + Language ID Language tag + + 0x0001 ar + + 0x0002 bg + + 0x0003 ca + + 0x0004 zh-Hans + + 0x0005 cs + + 0x0006 da + + 0x0007 de + + 0x0008 el + + 0x0009 en + + 0x000A es + + + 9 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x000B fi + + 0x000C fr + + 0x000D he + + 0x000E hu + + 0x000F is + + 0x0010 it + + 0x0011 ja + + 0x0012 ko + + 0x0013 nl + + 0x0014 no + + 0x0015 pl + + 0x0016 pt + + 0x0017 rm + + 0x0018 ro + + 0x0019 ru + + 0x001A hr + + 0x001B sk + + 0x001C sq + + 0x001D sv + + 0x001E th + + 0x001F tr + + 0x0020 ur + + 0x0021 id + + 0x0022 uk + + 0x0023 be + + 0x0024 sl + + 0x0025 et + + 0x0026 lv + + 0x0027 lt + + 0x0028 tg + + 0x0029 fa + + 0x002A vi + + + 10 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x002B hy + + 0x002C az + + 0x002D eu + + 0x002E hsb + + 0x002F mk + + 0x0030 st + + 0x0031 ts + + 0x0032 tn + + 0x0033 ve + + 0x0034 xh + + 0x0035 zu + + 0x0036 af + + 0x0037 ka + + 0x0038 fo + + 0x0039 hi + + 0x003A mt + + 0x003B se + + 0x003C ga + + 0x003D yi, reserved + + 0x003E ms + + 0x003F kk + + 0x0040 ky + + 0x0041 sw + + 0x0042 tk + + 0x0043 uz + + 0x0044 tt + + 0x0045 bn + + 0x0046 pa + + 0x0047 gu + + 0x0048 or + + 0x0049 ta + + 0x004A te + + + 11 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x004B kn + + 0x004C ml + + 0x004D as + + 0x004E mr + + 0x004F sa + + 0x0050 mn + + 0x0051 bo + + 0x0052 cy + + 0x0053 km + + 0x0054 lo + + 0x0055 my + + 0x0056 gl + + 0x0057 kok + + 0x0058 mni, reserved + + 0x0059 sd + + 0x005A syr + + 0x005B si + + 0x005C chr + + 0x005D iu + + 0x005E am + + 0x005F tzm + + 0x0060 ks + + 0x0061 ne + + 0x0062 fy + + 0x0063 ps + + 0x0064 fil + + 0x0065 dv + + 0x0066 bin, reserved + + 0x0067 ff + + 0x0068 ha + + 0x0069 ibb, reserved + + 0x006A yo + + + 12 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x006B quz + + 0x006C nso + + 0x006D ba + + 0x006E lb + + 0x006F kl + + 0x0070 ig + + 0x0071 kr, reserved + + 0x0072 om + + 0x0073 ti + + 0x0074 gn + + 0x0075 haw + + 0x0076 la, reserved + + 0x0077 so, reserved + + 0x0078 ii + + 0x0079 pap, reserved + + 0x007A arn + + 0x007B Neither defined nor reserved + + 0x007C moh + + 0x007D Neither defined nor reserved + + 0x007E br + + 0x007F Reserved for invariant locale behavior + + 0x0080 ug + + 0x0081 mi + + 0x0082 oc + + 0x0083 co + + 0x0084 gsw + + 0x0085 sah + + 0x0086 qut + + 0x0087 rw + + 0x0088 wo + + 0x0089 Neither defined nor reserved + + 0x008A Neither defined nor reserved + + + 13 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x008B Neither defined nor reserved + + 0x008C prs + + 0x008D Neither defined nor reserved + + 0x008E Neither defined nor reserved + + 0x008F Neither defined nor reserved + + 0x0090 Neither defined nor reserved + + 0x0091 gd + + 0x0092 ku + + 0x0093 quc, reserved + + 0x0401 ar-SA + + 0x0402 bg-BG + + 0x0403 ca-ES + + 0x0404 zh-TW + + 0x0405 cs-CZ + + 0x0406 da-DK + + 0x0407 de-DE + + 0x0408 el-GR + + 0x0409 en-US + + 0x040A es-ES_tradnl + + 0x040B fi-FI + + 0x040C fr-FR + + 0x040D he-IL + + 0x040E hu-HU + + 0x040F is-IS + + 0x0410 it-IT + + 0x0411 ja-JP + + 0x0412 ko-KR + + 0x0413 nl-NL + + 0x0414 nb-NO + + 0x0415 pl-PL + + 0x0416 pt-BR + + 0x0417 rm-CH + + + 14 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x0418 ro-RO + + 0x0419 ru-RU + + 0x041A hr-HR + + 0x041B sk-SK + + 0x041C sq-AL + + 0x041D sv-SE + + 0x041E th-TH + + 0x041F tr-TR + + 0x0420 ur-PK + + 0x0421 id-ID + + 0x0422 uk-UA + + 0x0423 be-BY + + 0x0424 sl-SI + + 0x0425 et-EE + + 0x0426 lv-LV + + 0x0427 lt-LT + + 0x0428 tg-Cyrl-TJ + + 0x0429 fa-IR + + 0x042A vi-VN + + 0x042B hy-AM + + 0x042C az-Latn-AZ + + 0x042D eu-ES + + 0x042E hsb-DE + + 0x042F mk-MK + + 0x0430 st-ZA + + 0x0431 ts-ZA + + 0x0432 tn-ZA + + 0x0433 ve-ZA + + 0x0434 xh-ZA + + 0x0435 zu-ZA + + 0x0436 af-ZA + + 0x0437 ka-GE + + + 15 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x0438 fo-FO + + 0x0439 hi-IN + + 0x043A mt-MT + + 0x043B se-NO + + 0x043D yi-001 + + 0x043E ms-MY + + 0x043F kk-KZ + + 0x0440 ky-KG + + 0x0441 sw-KE + + 0x0442 tk-TM + + 0x0443 uz-Latn-UZ + + 0x0444 tt-RU + + 0x0445 bn-IN + + 0x0446 pa-IN + + 0x0447 gu-IN + + 0x0448 or-IN + + 0x0449 ta-IN + + 0x044A te-IN + + 0x044B kn-IN + + 0x044C ml-IN + + 0x044D as-IN + + 0x044E mr-IN + + 0x044F sa-IN + + 0x0450 mn-MN + + 0x0451 bo-CN + + 0x0452 cy-GB + + 0x0453 km-KH + + 0x0454 lo-LA + + 0x0455 my-MM + + 0x0456 gl-ES + + 0x0457 kok-IN + + 0x0458 mni-IN, reserved + + + 16 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x0459 sd-Deva-IN, reserved + + 0x045A syr-SY + + 0x045B si-LK + + 0x045C chr-Cher-US + + 0x045D iu-Cans-CA + + 0x045E am-ET + + 0x045F tzm-Arab-MA + + 0x0460 ks-Arab + + 0x0461 ne-NP + + 0x0462 fy-NL + + 0x0463 ps-AF + + 0x0464 fil-PH + + 0x0465 dv-MV + + 0x0466 bin-NG, reserved + + 0x0467 ff-NG, ff-Latn-NG + + 0x0468 ha-Latn-NG + + 0x0469 ibb-NG, reserved + + 0x046A yo-NG + + 0x046B quz-BO + + 0x046C nso-ZA + + 0x046D ba-RU + + 0x046E lb-LU + + 0x046F kl-GL + + 0x0470 ig-NG + + 0x0471 kr-Latn-NG + + 0x0472 om-ET + + 0x0473 ti-ET + + 0x0474 gn-PY + + 0x0475 haw-US + + 0x0476 la-VA + + 0x0477 so-SO + + 0x0478 ii-CN + + + 17 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x0479 pap-029, reserved + + 0x047A arn-CL + + 0x047C moh-CA + + 0x047E br-FR + + 0x0480 ug-CN + + 0x0481 mi-NZ + + 0x0482 oc-FR + + 0x0483 co-FR + + 0x0484 gsw-FR + + 0x0485 sah-RU + + 0x0486 qut-GT, reserved + + 0x0487 rw-RW + + 0x0488 wo-SN + + 0x048C prs-AF + + 0x048D plt-MG, reserved + + 0x048E zh-yue-HK, reserved + + 0x048F tdd-Tale-CN, reserved + + 0x0490 khb-Talu-CN, reserved + + 0x0491 gd-GB + + 0x0492 ku-Arab-IQ + + 0x0493 quc-CO, reserved + + 0x0501 qps-ploc + + 0x05FE qps-ploca + + 0x0801 ar-IQ + + 0x0803 ca-ES-valencia + + 0x0804 zh-CN + + 0x0807 de-CH + + 0x0809 en-GB + + 0x080A es-MX + + 0x080C fr-BE + + 0x0810 it-CH + + 0x0811 ja-Ploc-JP, reserved + + + 18 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x0813 nl-BE + + 0x0814 nn-NO + + 0x0816 pt-PT + + 0x0818 ro-MD + + 0x0819 ru-MD + + 0x081A sr-Latn-CS + + 0x081D sv-FI + + 0x0820 ur-IN + + 0x0827 Neither defined nor reserved + + 0x082C az-Cyrl-AZ, reserved + + 0x082E dsb-DE + + 0x0832 tn-BW + + 0x083B se-SE + + 0x083C ga-IE + + 0x083E ms-BN + + 0x083F kk-Latn-KZ, reserved + + 0x0843 uz-Cyrl-UZ, reserved + + 0x0845 bn-BD + + 0x0846 pa-Arab-PK + + 0x0849 ta-LK + + 0x0850 mn-Mong-CN, reserved + + 0x0851 bo-BT, reserved + + 0x0859 sd-Arab-PK + + 0x085D iu-Latn-CA + + 0x085F tzm-Latn-DZ + + 0x0860 ks-Deva-IN + + 0x0861 ne-IN + + 0x0867 ff-Latn-SN + + 0x086B quz-EC + + 0x0873 ti-ER + + 0x09FF qps-plocm + + 0x0C00 Locale without assigned LCID if the current user default locale. See section 2.2.1. + + + 19 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x0C01 ar-EG + + 0x0C04 zh-HK + + 0x0C07 de-AT + + 0x0C09 en-AU + + 0x0C0A es-ES + + 0x0C0C fr-CA + + 0x0C1A sr-Cyrl-CS + + 0x0C3B se-FI + + 0x0C50 mn-Mong-MN + + 0x0C51 dz-BT + + 0x0C5F tmz-MA, reserved + + 0x0C6b quz-PE + + 0x1000 Locale without assigned LCID if the current user default locale. See section 2.2.1. + + 0x1001 ar-LY + + 0x1004 zh-SG + + 0x1007 de-LU + + 0x1009 en-CA + + 0x100A es-GT + + 0x100C fr-CH + + 0x101A hr-BA + + 0x103B smj-NO + + 0x105F tzm-Tfng-MA + + 0x1401 ar-DZ + + 0x1404 zh-MO + + 0x1407 de-LI + + 0x1409 en-NZ + + 0x140A es-CR + + 0x140C fr-LU + + 0x141A bs-Latn-BA + + 0x143B smj-SE + + 0x1801 ar-MA + + 0x1809 en-IE + + + 20 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x180A es-PA + + 0x180C fr-MC + + 0x181A sr-Latn-BA + + 0x183B sma-NO + + 0x1C01 ar-TN + + 0x1C09 en-ZA + + 0x1C0A es-DO + + 0x1C0C fr-029 + + 0x1C1A sr-Cyrl-BA + + 0x1C3B sma-SE + + 0x2000 Unassigned LCID locale temporarily assigned to LCID 0x3000. See section 2.2.1. + + 0x2001 ar-OM + + 0x2008 Neither defined nor reserved + + 0x2009 en-JM + + 0x200A es-VE + + 0x200C fr-RE + + 0x201A bs-Cyrl-BA + + 0x203B sms-FI + + 0x2400 Unassigned LCID locale temporarily assigned to LCID 0x3000. See section 2.2.1. + + 0x2401 ar-YE + + 0x2409 en-029, reserved + + 0x240A es-CO + + 0x240C fr-CD + + 0x241A sr-Latn-RS + + 0x243B smn-FI + + 0x2800 Unassigned LCID locale temporarily assigned to LCID 0x3000. See section 2.2.1. + + 0x2801 ar-SY + + 0x2809 en-BZ + + 0x280A es-PE + + 0x280C fr-SN + + 0x281A sr-Cyrl-RS + + 0x2C00 Unassigned LCID locale temporarily assigned to LCID 0x3000. See section 2.2.1. + + + 21 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x2C01 ar-JO + + 0x2C09 en-TT + + 0x2C0A es-AR + + 0x2C0C fr-CM + + 0x2C1A sr-Latn-ME + + 0x3000 Unassigned LCID locale temporarily assigned to LCID 0x3000. See section 2.2.1. + + 0x3001 ar-LB + + 0x3009 en-ZW + + 0x300A es-EC + + 0x300C fr-CI + + 0x301A sr-Cyrl-ME + + 0x3400 Unassigned LCID locale temporarily assigned to LCID 0x3400. See section 2.2.1. + + 0x3401 ar-KW + + 0x3409 en-PH + + 0x340A es-CL + + 0x340C fr-ML + + 0x3800 Unassigned LCID locale temporarily assigned to LCID 0x3800. See section 2.2.1. + + 0x3801 ar-AE + + 0x3809 en-ID, reserved + + 0x380A es-UY + + 0x380C fr-MA + + 0x3C00 Unassigned LCID locale temporarily assigned to LCID 0x3C00. See section 2.2.1. + + 0x3C01 ar-BH + + 0x3C09 en-HK + + 0x3C0A es-PY + + 0x3C0C fr-HT + + 0x4000 Unassigned LCID locale temporarily assigned to LCID 0x4000. See section 2.2.1. + + 0x4001 ar-QA + + 0x4009 en-IN + + 0x400A es-BO + + 0x4400 Unassigned LCID locale temporarily assigned to LCID 0x4400. See section 2.2.1. + + 0x4401 ar-Ploc-SA, reserved + + + 22 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x4409 en-MY + + 0x440A es-SV + + 0x4800 Unassigned LCID locale temporarily assigned to LCID 0x4800. See section 2.2.1. + + 0x4801 ar-145, reserved + + 0x4809 en-SG + + 0x480A es-HN + + 0x4C00 Unassigned LCID locale temporarily assigned to LCID 0x4C00. See section 2.2.1. + + 0x4C09 en-AE + + 0x4C0A es-NI + + 0x5009 en-BH, reserved + + 0x500A es-PR + + 0x5409 en-EG, reserved + + 0x540A es-US + + 0x5809 en-JO, reserved + + 0x580A es-419, reserved + + 0x5C09 en-KW, reserved + + 0x5C0A es-CU + + 0x6009 en-TR, reserved + + 0x6409 en-YE, reserved + + 0x641A bs-Cyrl + + 0x681A bs-Latn + + 0x6C1A sr-Cyrl + + 0x701A sr-Latn + + 0x703B smn + + 0x742C az-Cyrl + + 0x743B sms + + 0x7804 zh + + 0x7814 nn + + 0x781A bs + + 0x782C az-Latn + + 0x783B sma + + 0x783F kk-Cyrl, reserved + + + 23 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language ID Language tag + + 0x7843 uz-Cyrl + + 0x7850 mn-Cyrl + + 0x785D iu-Cans + + 0x785F tzm-Tfng + + 0x7C04 zh-Hant + + 0x7C14 nb + + 0x7C1A sr + + 0x7C28 tg-Cyrl + + 0x7C2E dsb + + 0x7C3B smj + + 0x7C3F kk-Latn, reserved + + 0x7C43 uz-Latn + + 0x7C46 pa-Arab + + 0x7C50 mn-Mong + + 0x7C59 sd-Arab + + 0x7C5C chr-Cher + + 0x7C5D iu-Latn + + 0x7C5F tzm-Latn + + 0x7C67 ff-Latn + + 0x7C68 ha-Latn + + 0x7C92 ku-Arab + + 0xF2EE reserved + + 0xE40C fr-015, reserved + + 0xEEEE reserved + + +Some locales have more than one method of sorting, such as by pronunciation or stroke count. The +primary sort for each locale is provided by the identifiers in the preceding Language ID table. +Alternate sorts can be selected by using one of the identifiers from the following table. + + LCID Language tag (string name) + + 0x0001007F x-IV-mathan (math alphanumeric sorting) + + 0x00010407 de-DE_phoneb + + 0x0001040E hu-HU_tchncl + + 0x00010437 ka-GE_modern + + + + 24 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + LCID Language tag (string name) + + 0x00020804 zh-CN_stroke + + 0x00021004 zh-SG_stroke + + 0x00021404 zh-MO_stroke + + 0x00030404 zh-TW_pronun + + 0x00040404<9> zh-TW_radstr + + 0x00040411 ja-JP_radstr + + 0x00040C04<10> zh-HK_radstr + + 0x00041404<11> zh-MO_radstr + + 0x00050804<12> zh-CN_phoneb + + 0x00051004<13> zh-SG_phoneb + + + + +2.2.1 Locale Names without LCIDs + +Every locale name without an assigned LCID MAY be temporarily given one of the LCIDs in the +following table, if the application requests an LCID.<14> These locale names include any valid +[RFC5646] language tag. + + Note: LCID assignments for Locale Names without LCIDs are temporary and are not suitable + for use across a protocol, or for interchange between processes or machines. These temporary + LCID assignments are also unsuitable for tagging persisted data as the meaning of the LCID + assignment will change over time. + + + Name Value Conditions + + LOCALE_CUSTOM_USER_DEFAULT<15> 0x0C00 When an LCID without a permanent LCID + assignment is also the current user locale, the + protocol will respond with + LOCALE_CUSTOM_USER_DEFAULT for that locale. + This assignment persists until the user changes the + locale. Because the meaning changes over time, + applications are discouraged from persisting this + data. Though this value will likely refer to the same + locale for the lifetime of the current process, that is + not guaranteed. This assignment is a 1-to-1 + relationship between this LCID and the user’s + current default locale name. + + + + + 25 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Name Value Conditions + + Transient LCIDs<16> 0x2000, Some user configurations temporarily associate a + 0x2400, locale without a permanent LCID assignment with + 0x2800, one of these 12 transient LCIDs. This assignment is + 0x2C00, transient and it is not guaranteed; it will likely refer + 0x3000, to the same locale for the lifetime of the process. + 0x3400, However, this assignment will differ for other users + 0x3800, on the machine, or other machines, and, as such, + 0x3C00, is unsuitable for use in protocols or persisted data. + 0x4000, This assignment is a temporary 1-to-1 relationship + 0x4400, between an LCID and a particular locale name and + 0x4800, 0x4C00 will round trip until that relationship changes. + + LOCALE_CUSTOM_UNSPECIFIED<17> 0x1000 When an LCID is requested for a locale without a + permanent LCID assignment, nor a temporary + assignment as above, the protocol will respond + with LOCALE_CUSTOM_UNSPECIFIED for all such + locales. Because this single value is used for + numerous possible locale names, it is impossible to + round trip this locale, even temporarily. + Applications should discard this value as soon as + possible and never persist it. If the system is + forced to respond to a request for + LCID_CUSTOM_UNSPECIFIED, it will fall back to + the current user locale. This is often incorrect but + may prevent an application or component from + failing. As the meaning of this temporary LCID is + unstable, it should never be used for interchange + or persisted data. This is a 1-to-many relationship + that is very unstable. + + + + + 26 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 +3 Structure Examples +The following are examples of LCID values. + + LCID Language tag (string name) Type + + 0x00000075 haw neutral locale + + 0x00000409 en-US specific locale + + 0x00010407 de-DE_phoneb alternate sort for locale + + + + + 27 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 +4 Security Considerations +None. + + + + + 28 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 +5 Appendix A: Product Behavior +The information in this specification is applicable to the following Microsoft products or supplemental +software. References to product versions include updates to those products. + +The terms "earlier" and "later", when used with a product version, refer to either all preceding +versions or all subsequent versions, respectively. The term "through" refers to the inclusive range of +versions. Applicable Microsoft products are listed chronologically in this section. + +Windows Client + + Windows NT operating system + + Windows 2000 operating system + + Windows XP operating system + + Windows Vista operating system + + Windows 7 operating system + + Windows 8 operating system + + Windows 8.1 operating system + + Windows 10 operating system + + Windows 11 operating system + +Windows Server + + Windows NT + + Windows 2000 + + Windows Server 2003 operating system + + Windows Server 2008 R2 operating system + + Windows Server 2012 operating system + + Windows Server 2012 R2 operating system + + Windows Server 2016 operating system + + Windows Server operating system + + Windows Server 2019 operating system + + Windows Server 2022 operating system + + Windows Server 2025 operating system + +Exceptions, if any, are noted in this section. If an update version, service pack or Knowledge Base +(KB) number appears with a product name, the behavior changed in that update. The new behavior +also applies to subsequent updates unless otherwise specified. If a product edition appears with the +product version, behavior is different in that product edition. + +Unless otherwise specified, any statement of optional behavior in this specification that is prescribed +using the terms "SHOULD" or "SHOULD NOT" implies product behavior in accordance with the + + + + 29 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 +SHOULD or SHOULD NOT prescription. Unless otherwise specified, the term "MAY" implies that the +product does not follow the prescription. + +<1> Section 2.1: Enabled Languages Kit (ELK) refers to a set of locales that is available through a +web download. Everything that is related to a locale is available from an ELK package (including +information on data formatting, such as date and time, font, keyboard layout, sorting, and currency +information). Additional LCID support is available through a separate ELK package for Windows XP and +Windows Vista clients and for Windows Server 2003 and Windows Server 2008 operating system +servers. + +<2> Section 2.1: In Windows, locales are primarily identified with numeric LCIDs. + +<3> Section 2.1: Windows Server 2003 supports all languages defined for Windows 95 operating +system, Windows 98 operating system, Windows Millennium Edition operating system, Windows NT +3.51 operating system, Windows NT 4.0 operating system, Windows 2000, Windows XP, and Windows +Server 2003 through the ELK. + +<4> Section 2.2: Supported only on Windows NT client and server releases. + +<5> Section 2.2: Supported only on Windows NT client and server releases. + +<6> Section 2.2: Supported only on Windows NT client and server releases. + +<7> Section 2.2: Supported only on Windows 7. + +<8> Section 2.2: The following table shows Language IDs and the versions of Windows in which they +were first made available. Language IDs are not assigned for all Language tags, please see section 1.3 +for further details. + +Supported Versions Key + + Release key Supported versions + + Release A First available in Windows NT 3.51. Supported in all later versions. + + Release B First available in Windows NT Server 4.0 operating system. Supported in all later versions. + + Release C First available in Windows 2000. Supported in all later versions. + + Release D First available in Windows XP and Windows Server 2003. Supported in all later versions. + + Release E1 First available in Windows XP ELK v1 for Windows XP SP2, Windows Server 2003, Windows + Vista, and Windows Server 2008. Supported in all later client and server versions of Windows. + + Release E2 First available in Windows XP ELK v2 for Windows XP SP2, Windows Server 2003, Windows + Vista, and Windows Server 2008. Supported in all later client and server versions of Windows. + + Release V First available in Windows Server 2008 and Windows Vista. Supported in all later versions. + + Release 7 First available in Windows 7 and Windows Server 2008 R2. Supported in all later versions. + + Release 8 First available in Windows 8 and Windows Server 2012. Supported in all later versions + + Release 8.1 First available in Windows 8.1 and Windows Server 2012 R2. Supported in all later versions. + + Release 10 First available in Windows 10 and Windows Server 2016. Supported in all later versions. + + Release 10.1 First available in Windows 10 v1607 operating system and Windows Server 2016. Supported + in all later versions. + + Release 10.2 First available in Windows 10 v1703 operating system. Supported in all later versions. + + Release 10.3 First available in Windows 10 v1709 operating system and Windows Server operating system. + + + 30 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Release key Supported versions + + Supported in all later versions. + + Release 10.4 First available in Windows 10 v1903 operating system and Windows Server v1903 operating + system. Supported in all later versions. + + Release 10.5 First available in Windows 10 v2004 operating system and Windows Server v2004 operating + system. Supported in all later versions. + + + + + Language Language Supported + Language Location (or type) ID tag version + + Afar 0x1000 aa Release 10 + + Afar Djibouti 0x1000 aa-DJ Release 10 + + Afar Eritrea 0x1000 aa-ER Release 10 + + Afar Ethiopia 0x1000 aa-ET Release 10 + + Afrikaans 0x0036 af Release 7 + + Afrikaans Namibia 0x1000 af-NA Release 10 + + Afrikaans South Africa 0x0436 af-ZA Release B + + Aghem 0x1000 agq Release 10 + + Aghem Cameroon 0x1000 agq-CM Release 10 + + Akan 0x1000 ak Release 10 + + Akan Ghana 0x1000 ak-GH Release 10 + + Albanian 0x001C sq Release 7 + + Albanian Albania 0x041C sq-AL Release B + + Albanian North Macedonia 0x1000 sq-MK Release 10 + + Alsatian 0x0084 gsw Release 7 + + Alsatian France 0x0484 gsw-FR Release V + + Alsatian Liechtenstein 0x1000 gsw-LI Release 10 + + Alsatian Switzerland 0x1000 gsw-CH Release 10 + + Amharic 0x005E am Release 7 + + Amharic Ethiopia 0x045E am-ET Release V + + Arabic 0x0001 ar Release 7 + + Arabic Algeria 0x1401 ar-DZ Release B + + Arabic Bahrain 0x3C01 ar-BH Release B + + Arabic Chad 0x1000 ar-TD Release 10 + + Arabic Comoros 0x1000 ar-KM Release 10 + + + 31 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Arabic Djibouti 0x1000 ar-DJ Release 10 + + Arabic Egypt 0x0c01 ar-EG Release B + + Arabic Eritrea 0x1000 ar-ER Release 10 + + Arabic Iraq 0x0801 ar-IQ Release B + + Arabic Israel 0x1000 ar-IL Release 10 + + Arabic Jordan 0x2C01 ar-JO Release B + + Arabic Kuwait 0x3401 ar-KW Release B + + Arabic Lebanon 0x3001 ar-LB Release B + + Arabic Libya 0x1001 ar-LY Release B + + Arabic Mauritania 0x1000 ar-MR Release 10 + + Arabic Morocco 0x1801 ar-MA Release B + + Arabic Oman 0x2001 ar-OM Release B + + Arabic Palestinian Authority 0x1000 ar-PS Release 10 + + Arabic Qatar 0x4001 ar-QA Release B + + Arabic Saudi Arabia 0x0401 ar-SA Release B + + Arabic Somalia 0x1000 ar-SO Release 10 + + Arabic South Sudan 0x1000 ar-SS Release 10 + + Arabic Sudan 0x1000 ar-SD Release 10 + + Arabic Syria 0x2801 ar-SY Release B + + Arabic Tunisia 0x1C01 ar-TN Release B + + Arabic U.A.E. 0x3801 ar-AE Release B + + Arabic World 0x1000 ar-001 Release 10 + + Arabic Yemen 0x2401 ar-YE Release B + + Armenian 0x002B hy Release 7 + + Armenian Armenia 0x042B hy-AM Release C + + Assamese 0x004D as Release 7 + + Assamese India 0x044D as-IN Release V + + Asturian 0x1000 ast Release 10 + + Asturian Spain 0x1000 ast-ES Release 10 + + Asu 0x1000 asa Release 10 + + Asu Tanzania 0x1000 asa-TZ Release 10 + + + + 32 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Azerbaijani (Cyrillic) 0x742C az-Cyrl Windows 7 + + Azerbaijani (Cyrillic) Azerbaijan 0x082C az-Cyrl-AZ Release C + + Azerbaijani (Latin) 0x002C az Release 7 + + Azerbaijani (Latin) 0x782C az-Latn Windows 7 + + Azerbaijani (Latin) Azerbaijan 0x042C az-Latn-AZ Release C + + Bafia 0x1000 ksf Release 10 + + Bafia Cameroon 0x1000 ksf-CM Release 10 + + Bamanankan 0x1000 bm Release 10 + + Bamanankan (Latin) Mali 0x1000 bm-Latn-ML Release 10 + + Bangla 0x0045 bn Release 7 + + Bangla Bangladesh 0x0845 bn-BD Release V + + Bangla India 0x0445 bn-IN Release E1 + + Basaa 0x1000 bas Release 10 + + Basaa Cameroon 0x1000 bas-CM Release 10 + + Bashkir 0x006D ba Release 7 + + Bashkir Russia 0x046D ba-RU Release V + + Basque 0x002D eu Release 7 + + Basque Spain 0x042D eu-ES Release B + + Belarusian 0x0023 be Release 7 + + Belarusian Belarus 0x0423 be-BY Release B + + Bemba 0x1000 bem Release 10 + + Bemba Zambia 0x1000 bem-ZM Release 10 + + Bena 0x1000 bez Release 10 + + Bena Tanzania 0x1000 bez-TZ Release 10 + + Bhojpuri 0x1000 bho Release 11 + + Bhojpuri (Devanagari) 0x1000 bho-Deva Release 11 + + Bhojpuri (Devanagari) India 0x1000 bho-Deva-IN Release 11 + + Blin 0x1000 byn Release 10 + + Blin Eritrea 0x1000 byn-ER Release 10 + + Bodo 0x1000 brx Release 10 + + Bodo India 0x1000 brx-IN Release 10 + + + + 33 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Bosnian (Cyrillic) 0x641A bs-Cyrl Windows 7 + + Bosnian (Cyrillic) Bosnia and Herzegovina 0x201A bs-Cyrl-BA Release E1 + + Bosnian (Latin) 0x681A bs-Latn Windows 7 + + Bosnian (Latin) 0x781A bs Release 7 + + Bosnian (Latin) Bosnia and Herzegovina 0x141A bs-Latn-BA Release E1 + + Breton 0x007E br Release 7 + + Breton France 0x047E br-FR Release V + + Bulgarian 0x0002 bg Release 7 + + Bulgarian Bulgaria 0x0402 bg-BG Release B + + Burmese 0x0055 my Release 8.1 + + Burmese Myanmar 0x0455 my-MM Release 8.1 + + Catalan 0x0003 ca Release 7 + + Catalan Andorra 0x1000 ca-AD Release 10 + + Catalan France 0x1000 ca-FR Release 10 + + Catalan Italy 0x1000 ca-IT Release 10 + + Catalan Spain 0x0403 ca-ES Release B + + Cebuano 0x1000 ceb Release 10.5 + + Cebuan (Latin) 0x1000 ceb-Latn Release 10.5 + + Cebuan (Latin) Philippines 0x1000 ceb-Latn-PH Release 10.5 + + Central Atlas Tamazight Morocco 0x045F tzm-Arab- Release 10 + (Arabic) MA + + Central Atlas Tamazight Morocco 0x1000 tzm-Latn- Release 10 + (Latin) MA + + Central Kurdish 0x0092 ku Release 8 + + Central Kurdish 0x7c92 ku-Arab Release 8 + + Central Kurdish Iraq 0x0492 ku-Arab-IQ Release 8 + + Chakma 0x1000 ccp Release 10.5 + + Chakma Chakma 0x1000 ccp-Cakm Release 10.5 + + Chakma Bangladesh 0x1000 ccp-Cakm- Release 10.5 + BD + + Chakma India 0x1000 ccp-Cakm- Release 10.5 + IN + + Chechen Russia 0x1000 ce-RU Release 10.1 + + + + 34 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Cherokee 0x005C chr Release 8 + + Cherokee 0x7c5C chr-Cher Release 8 + + Cherokee United States 0x045C chr-Cher-US Release 8 + + Chiga 0x1000 cgg Release 10 + + Chiga Uganda 0x1000 cgg-UG Release 10 + + Chinese (Simplified) 0x0004 zh-Hans Release A + + Chinese (Simplified) 0x7804 zh Windows 7 + + Chinese (Simplified) People's Republic of China 0x0804 zh-CN Release A + + Chinese (Simplified) Singapore 0x1004 zh-SG Release A + + Chinese (Traditional) 0x7C04 zh-Hant Release A + + Chinese (Traditional) Hong Kong S.A.R. 0x0C04 zh-HK Release A + + Chinese (Traditional) Macao S.A.R. 0x1404 zh-MO Release D + + Chinese (Traditional) Taiwan 0x0404 zh-TW Release A + + Church Slavic Russia 0x1000 cu-RU Release 10.1 + + Chuvash 0x1000 cv Release 11 + + Chuvash (Cyrillic) 0x1000 cv-Cyrl Release 11 + + Chuvash (Cyrillic) Russia 0x1000 cv-Cyrl-RU Release 11 + + Congo Swahili 0x1000 swc Release 10 + + Congo Swahili Congo DRC 0x1000 swc-CD Release 10 + + Cornish 0x1000 kw Release 10 + + Cornish United Kingdom 0x1000 kw-GB Release 10 + + Corsican 0x0083 co Release 7 + + Corsican France 0x0483 co-FR Release V + + Croatian 0x001A hr Release 7 + + Croatian Croatia 0x041A hr-HR Release A + + Croatian (Latin) Bosnia and Herzegovina 0x101A hr-BA Release E1 + + Czech 0x0005 cs Release 7 + + Czech Czech Republic 0x0405 cs-CZ Release A + + Danish 0x0006 da Release 7 + + Danish Denmark 0x0406 da-DK Release A + + Danish Greenland 0x1000 da-GL Release 10 + + + + 35 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Dari 0x008C prs Release 7 + + Dari Afghanistan 0x048C prs-AF Release V + + Divehi 0x0065 dv Release 7 + + Divehi Maldives 0x0465 dv-MV Release D + + Duala 0x1000 dua Release 10 + + Duala Cameroon 0x1000 dua-CM Release 10 + + Dutch 0x0013 nl Release 7 + + Dutch Aruba 0x1000 nl-AW Release 10 + + Dutch Belgium 0x0813 nl-BE Release A + + Dutch Bonaire, Sint Eustatius and Saba 0x1000 nl-BQ Release 10 + + Dutch Curaçao 0x1000 nl-CW Release 10 + + Dutch Netherlands 0x0413 nl-NL Release A + + Dutch Sint Maarten 0x1000 nl-SX Release 10 + + Dutch Suriname 0x1000 nl-SR Release 10 + + Dzongkha 0x1000 dz Release 10 + + Dzongkha Bhutan 0x0C51 dz-BT Release 10 + + Embu 0x1000 ebu Release 10 + + Embu Kenya 0x1000 ebu-KE Release 10 + + English 0x0009 en Release 7 + + English American Samoa 0x1000 en-AS Release 10 + + English Anguilla 0x1000 en-AI Release 10 + + English Antigua and Barbuda 0x1000 en-AG Release 10 + + English Australia 0x0C09 en-AU Release A + + English Austria 0x1000 en-AT Release 10.1 + + English Bahamas 0x1000 en-BS Release 10 + + English Barbados 0x1000 en-BB Release 10 + + English Belgium 0x1000 en-BE Release 10 + + English Belize 0x2809 en-BZ Release B + + English Bermuda 0x1000 en-BM Release 10 + + English Botswana 0x1000 en-BW Release 10 + + English British Indian Ocean Territory 0x1000 en-IO Release 10 + + + + 36 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + English British Virgin Islands 0x1000 en-VG Release 10 + + English Burundi 0x1000 en-BI Release 10.1 + + English Cameroon 0x1000 en-CM Release 10 + + English Canada 0x1009 en-CA Release A + + English Caribbean 0x2409 en-029 Release B + + English Cayman Islands 0x1000 en-KY Release 10 + + English Christmas Island 0x1000 en-CX Release 10 + + English Cocos [Keeling] Islands 0x1000 en-CC Release 10 + + English Cook Islands 0x1000 en-CK Release 10 + + English Cyprus 0x1000 en-CY Release 10.1 + + English Denmark 0x1000 en-DK Release 10.1 + + English Dominica 0x1000 en-DM Release 10 + + English Eritrea 0x1000 en-ER Release 10 + + English Europe 0x1000 en-150 Release 10 + + English Falkland Islands 0x1000 en-FK Release 10 + + English Finland 0x1000 en-FI Release 10.1 + + English Fiji 0x1000 en-FJ Release 10 + + English Gambia 0x1000 en-GM Release 10 + + English Germany 0x1000 en-DE Release 10.1 + + English Ghana 0x1000 en-GH Release 10 + + English Gibraltar 0x1000 en-GI Release 10 + + English Grenada 0x1000 en-GD Release 10 + + English Guam 0x1000 en-GU Release 10 + + English Guernsey 0x1000 en-GG Release 10 + + English Guyana 0x1000 en-GY Release 10 + + English Hong Kong 0x3C09 en-HK Release 8.1 + + English India 0x4009 en-IN Release V + + English Ireland 0x1809 en-IE Release A + + English Isle of Man 0x1000 en-IM Release 10 + + English Israel 0x1000 en-IL Release 10.1 + + English Jamaica 0x2009 en-JM Release B + + + + 37 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + English Jersey 0x1000 en-JE Release 10 + + English Kenya 0x1000 en-KE Release 10 + + English Kiribati 0x1000 en-KI Release 10 + + English Lesotho 0x1000 en-LS Release 10 + + English Liberia 0x1000 en-LR Release 10 + + English Macao SAR 0x1000 en-MO Release 10 + + English Madagascar 0x1000 en-MG Release 10 + + English Malawi 0x1000 en-MW Release 10 + + English Malaysia 0x4409 en-MY Release V + + English Maldives 0x1000 en-MV Release 11 + + English Malta 0x1000 en-MT Release 10 + + English Marshall Islands 0x1000 en-MH Release 10 + + English Mauritius 0x1000 en-MU Release 10 + + English Micronesia 0x1000 en-FM Release 10 + + English Montserrat 0x1000 en-MS Release 10 + + English Namibia 0x1000 en-NA Release 10 + + English Nauru 0x1000 en-NR Release 10 + + English Netherlands 0x1000 en-NL Release 10.1 + + English New Zealand 0x1409 en-NZ Release A + + English Nigeria 0x1000 en-NG Release 10 + + English Niue 0x1000 en-NU Release 10 + + English Norfolk Island 0x1000 en-NF Release 10 + + English Northern Mariana Islands 0x1000 en-MP Release 10 + + English Pakistan 0x1000 en-PK Release 10 + + English Palau 0x1000 en-PW Release 10 + + English Papua New Guinea 0x1000 en-PG Release 10 + + English Pitcairn Islands 0x1000 en-PN Release 10 + + English Puerto Rico 0x1000 en-PR Release 10 + + English Republic of the Philippines 0x3409 en-PH Release C + + English Rwanda 0x1000 en-RW Release 10 + + English Saint Kitts and Nevis 0x1000 en-KN Release 10 + + + + 38 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + English Saint Lucia 0x1000 en-LC Release 10 + + English Saint Vincent and the Grenadines 0x1000 en-VC Release 10 + + English Samoa 0x1000 en-WS Release 10 + + English Seychelles 0x1000 en-SC Release 10 + + English Sierra Leone 0x1000 en-SL Release 10 + + English Singapore 0x4809 en-SG Release V + + English Sint Maarten 0x1000 en-SX Release 10 + + English Slovenia 0x1000 en-SI Release 10.1 + + English Solomon Islands 0x1000 en-SB Release 10 + + English South Africa 0x1C09 en-ZA Release B + + English South Sudan 0x1000 en-SS Release 10 + + English St Helena, Ascension, Tristan da 0x1000 en-SH Release 10 + Cunha + + English Sudan 0x1000 en-SD Release 10 + + English Swaziland 0x1000 en-SZ Release 10 + + English Sweden 0x1000 en-SE Release 10.1 + + English Switzerland 0x1000 en-CH Release 10.1 + + English Tanzania 0x1000 en-TZ Release 10 + + English Tokelau 0x1000 en-TK Release 10 + + English Tonga 0x1000 en-TO Release 10 + + English Trinidad and Tobago 0x2c09 en-TT Release B + + English Turks and Caicos Islands 0x1000 en-TC Release 10 + + English Tuvalu 0x1000 en-TV Release 10 + + English Uganda 0x1000 en-UG Release 10 + + English United Arab Emirates 0x4C09 en-AE Release 10.5 + + English United Kingdom 0x0809 en-GB Release A + + English United States 0x0409 en-US Release A + + English US Minor Outlying Islands 0x1000 en-UM Release 10 + + English US Virgin Islands 0x1000 en-VI Release 10 + + English Vanuatu 0x1000 en-VU Release 10 + + English World 0x1000 en-001 Release 10 + + English Zambia 0x1000 en-ZM Release 10 + + + 39 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + English Zimbabwe 0x3009 en-ZW Release C + + Esperanto 0x1000 eo Release 10 + + Esperanto World 0x1000 eo-001 Release 10 + + Estonian 0x0025 et Release 7 + + Estonian Estonia 0x0425 et-EE Release B + + Ewe 0x1000 ee Release 10 + + Ewe Ghana 0x1000 ee-GH Release 10 + + Ewe Togo 0x1000 ee-TG Release 10 + + Ewondo 0x1000 ewo Release 10 + + Ewondo Cameroon 0x1000 ewo-CM Release 10 + + Faroese 0x0038 fo Release 7 + + Faroese Denmark 0x1000 fo-DK Release 10.1 + + Faroese Faroe Islands 0x0438 fo-FO Release B + + Filipino 0x0064 fil Release 7 + + Filipino Philippines 0x0464 fil-PH Release E2 + + Finnish 0x000B fi Release 7 + + Finnish Finland 0x040B fi-FI Release A + + French 0x000C fr Release 7 + + French Algeria 0x1000 fr-DZ Release 10 + + French Belgium 0x080C fr-BE Release A + + French Benin 0x1000 fr-BJ Release 10 + + French Burkina Faso 0x1000 fr-BF Release 10 + + French Burundi 0x1000 fr-BI Release 10 + + French Cameroon 0x2c0C fr-CM Release 8.1 + + French Canada 0x0c0C fr-CA Release A + + French Caribbean 0x1C0C fr-029 Release 10 + + French Central African Republic 0x1000 fr-CF Release 10 + + French Chad 0x1000 fr-TD Release 10 + + French Comoros 0x1000 fr-KM Release 10 + + French Congo 0x1000 fr-CG Release 10 + + French Congo, DRC 0x240C fr-CD Release 8.1 + + + + 40 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + French Côte d'Ivoire 0x300C fr-CI Release 8.1 + + French Djibouti 0x1000 fr-DJ Release 10 + + French Equatorial Guinea 0x1000 fr-GQ Release 10 + + French France 0x040C fr-FR Release A + + French French Guiana 0x1000 fr-GF Release 10 + + French French Polynesia 0x1000 fr-PF Release 10 + + French Gabon 0x1000 fr-GA Release 10 + + French Guadeloupe 0x1000 fr-GP Release 10 + + French Guinea 0x1000 fr-GN Release 10 + + French Haiti 0x3c0C fr-HT Release 8.1 + + French Luxembourg 0x140C fr-LU Release A + + French Madagascar 0x1000 fr-MG Release 10 + + French Mali 0x340C fr-ML Release 8.1 + + French Martinique 0x1000 fr-MQ Release 10 + + French Mauritania 0x1000 fr-MR Release 10 + + French Mauritius 0x1000 fr-MU Release 10 + + French Mayotte 0x1000 fr-YT Release 10 + + French Morocco 0x380C fr-MA Release 8.1 + + French New Caledonia 0x1000 fr-NC Release 10 + + French Niger 0x1000 fr-NE Release 10 + + French Principality of Monaco 0x180C fr-MC Release A + + French Reunion 0x200C fr-RE Release 8.1 + + French Rwanda 0x1000 fr-RW Release 10 + + French Saint Barthélemy 0x1000 fr-BL Release 10 + + French Saint Martin 0x1000 fr-MF Release 10 + + French Saint Pierre and Miquelon 0x1000 fr-PM Release 10 + + French Senegal 0x280C fr-SN Release 8.1 + + French Seychelles 0x1000 fr-SC Release 10 + + French Switzerland 0x100C fr-CH Release A + + French Syria 0x1000 fr-SY Release 10 + + French Togo 0x1000 fr-TG Release 10 + + + + 41 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + French Tunisia 0x1000 fr-TN Release 10 + + French Vanuatu 0x1000 fr-VU Release 10 + + French Wallis and Futuna 0x1000 fr-WF Release 10 + + Frisian 0x0062 fy Release 7 + + Frisian Netherlands 0x0462 fy-NL Release E2 + + Friulian 0x1000 fur Release 10 + + Friulian Italy 0x1000 fur-IT Release 10 + + Fulah 0x0067 ff Release 8 + + Fulah (Latin) 0x7C67 ff-Latn Release 8 + + Fulah (Latin) Burkina Faso 0x1000 ff-Latn-BF Release 10.4 + + Fulah Cameroon 0x1000 ff-CM Release 10 + + Fulah (Latin) Cameroon 0x1000 ff-Latn-CM Release 10.4 + + Fulah (Latin) Gambia 0x1000 ff-Latn-GM Release 10.4 + + Fulah (Latin) Ghana 0x1000 ff-Latn-GH Release 10.4 + + Fulah Guinea 0x1000 ff-GN Release 10 + + Fulah (Latin) Guinea 0x1000 ff-Latn-GN Release 10.4 + + Fulah (Latin) Guinea-Bissau 0x1000 ff-Latn-GW Release 10.4 + + Fulah (Latin) Liberia 0x1000 ff-Latn-LR Release 10.4 + + Fulah Mauritania 0x1000 ff-MR Release 10 + + Fulah (Latin) Mauritania 0x1000 ff-Latn-MR Release 10.4 + + Fulah (Latin) Niger 0x1000 ff-Latn-NE Release 10.4 + + Fulah Nigeria 0x0467 ff-NG Release 10 + + Fulah (Latin) Nigeria 0x0467 ff-Latn-NG Release 10.4 + + Fulah Senegal 0x0867 ff-Latn-SN Release 8 + + Fulah (Latin) Sierra Leone 0x1000 ff-Latn-SL Release 10.4 + + Galician 0x0056 gl Release 7 + + Galician Spain 0x0456 gl-ES Release D + + Ganda 0x1000 lg Release 10 + + Ganda Uganda 0x1000 lg-UG Release 10 + + Georgian 0x0037 ka Release 7 + + Georgian Georgia 0x0437 ka-GE Release C + + + + 42 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + German 0x0007 de Release 7 + + German Austria 0x0C07 de-AT Release A + + German Belgium 0x1000 de-BE Release 10 + + German Germany 0x0407 de-DE Release A + + German Italy 0x1000 de-IT Release 10.2 + + German Liechtenstein 0x1407 de-LI Release B + + German Luxembourg 0x1007 de-LU Release B + + German Switzerland 0x0807 de-CH Release A + + Greek 0x0008 el Release 7 + + Greek Cyprus 0x1000 el-CY Release 10 + + Greek Greece 0x0408 el-GR Release A + + Greenlandic 0x006F kl Release 7 + + Greenlandic Greenland 0x046F kl-GL Release V + + Guarani 0x0074 gn Release 8.1 + + Guarani Paraguay 0x0474 gn-PY Release 8.1 + + Gujarati 0x0047 gu Release 7 + + Gujarati India 0x0447 gu-IN Release D + + Gusii 0x1000 guz Release 10 + + Gusii Kenya 0x1000 guz-KE Release 10 + + Haryanvi 0x1000 bgc Release 11 + + Haryanvi (Devanagari) 0x1000 bgc-Deva Release 11 + + Haryanvi (Devanagari) India 0x1000 bgc-Deva-IN Release 11 + + Hausa (Latin) 0x0068 ha Release 7 + + Hausa (Latin) 0x7C68 ha-Latn Windows 7 + + Hausa (Latin) Ghana 0x1000 ha-Latn-GH Release 10 + + Hausa (Latin) Niger 0x1000 ha-Latn-NE Release 10 + + Hausa (Latin) Nigeria 0x0468 ha-Latn-NG Release V + + Hawaiian 0x0075 haw Release 8 + + Hawaiian United States 0x0475 haw-US Release 8 + + Hebrew 0x000D he Release 7 + + Hebrew Israel 0x040D he-IL Release B + + + + 43 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Hindi 0x0039 hi Release 7 + + Hindi India 0x0439 hi-IN Release C + + Hindi (Latin) 0x1000 hi-Latn Release 11 + + Hindi (Latin) India 0x1000 hi-Latn-IN Release 11 + + Hungarian 0x000E hu Release 7 + + Hungarian Hungary 0x040E hu-HU Release A + + Icelandic 0x000F is Release 7 + + Icelandic Iceland 0x040F is-IS Release A + + Igbo 0x0070 ig Release 7 + + Igbo Nigeria 0x0470 ig-NG Release V + + Indonesian 0x0021 id Release 7 + + Indonesian Indonesia 0x0421 id-ID Release B + + Interlingua 0x1000 ia Release 10 + + Interlingua France 0x1000 ia-FR Release 10 + + Interlingua World 0x1000 ia-001 Release 10 + + Inuktitut (Latin) 0x005D iu Release 7 + + Inuktitut (Latin) 0x7C5D iu-Latn Windows 7 + + Inuktitut (Latin) Canada 0x085D iu-Latn-CA Release E2 + + Inuktitut (Syllabics) 0x785D iu-Cans Windows 7 + + Inuktitut (Syllabics) Canada 0x045d iu-Cans-CA Release V + + Irish 0x003C ga Windows 7 + + Irish Ireland 0x083C ga-IE Release E2 + + Italian 0x0010 it Release 7 + + Italian Italy 0x0410 it-IT Release A + + Italian San Marino 0x1000 it-SM Release 10 + + Italian Switzerland 0x0810 it-CH Release A + + Italian Vatican City 0x1000 it-VA Release 10.3 + + Japanese 0x0011 ja Release 7 + + Japanese Japan 0x0411 ja-JP Release A + + Javanese 0x1000 jv Release 8.1 + + Javanese Latin 0x1000 jv-Latn Release 8.1 + + + + 44 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Javanese Latin, Indonesia 0x1000 jv-Latn-ID Release 8.1 + + Jola-Fonyi 0x1000 dyo Release 10 + + Jola-Fonyi Senegal 0x1000 dyo-SN Release 10 + + Kabuverdianu 0x1000 kea Release 10 + + Kabuverdianu Cabo Verde 0x1000 kea-CV Release 10 + + Kabyle 0x1000 kab Release 10 + + Kabyle Algeria 0x1000 kab-DZ Release 10 + + Kaingang 0x1000 kgp Release 11 + + Kaingang (Latin) 0x1000 kgp-Latn Release 11 + + Kaingang (Latin) Brazil 0x1000 kgp-Latn-BR Release 11 + + Kako 0x1000 kkj Release 10 + + Kako Cameroon 0x1000 kkj-CM Release 10 + + Kalenjin 0x1000 kln Release 10 + + Kalenjin Kenya 0x1000 kln-KE Release 10 + + Kamba 0x1000 kam Release 10 + + Kamba Kenya 0x1000 kam-KE Release 10 + + Kannada 0x004B kn Release 7 + + Kannada India 0x044B kn-IN Release D + + Kanuri (Latin) Nigeria 0x0471 kr-Latn-NG Release 10 + + Kashmiri 0x0060 ks Release 10 + + Kashmiri Perso-Arabic 0x0460 ks-Arab Release 10 + + Kashmiri Perso-Arabic 0x1000 ks-Arab-IN Release 10 + + Kashmiri (Devanagari) India 0x0860 ks-Deva-IN Release 10 + + Kazakh 0x003F kk Release 7 + + Kazakh Kazakhstan 0x043F kk-KZ Release C + + Khmer 0x0053 km Release 7 + + Khmer Cambodia 0x0453 km-KH Release V + + K'iche 0x0086 quc Release 10 + + K'iche Guatemala 0x0486 quc-Latn-GT Release 10 + + Kikuyu 0x1000 ki Release 10 + + Kikuyu Kenya 0x1000 ki-KE Release 10 + + + + 45 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Kinyarwanda 0x0087 rw Release 7 + + Kinyarwanda Rwanda 0x0487 rw-RW Release V + + Kiswahili 0x0041 sw Release 7 + + Kiswahili Kenya 0x0441 sw-KE Release C + + Kiswahili Tanzania 0x1000 sw-TZ Release 10 + + Kiswahili Uganda 0x1000 sw-UG Release 10 + + Konkani 0x0057 kok Release 7 + + Konkani India 0x0457 kok-IN Release C + + Korean 0x0012 ko Release 7 + + Korean Korea 0x0412 ko-KR Release A + + Korean North Korea 0x1000 ko-KP Release 10.1 + + Koyra Chiini 0x1000 khq Release 10 + + Koyra Chiini Mali 0x1000 khq-ML Release 10 + + Koyraboro Senni 0x1000 ses Release 10 + + Koyraboro Senni Mali 0x1000 ses-ML Release 10 + + Kwasio 0x1000 nmg Release 10 + + Kwasio Cameroon 0x1000 nmg-CM Release 10 + + Kyrgyz 0x0040 ky Release 7 + + Kyrgyz Kyrgyzstan 0x0440 ky-KG Release D + + Kurdish Perso-Arabic, Iran 0x1000 ku-Arab-IR Release 10.1 + + Lakota 0x1000 lkt Release 10 + + Lakota United States 0x1000 lkt-US Release 10 + + Langi 0x1000 lag Release 10 + + Langi Tanzania 0x1000 lag-TZ Release 10 + + Lao 0x0054 lo Release 7 + + Lao Lao P.D.R. 0x0454 lo-LA Release V + + Latin Vatican City 0x0476 la-VA Release 10.5 + + Latvian 0x0026 lv Release 7 + + Latvian Latvia 0x0426 lv-LV Release B + + Lingala 0x1000 ln Release 10 + + Lingala Angola 0x1000 ln-AO Release 10 + + + + 46 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Lingala Central African Republic 0x1000 ln-CF Release 10 + + Lingala Congo 0x1000 ln-CG Release 10 + + Lingala Congo DRC 0x1000 ln-CD Release 10 + + Lithuanian 0x0027 lt Release 7 + + Lithuanian Lithuania 0x0427 lt-LT Release B + + Low German 0x1000 nds Release 10.2 + + Low German Germany 0x1000 nds-DE Release 10.2 + + Low German Netherlands 0x1000 nds-NL Release 10.2 + + Lower Sorbian 0x7C2E dsb Windows 7 + + Lower Sorbian Germany 0x082E dsb-DE Release V + + Luba-Katanga 0x1000 lu Release 10 + + Luba-Katanga Congo DRC 0x1000 lu-CD Release 10 + + Luo 0x1000 luo Release 10 + + Luo Kenya 0x1000 luo-KE Release 10 + + Luxembourgish 0x006E lb Release 7 + + Luxembourgish Luxembourg 0x046E lb-LU Release E2 + + Luyia 0x1000 luy Release 10 + + Luyia Kenya 0x1000 luy-KE Release 10 + + Macedonian 0x002F mk Release 7 + + Macedonian North Macedonia 0x042F mk-MK Release C + + Machame 0x1000 jmc Release 10 + + Machame Tanzania 0x1000 jmc-TZ Release 10 + + Makhuwa-Meetto 0x1000 mgh Release 10 + + Makhuwa-Meetto Mozambique 0x1000 mgh-MZ Release 10 + + Makonde 0x1000 kde Release 10 + + Makonde Tanzania 0x1000 kde-TZ Release 10 + + Malagasy 0x1000 mg Release 8.1 + + Malagasy Madagascar 0x1000 mg-MG Release 8.1 + + Malay 0x003E ms Release 7 + + Malay Brunei Darussalam 0x083E ms-BN Release C + + Malay Malaysia 0x043E ms-MY Release C + + + + 47 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Malayalam 0x004C ml Release 7 + + Malayalam India 0x044C ml-IN Release E1 + + Maltese 0x003A mt Release 7 + + Maltese Malta 0x043A mt-MT Release E1 + + Manx 0x1000 gv Release 10 + + Manx Isle of Man 0x1000 gv-IM Release 10 + + Maori 0x0081 mi Release 7 + + Maori New Zealand 0x0481 mi-NZ Release E1 + + Mapudungun 0x007A arn Release 7 + + Mapudungun Chile 0x047A arn-CL Release E2 + + Marathi 0x004E mr Release 7 + + Marathi India 0x044E mr-IN Release C + + Masai 0x1000 mas Release 10 + + Masai Kenya 0x1000 mas-KE Release 10 + + Masai Tanzania 0x1000 mas-TZ Release 10 + + Mazanderani Iran 0x1000 mzn-IR Release 10.1 + + Meru 0x1000 mer Release 10 + + Meru Kenya 0x1000 mer-KE Release 10 + + Meta' 0x1000 mgo Release 10 + + Meta' Cameroon 0x1000 mgo-CM Release 10 + + Mohawk 0x007C moh Release 7 + + Mohawk Canada 0x047C moh-CA Release E2 + + Mongolian (Cyrillic) 0x0050 mn Release 7 + + Mongolian (Cyrillic) 0x7850 mn-Cyrl Windows 7 + + Mongolian (Cyrillic) Mongolia 0x0450 mn-MN Release D + + Mongolian (Traditional 0x7C50 mn-Mong Windows 7 + Mongolian) + + Mongolian (Traditional People's Republic of China 0x0850 mn-Mong- Release V + Mongolian) CN + + Mongolian (Traditional Mongolia 0x0C50 mn-Mong- Windows 7 + Mongolian) MN + + Morisyen 0x1000 mfe Release 10 + + Morisyen Mauritius 0x1000 mfe-MU Release 10 + + + 48 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Mundang 0x1000 mua Release 10 + + Mundang Cameroon 0x1000 mua-CM Release 10 + + N'ko 0x1000 nqo Release 8.1 + + N'ko Guinea 0x1000 nqo-GN Release 8.1 + + Nama 0x1000 naq Release 10 + + Nama Namibia 0x1000 naq-NA Release 10 + + Nepali 0x0061 ne Release 7 + + Nepali India 0x0861 ne-IN Release 8.1 + + Nepali Nepal 0x0461 ne-NP Release E2 + + Ngiemboon 0x1000 nnh Release 10 + + Ngiemboon Cameroon 0x1000 nnh-CM Release 10 + + Ngomba 0x1000 jgo Release 10 + + Ngomba Cameroon 0x1000 jgo-CM Release 10 + + Nheengatu 0x1000 yrl Release 11 + + Nheengatu (Latin) 0x1000 yrl-Latn Release 11 + + Nheengatu (Latin) Brazil 0x1000 yrl-Latn-BR Release 11 + + Nheengatu (Latin) Colombia 0x1000 yrl-Latn-CO Release 11 + + Nheengatu (Latin) Venezuela 0x1000 yrl-Latn-VE Release 11 + + Northern Luri Iraq 0x1000 lrc-IQ Release 10.1 + + Northern Luri Iran 0x1000 lrc-IR Release 10.1 + + North Ndebele 0x1000 nd Release 10 + + North Ndebele Zimbabwe 0x1000 nd-ZW Release 10 + + Norwegian (Bokmal) 0x0014 no Release 7 + + Norwegian (Bokmal) 0x7C14 nb Release 7 + + Norwegian (Bokmal) Norway 0x0414 nb-NO Release A + + Norwegian (Nynorsk) 0x7814 nn Release 7 + + Norwegian (Nynorsk) Norway 0x0814 nn-NO Release A + + Norwegian Bokmål Svalbard and Jan Mayen 0x1000 nb-SJ Release 10 + + Nuer 0x1000 nus Release 10 + + Nuer Sudan 0x1000 nus-SD Release 10 + + Nuer South Sudan 0x1000 nus-SS Release 10.1 + + + + 49 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Nyankole 0x1000 nyn Release 10 + + Nyankole Uganda 0x1000 nyn-UG Release 10 + + Occitan 0x0082 oc Release 7 + + Occitan France 0x0482 oc-FR Release V + + Occitan Spain 0x1000 oc-ES Release 11 + + Odia 0x0048 or Release 7 + + Odia India 0x0448 or-IN Release V + + Oromo 0x0072 om Release 8.1 + + Oromo Ethiopia 0x0472 om-ET Release 8.1 + + Oromo Kenya 0x1000 om-KE Release 10 + + Ossetian 0x1000 os Release 10 + + Ossetian Cyrillic, Georgia 0x1000 os-GE Release 10 + + Ossetian Cyrillic, Russia 0x1000 os-RU Release 10 + + Pashto 0x0063 ps Release 7 + + Pashto Afghanistan 0x0463 ps-AF Release E2 + + Pashto Pakistan 0x1000 ps-PK Release 10.5 + + Persian 0x0029 fa Release 7 + + Persian Afghanistan 0x1000 fa-AF Release 10 + + Persian Iran 0x0429 fa-IR Release B + + Polish 0x0015 pl Release 7 + + Polish Poland 0x0415 pl-PL Release A + + Portuguese 0x0016 pt Release 7 + + Portuguese Angola 0x1000 pt-AO Release 8.1 + + Portuguese Brazil 0x0416 pt-BR Release A + + Portuguese Cabo Verde 0x1000 pt-CV Release 10 + + Portuguese Equatorial Guinea 0x1000 pt-GQ Release 10.2 + + Portuguese Guinea-Bissau 0x1000 pt-GW Release 10 + + Portuguese Luxembourg 0x1000 pt-LU Release 10.2 + + Portuguese Macao SAR 0x1000 pt-MO Release 10 + + Portuguese Mozambique 0x1000 pt-MZ Release 10 + + Portuguese Portugal 0x0816 pt-PT Release A + + + + 50 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Portuguese São Tomé and Príncipe 0x1000 pt-ST Release 10 + + Portuguese Switzerland 0x1000 pt-CH Release 10.2 + + Portuguese Timor-Leste 0x1000 pt-TL Release 10 + + Prussian 0x1000 prg-001 Release 10.1 + + Pseudo Language Pseudo locale for east Asian/complex 0x05FE qps-ploca Release 7 + script localization testing + + Pseudo Language Pseudo locale used for localization 0x0501 qps-ploc Release 7 + testing + + Pseudo Language Pseudo locale used for localization 0x09FF qps-plocm Release 7 + testing of mirrored locales + + Punjabi 0x0046 pa Release 7 + + Punjabi 0x7C46 pa-Arab Release 8 + + Punjabi India 0x0446 pa-IN Release D + + Punjabi Islamic Republic of Pakistan 0x0846 pa-Arab-PK Release 8 + + Quechua 0x006B quz Release 7 + + Quechua Bolivia 0x046B quz-BO Release E1 + + Quechua Ecuador 0x086B quz-EC Release E1 + + Quechua Peru 0x0C6B quz-PE Release E1 + + Rajasthani 0x1000 raj Release 11 + + Rajasthani 0x1000 raj-Deva Release 11 + (Devanagari) + + Rajasthani India 0x1000 raj-Deva-IN Release 11 + (Devanagari) + + Ripuarian 0x1000 ksh Release 10 + + Ripuarian Germany 0x1000 ksh-DE Release 10 + + Romanian 0x0018 ro Release 7 + + Romanian Moldova 0x0818 ro-MD Release 8.1 + + Romanian Romania 0x0418 ro-RO Release A + + Romansh 0x0017 rm Release 7 + + Romansh Switzerland 0x0417 rm-CH Release E2 + + Rombo 0x1000 rof Release 10 + + Rombo Tanzania 0x1000 rof-TZ Release 10 + + Rundi 0x1000 rn Release 10 + + Rundi Burundi 0x1000 rn-BI Release 10 + + + 51 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Russian 0x0019 ru Release 7 + + Russian Belarus 0x1000 ru-BY Release 10 + + Russian Kazakhstan 0x1000 ru-KZ Release 10 + + Russian Kyrgyzstan 0x1000 ru-KG Release 10 + + Russian Moldova 0x0819 ru-MD Release 10 + + Russian Russia 0x0419 ru-RU Release A + + Russian Ukraine 0x1000 ru-UA Release 10 + + Rwa 0x1000 rwk Release 10 + + Rwa Tanzania 0x1000 rwk-TZ Release 10 + + Saho 0x1000 ssy Release 10 + + Saho Eritrea 0x1000 ssy-ER Release 10 + + Sakha 0x0085 sah Release 7 + + Sakha Russia 0x0485 sah-RU Release V + + Samburu 0x1000 saq Release 10 + + Samburu Kenya 0x1000 saq-KE Release 10 + + Sami (Inari) 0x703B smn Windows 7 + + Sami (Inari) Finland 0x243B smn-FI Release E1 + + Sami (Lule) 0x7C3B smj Windows 7 + + Sami (Lule) Norway 0x103B smj-NO Release E1 + + Sami (Lule) Sweden 0x143B smj-SE Release E1 + + Sami (Northern) 0x003B se Release 7 + + Sami (Northern) Finland 0x0C3B se-FI Release E1 + + Sami (Northern) Norway 0x043B se-NO Release E1 + + Sami (Northern) Sweden 0x083B se-SE Release E1 + + Sami (Skolt) 0x743B sms Windows 7 + + Sami (Skolt) Finland 0x203B sms-FI Release E1 + + Sami (Southern) 0x783B sma Windows 7 + + Sami (Southern) Norway 0x183B sma-NO Release E1 + + Sami (Southern) Sweden 0x1C3B sma-SE Release E1 + + Sango 0x1000 sg Release 10 + + Sango Central African Republic 0x1000 sg-CF Release 10 + + + + 52 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Sangu 0x1000 sbp Release 10 + + Sangu Tanzania 0x1000 sbp-TZ Release 10 + + Sanskrit 0x004F sa Release 7 + + Sanskrit India 0x044F sa-IN Release C + + Sardinian 0x1000 sc Release 11 + + Sardinian (Latin) 0x1000 sc-Latn Release 11 + + Sardinian (Latin) Italy 0x1000 sc-Latn-IT Release 11 + + Scottish Gaelic 0x0091 gd Windows 7 + + Scottish Gaelic United Kingdom 0x0491 gd-GB Release 7 + + Sena 0x1000 seh Release 10 + + Sena Mozambique 0x1000 seh-MZ Release 10 + + Serbian (Cyrillic) 0x6C1A sr-Cyrl Windows 7 + + Serbian (Cyrillic) Bosnia and Herzegovina 0x1C1A sr-Cyrl-BA Release E1 + + Serbian (Cyrillic) Montenegro 0x301A sr-Cyrl-ME Release 7 + + Serbian (Cyrillic) Serbia 0x281A sr-Cyrl-RS Release 7 + + Serbian (Cyrillic) Serbia and Montenegro (Former) 0x0C1A sr-Cyrl-CS Release B + + Serbian (Latin) 0x701A sr-Latn Windows 7 + + Serbian (Latin) 0x7C1A sr Release 7 + + Serbian (Latin) Bosnia and Herzegovina 0x181A sr-Latn-BA Release E1 + + Serbian (Latin) Montenegro 0x2c1A sr-Latn-ME Release 7 + + Serbian (Latin) Serbia 0x241A sr-Latn-RS Release 7 + + Serbian (Latin) Serbia and Montenegro (Former) 0x081A sr-Latn-CS Release B + + Sesotho sa Leboa 0x006C nso Release 7 + + Sesotho sa Leboa South Africa 0x046C nso-ZA Release E1 + + Setswana 0x0032 tn Release 7 + + Setswana Botswana 0x0832 tn-BW Release 8 + + Setswana South Africa 0x0432 tn-ZA Release E1 + + Shambala 0x1000 ksb Release 10 + + Shambala Tanzania 0x1000 ksb-TZ Release 10 + + Shona 0x1000 sn Release 8.1 + + Shona Latin 0x1000 sn-Latn Release 8.1 + + + + 53 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Shona Zimbabwe 0x1000 sn-Latn-ZW Release 8.1 + + Sindhi 0x0059 sd Release 8 + + Sindhi 0x7C59 sd-Arab Release 8 + + Sindhi Islamic Republic of Pakistan 0x0859 sd-Arab-PK Release 8 + + Sinhala 0x005B si Release 7 + + Sinhala Sri Lanka 0x045B si-LK Release V + + Slovak 0x001B sk Release 7 + + Slovak Slovakia 0x041B sk-SK Release A + + Slovenian 0x0024 sl Release 7 + + Slovenian Slovenia 0x0424 sl-SI Release A + + Soga 0x1000 xog Release 10 + + Soga Uganda 0x1000 xog-UG Release 10 + + Somali 0x0077 so Release 8.1 + + Somali Djibouti 0x1000 so-DJ Release 10 + + Somali Ethiopia 0x1000 so-ET Release 10 + + Somali Kenya 0x1000 so-KE Release 10 + + Somali Somalia 0x0477 so-SO Release 8.1 + + Sotho 0x0030 st Release 8.1 + + Sotho South Africa 0x0430 st-ZA Release 8.1 + + South Ndebele 0x1000 nr Release 10 + + South Ndebele South Africa 0x1000 nr-ZA Release 10 + + Southern Sotho Lesotho 0x1000 st-LS Release 10 + + Spanish 0x000A es Release 7 + + Spanish Argentina 0x2C0A es-AR Release B + + Spanish Belize 0x1000 es-BZ Release 10.3 + + Spanish Bolivarian Republic of Venezuela 0x200A es-VE Release B + + Spanish Bolivia 0x400A es-BO Release B + + Spanish Brazil 0x1000 es-BR Release 10.2 + + Spanish Chile 0x340A es-CL Release B + + Spanish Colombia 0x240A es-CO Release B + + Spanish Costa Rica 0x140A es-CR Release B + + + + 54 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Spanish Cuba 0x5c0A es-CU Release 10 + + Spanish Dominican Republic 0x1c0A es-DO Release B + + Spanish Ecuador 0x300A es-EC Release B + + Spanish El Salvador 0x440A es-SV Release B + + Spanish Equatorial Guinea 0x1000 es-GQ Release 10 + + Spanish Guatemala 0x100A es-GT Release B + + Spanish Honduras 0x480A es-HN Release B + + Spanish Latin America 0x580A es-419 Release 8.1 + + Spanish Mexico 0x080A es-MX Release A + + Spanish Nicaragua 0x4C0A es-NI Release B + + Spanish Panama 0x180A es-PA Release B + + Spanish Paraguay 0x3C0A es-PY Release B + + Spanish Peru 0x280A es-PE Release B + + Spanish Philippines 0x1000 es-PH Release 10 + + Spanish Puerto Rico 0x500A es-PR Release B + + Spanish Spain 0x040A es-ES_tradnl Release A + + Spanish Spain 0x0c0A es-ES Release A + + Spanish United States 0x540A es-US Release V + + Spanish Uruguay 0x380A es-UY Release B + + Standard Moroccan 0x1000 zgh Release 8.1 + Tamazight + + Standard Moroccan Morocco 0x1000 zgh-Tfng-MA Release 8.1 + Tamazight + + Standard Moroccan Tifinagh 0x1000 zgh-Tfng Release 8.1 + Tamazight + + Swati 0x1000 ss Release 10 + + Swati South Africa 0x1000 ss-ZA Release 10 + + Swati Swaziland 0x1000 ss-SZ Release 10 + + Swedish 0x001D sv Release 7 + + Swedish Åland Islands 0x1000 sv-AX Release 10 + + Swedish Finland 0x081D sv-FI Release B + + Swedish Sweden 0x041D sv-SE Release A + + Syriac 0x005A syr Release 7 + + + 55 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Syriac Syria 0x045A syr-SY Release D + + Tachelhit 0x1000 shi Release 10 + + Tachelhit Tifinagh 0x1000 shi-Tfng Release 10 + + Tachelhit Tifinagh, Morocco 0x1000 shi-Tfng-MA Release 10 + + Tachelhit (Latin) 0x1000 shi-Latn Release 10 + + Tachelhit (Latin) Morocco 0x1000 shi-Latn-MA Release 10 + + Taita 0x1000 dav Release 10 + + Taita Kenya 0x1000 dav-KE Release 10 + + Tajik (Cyrillic) 0x0028 tg Release 7 + + Tajik (Cyrillic) 0x7C28 tg-Cyrl Windows 7 + + Tajik (Cyrillic) Tajikistan 0x0428 tg-Cyrl-TJ Release V + + Tamazight (Latin) 0x005F tzm Release 7 + + Tamazight (Latin) 0x7C5F tzm-Latn Windows 7 + + Tamazight (Latin) Algeria 0x085F tzm-Latn-DZ Release V + + Tamil 0x0049 ta Release 7 + + Tamil India 0x0449 ta-IN Release C + + Tamil Malaysia 0x1000 ta-MY Release 10 + + Tamil Singapore 0x1000 ta-SG Release 10 + + Tamil Sri Lanka 0x0849 ta-LK Release 8 + + Tasawaq 0x1000 twq Release 10 + + Tasawaq Niger 0x1000 twq-NE Release 10 + + Tatar 0x0044 tt Release 7 + + Tatar Russia 0x0444 tt-RU Release D + + Telugu 0x004A te Release 7 + + Telugu India 0x044A te-IN Release D + + Teso 0x1000 teo Release 10 + + Teso Kenya 0x1000 teo-KE Release 10 + + Teso Uganda 0x1000 teo-UG Release 10 + + Thai 0x001E th Release 7 + + Thai Thailand 0x041E th-TH Release B + + Tibetan 0x0051 bo Release 7 + + + + 56 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Tibetan India 0x1000 bo-IN Release 10 + + Tibetan People's Republic of China 0x0451 bo-CN Release V + + Tigre 0x1000 tig Release 10 + + Tigre Eritrea 0x1000 tig-ER Release 10 + + Tigrinya 0x0073 ti Release 8 + + Tigrinya Eritrea 0x0873 ti-ER Release 8 + + Tigrinya Ethiopia 0x0473 ti-ET Release 8 + + Tongan 0x1000 to Release 10 + + Tongan Tonga 0x1000 to-TO Release 10 + + Tsonga 0x0031 ts Release 8.1 + + Tsonga South Africa 0x0431 ts-ZA Release 8.1 + + Turkish 0x001F tr Release 7 + + Turkish Cyprus 0x1000 tr-CY Release 10 + + Turkish Turkey 0x041F tr-TR Release A + + Turkmen 0x0042 tk Release 7 + + Turkmen Turkmenistan 0x0442 tk-TM Release V + + Ukrainian 0x0022 uk Release 7 + + Ukrainian Ukraine 0x0422 uk-UA Release B + + Upper Sorbian 0x002E hsb Release 7 + + Upper Sorbian Germany 0x042E hsb-DE Release V + + Urdu 0x0020 ur Release 7 + + Urdu India 0x0820 ur-IN Release 8.1 + + Urdu Islamic Republic of Pakistan 0x0420 ur-PK Release C + + Uyghur 0x0080 ug Release 7 + + Uyghur People's Republic of China 0x0480 ug-CN Release V + + Uzbek Perso-Arabic 0x1000 uz-Arab Release 10 + + Uzbek Perso-Arabic, Afghanistan 0x1000 uz-Arab-AF Release 10 + + Uzbek (Cyrillic) 0x7843 uz-Cyrl Windows 7 + + Uzbek (Cyrillic) Uzbekistan 0x0843 uz-Cyrl-UZ Release C + + Uzbek (Latin) 0x0043 uz Release 7 + + Uzbek (Latin) 0x7C43 uz-Latn Windows 7 + + + + 57 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Uzbek (Latin) Uzbekistan 0x0443 uz-Latn-UZ Release C + + Vai 0x1000 vai Release 10 + + Vai 0x1000 vai-Vaii Release 10 + + Vai Liberia 0x1000 vai-Vaii-LR Release 10 + + Vai (Latin) Liberia 0x1000 vai-Latn-LR Release 10 + + Vai (Latin) 0x1000 vai-Latn Release 10 + + Valencian Spain 0x0803 ca-ES- Release 8 + valencia + + Venda 0x0033 ve Release 10 + + Venda South Africa 0x0433 ve-ZA Release 10 + + Vietnamese 0x002A vi Release 7 + + Vietnamese Vietnam 0x042A vi-VN Release B + + Volapük 0x1000 vo Release 10 + + Volapük World 0x1000 vo-001 Release 10 + + Vunjo 0x1000 vun Release 10 + + Vunjo Tanzania 0x1000 vun-TZ Release 10 + + Walser 0x1000 wae Release 10 + + Walser Switzerland 0x1000 wae-CH Release 10 + + Welsh 0x0052 cy Release 7 + + Welsh United Kingdom 0x0452 cy-GB Release E1 + + Wolaytta 0x1000 wal Release 10 + + Wolaytta Ethiopia 0x1000 wal-ET Release 10 + + Wolof 0x0088 wo Release 7 + + Wolof Senegal 0x0488 wo-SN Release V + + Xhosa 0x0034 xh Release 7 + + Xhosa South Africa 0x0434 xh-ZA Release E1 + + Yangben 0x1000 yav Release 10 + + Yangben Cameroon 0x1000 yav-CM Release 10 + + Yi 0x0078 ii Release 7 + + Yi People's Republic of China 0x0478 ii-CN Release V + + Yiddish World 0x043D yi-001 Release 10 + + Yoruba 0x006A yo Release 7 + + + 58 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 + Language Language Supported + Language Location (or type) ID tag version + + Yoruba Benin 0x1000 yo-BJ Release 10 + + Yoruba Nigeria 0x046A yo-NG Release V + + Zarma 0x1000 dje Release 10 + + Zarma Niger 0x1000 dje-NE Release 10 + + Zulu 0x0035 zu Release 7 + + Zulu South Africa 0x0435 zu-ZA Release E1 + + + + +<9> Section 2.2: Supported only on Windows 7. + +<10> Section 2.2: Supported only on Windows 7. + +<11> Section 2.2: Supported only on Windows 7. + +<12> Section 2.2: Not supported in client releases earlier than Windows 10 or server releases earlier +than Windows Server 2016. + +<13> Section 2.2: Not supported in client releases earlier than Windows 10 or server releases earlier +than Windows Server 2016. + +<14> Section 2.2.1: The temporary Locale Names without LCID assignments are not supported in +versions before Windows Vista and Windows Server 2008 operating system with Service Pack 2 (SP2). + +<15> Section 2.2.1: Not supported in versions before Windows Vista and Windows Server 2008. + +<16> Section 2.2.1: The Transient LCIDs (0x2000, 0x2400, 0x2800, 0x2C00, 0x3000, 0x3400, +0x3800, 0x3C00, 0x4000, 0x4400, 0x4800, and 0x4C00) were introduced in Windows 8 operating +system and Windows Server 2012 operating system and fail in all prior versions. + +<17> Section 2.2.1: Not supported in versions before Windows Vista and Windows Server 2008. + + + + + 59 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 +6 Change Tracking +This section identifies changes that were made to this document since the last release. Changes are +classified as Major, Minor, or None. + +The revision class Major means that the technical content in the document was significantly revised. +Major changes affect protocol interoperability or implementation. Examples of major changes are: + + A document revision that incorporates changes to interoperability requirements. + A document revision that captures changes to protocol functionality. + +The revision class Minor means that the meaning of the technical content was clarified. Minor changes +do not affect protocol interoperability or implementation. Examples of minor changes are updates to +clarify ambiguity at the sentence, paragraph, or table level. + +The revision class None means that no new technical changes were introduced. Minor editorial and +formatting changes may have been made, but the relevant technical content is identical to the last +released version. + +The changes made to this document are listed in the following table. For more information, please +contact dochelp@microsoft.com. + + Revision + Section Description + class + + 11352 : Added four unassigned locales temporarily assigned to + 2.2 LCID Structure Major + 0x3000. + + Updated for Windows 11 24H2 and Windows Server 2025. + 2.2 LCID Structure Major + Updated the list of neutrals and locales. + + 2.2.1 Locale Names 11352 : Added four unassigned locales temporarily assigned to + Major + without LCIDs 0x3000. + + 5 Appendix A: Product + Added Windows Server 2025 to the product applicability list. Major + Behavior + + + + + 60 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 +7 Index +. + T +.NET - LCIDs as culture identifiers 8 + Tracking changes 60 +A + V +Applicability 7 + Vendor-extensible fields 7 +C Versioning 7 + +Change tracking 60 +Culture identifiers 8 + +E + +Examples 27 +Examples - LCID values 27 + +F + +Fields - vendor-extensible 7 + +G + +Glossary 5 + +I + +Implementer - security considerations 28 +Informative references 6 +Introduction 5 + +L + +LCID packet 8 +Localization 7 + +N + +Normative references 6 + +O + +Overview (synopsis) 6 + +P + +Product behavior 29 + +R + +References 6 + informative 6 + normative 6 +Relationship to protocols and other structures 7 + +S + +Security 28 +Security - implementer considerations 28 + + + 61 / 61 +[MS-LCID] - v20240423 +Windows Language Code Identifier (LCID) Reference +Copyright © 2024 Microsoft Corporation +Release: April 23, 2024 +
\ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 35a63ad..73c6b8f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# CMAkeLists.txt - Main build script for sbc-harness +# CMakeLists.txt - Main build script for sbc-harness project # # Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> # SPDX-Licence-Identifier: AGPL-3.0-or-later @@ -12,23 +12,15 @@ project(sbc_harness) pico_sdk_init() -add_executable(sbc_harness) -target_sources(sbc_harness PUBLIC - main.c - coroutine.c - usb_common.c - usb_keyboard.c +add_custom_target(generate + COMMENT Create generated files that are included in the source distribution ) -target_include_directories(sbc_harness PUBLIC ${CMAKE_CURRENT_LIST_DIR}) # So TinyUSB can find tusb_config.h -target_link_libraries(sbc_harness - pico_stdlib - pico_unique_id - tinyusb_device - tinyusb_board -) -pico_enable_stdio_usb(sbc_harness 0) -pico_enable_stdio_uart(sbc_harness 1) -pico_enable_stdio_semihosting(sbc_harness 0) -pico_enable_stdio_rtt(sbc_harness 0) -pico_add_extra_outputs(sbc_harness) # create map/bin/hex/uf2 file in addition to ELF. -pico_set_program_url(sbc_harness "https://git.lukeshu.com/sbc-harness") + +add_subdirectory(libcr) +add_subdirectory(libcr_ipc) +add_subdirectory(libusb) +add_subdirectory(libnetio) +add_subdirectory(lib9p) + +add_subdirectory(cmd/sbc_harness) +add_subdirectory(cmd/srv9p) diff --git a/HACKING.md b/HACKING.md new file mode 100644 index 0000000..1492820 --- /dev/null +++ b/HACKING.md @@ -0,0 +1,10 @@ +Source layout + + - cmd/sbc_harness + - cmd/srv9p + - libcr - A simple coroutine (cooperative multitasking) library + - libcr_ipc - IPC primatives for coroutines built on top of libcr + - libnetio - TODO + - lib9p - A simple 9P protocol server library + - libusb - TODO + @@ -12,3 +12,5 @@ 1. [ ] PicoDVI hello-world 2. [ ] "PiciDVI" to network 3. [ ] reverse the flow of PicoDVI + +https://hackaday.com/2022/08/26/bit-banged-ethernet-on-the-raspberry-pi-pico/ diff --git a/cmd/sbc_harness/CMakeLists.txt b/cmd/sbc_harness/CMakeLists.txt new file mode 100644 index 0000000..34f6360 --- /dev/null +++ b/cmd/sbc_harness/CMakeLists.txt @@ -0,0 +1,23 @@ +# cmd/sbc_harness/CMakeLists.txt - Build script for main sbc_harness.uf2 firmware file +# +# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-Licence-Identifier: AGPL-3.0-or-later + +add_executable(sbc_harness + main.c + usb_keyboard.c +) +target_include_directories(sbc_harness PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/config) +target_link_libraries(sbc_harness + pico_stdlib + pico_unique_id + tinyusb_device + tinyusb_board + libusb +) +pico_enable_stdio_usb(sbc_harness 0) +pico_enable_stdio_uart(sbc_harness 1) +pico_enable_stdio_semihosting(sbc_harness 0) +pico_enable_stdio_rtt(sbc_harness 0) +pico_add_extra_outputs(sbc_harness) # create .map/.bin/.hex/.uf2 files in addition to .elf +pico_set_program_url(sbc_harness "https://git.lukeshu.com/sbc-harness") diff --git a/config.h b/cmd/sbc_harness/config/config.h index 37bfcbe..0f0385b 100644 --- a/config.h +++ b/cmd/sbc_harness/config/config.h @@ -1,4 +1,4 @@ -/* config.h - Compile-time configuration for sbc-harness +/* config.h - Compile-time configuration for sbc_harness * * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-Licence-Identifier: AGPL-3.0-or-later @@ -28,10 +28,6 @@ /*static_assert((CONFIG_COROUTINE_NUM * CONFIG_COROUTINE_DEFAULT_STACK_SIZE) < (264 * 1024)); */ #endif -#ifdef USE_CONFIG_TUSB -# include "tusb_config.h" -#endif - #ifdef USE_CONFIG_9P # define CONFIG_9P_PORT 564 /** diff --git a/libusb/tusb_config.h b/cmd/sbc_harness/config/tusb_config.h index cb1ca3b..cb1ca3b 100644 --- a/libusb/tusb_config.h +++ b/cmd/sbc_harness/config/tusb_config.h diff --git a/cmd/harness/main.c b/cmd/sbc_harness/main.c index 1fd9f8c..1fd9f8c 100644 --- a/cmd/harness/main.c +++ b/cmd/sbc_harness/main.c diff --git a/cmd/harness/usb_keyboard.c b/cmd/sbc_harness/usb_keyboard.c index 1989b35..1989b35 100644 --- a/cmd/harness/usb_keyboard.c +++ b/cmd/sbc_harness/usb_keyboard.c diff --git a/cmd/harness/usb_keyboard.h b/cmd/sbc_harness/usb_keyboard.h index 6b65360..6b65360 100644 --- a/cmd/harness/usb_keyboard.h +++ b/cmd/sbc_harness/usb_keyboard.h diff --git a/cmd/srv9p/CMakeLists.txt b/cmd/srv9p/CMakeLists.txt new file mode 100644 index 0000000..3db8795 --- /dev/null +++ b/cmd/srv9p/CMakeLists.txt @@ -0,0 +1,15 @@ +# cmd/srv9p/CMakeLists.txt - Build script for srv9p test/dev executable +# +# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-Licence-Identifier: AGPL-3.0-or-later + +add_executable(srv9p + main.c +) +target_include_directories(srv9p PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/config) +target_link_libraries(srv9p + libcr + libcr_ipc + libnetio + lib9p +) diff --git a/cmd/srv9p/config/config.h b/cmd/srv9p/config/config.h new file mode 120000 index 0000000..2edbd7b --- /dev/null +++ b/cmd/srv9p/config/config.h @@ -0,0 +1 @@ +../../sbc_harness/config/config.h
\ No newline at end of file diff --git a/lib9p/.editorconfig b/lib9p/.editorconfig index 3f04564..5c79099 100644 --- a/lib9p/.editorconfig +++ b/lib9p/.editorconfig @@ -1,3 +1,3 @@ -[{defs.gen,linux-errno.h.gen}] +[{types.gen,linux-errno.h.gen}] indent_style = space indent_size = 4 diff --git a/lib9p/.gitignore b/lib9p/.gitignore deleted file mode 100644 index 667e81c..0000000 --- a/lib9p/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/defs-* -/linux-errno.h diff --git a/lib9p/9P2000.e.txt b/lib9p/9P2000.e.txt index 22f056e..e60bce0 100644 --- a/lib9p/9P2000.e.txt +++ b/lib9p/9P2000.e.txt @@ -8,9 +8,11 @@ # https://github.com/cloudozer/ling/blob/master/doc/9p2000e.md version "9P2000.e" +from 9P2000.txt import * + 150/Tsession = "key[8]" 151/Rsession = "" 152/Tsread = "fid[4] nwname[2] nwname*(wname[s])" 153/Rsread = "data[d]" -154/Tswrite = "Tswrite tag[2] fid[4] nwname[2] nwname*(wname[s]) data[d]" +154/Tswrite = "fid[4] nwname[2] nwname*(wname[s]) data[d]" 155/Rswrite = "count[4]" diff --git a/lib9p/9P2000.u.txt b/lib9p/9P2000.u.txt index 60d2b11..1fa71fb 100644 --- a/lib9p/9P2000.u.txt +++ b/lib9p/9P2000.u.txt @@ -18,3 +18,28 @@ stat += "file_extension[s]" Tauth += "n_uname[4]" Rerror += "errno[4]" + +# # qid.types +# QTDIR = 1<<7 +# QTAPPEND = 1<<6 +# QTEXCL = 1<<5 +# QTMOUNT = 1<<4 # been around forever, but undocumented? +# QTAUTH = 1<<3 +# QTTMP = 1<<2 # added to Plan 9 2003-12 +# QTSYMLINK = 1<<1 # .u +# QTFILE = 1<<0 +# +# DMDIR = 1<<31 +# DMAPPEND = 1<<30 +# DMEXCL = 1<<29 +# DMMOUNT = 1<<28 +# DMAUTH = 1<<27 +# DMTMP = 1<<26 +# # = 1<<25 +# # = 1<<24 +# DMDEVICE = 1<<23 # .u +# # = 1<<22 +# DMNAMEDPIPE = 1<<21 # .u +# DMSOCKET = 1<<20 # .u +# DMSETUID = 1<<19 # .u +# DMSETGID = 1<<18 # .u diff --git a/lib9p/defs.c b/lib9p/9p.c index 886a0c1..64b09a6 100644 --- a/lib9p/defs.c +++ b/lib9p/9p.c @@ -1,4 +1,4 @@ -/* 9p/defs.c - TODO +/* lib9p/9p.c - Base 9P protocol utilities for both clients and servers * * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-Licence-Identifier: AGPL-3.0-or-later @@ -9,23 +9,28 @@ #include <stdio.h> /* for vsnprintf() */ #include <string.h> /* for strncpy() */ -#include "9p/defs.h" -#include "9p/linux-errno.h" -#include "9p/internal.h" +#include <lib9p/9p.h> -static struct version *versions[_P9_VER_CNT] = { - [P9_VER_9P2000] = &version_9P2000, - /* [P9_VER_9P2000u] = &version_9P2000u, */ -}; +#include "internal.h" -int p9_error(struct p9_ctx *ctx, uint32_t linux_errno, char const *msg) { +enum lib9p_version lib9p_ctx_version(lib9p_ctx *ctx) { + assert(ctx); + return ctx->version; +} + +uint32_t lib9p_ctx_max_msg_size(lib9p_ctx *ctx) { + assert(ctx); + return ctx->max_msg_size; +} + +int lib9p_error(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *msg) { strncpy(ctx->err_msg, msg, sizeof(ctx->err_msg)); ctx->err_msg[sizeof(ctx->err_msg)-1] = '\0'; ctx->err_num = linux_errno; return -1; } -int p9_errorf(struct p9_ctx *ctx, uint32_t linux_errno, char const *fmt, ...) { +int lib9p_errorf(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *fmt, ...) { int n; va_list args; @@ -40,25 +45,25 @@ int p9_errorf(struct p9_ctx *ctx, uint32_t linux_errno, char const *fmt, ...) { return -1; } -size_t p9_unmarshal_size(struct p9_ctx *ctx, uint8_t *net_bytes) { +size_t lib9p_unmarshal_size(struct lib9p_ctx *ctx, uint8_t *net_bytes) { /* Header */ uint32_t net_len = decode_u32le(net_bytes); if (net_len < 7) - return p9_error(ctx, LINUX_EBADMSG, "message is too short"); + return lib9p_error(ctx, LINUX_EBADMSG, "message is too short"); uint8_t typ = net_bytes[4]; uint32_t net_offset = 7; /* Body */ if (!versions[ctx->version]->msgs[typ].unmarshal_extrasize) - return p9_errorf(ctx, LINUX_EOPNOTSUPP, "unknown message type %"PRIu8, typ); + return lib9p_errorf(ctx, LINUX_EOPNOTSUPP, "unknown message type %"PRIu8, typ); size_t host_size = versions[ctx->version]->msgs[typ].unmarshal_basesize; if (versions[ctx->version]->msgs[typ].unmarshal_extrasize(net_len, net_bytes, &net_offset, &host_size)) - return p9_error(ctx, LINUX_EBADMSG, "message is too short for content"); + return lib9p_error(ctx, LINUX_EBADMSG, "message is too short for content"); return host_size; } -uint8_t p9_unmarshal(struct p9_ctx *ctx, uint8_t *net_bytes, uint16_t *out_tag, void *out_body) { +uint8_t lib9p_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, uint16_t *out_tag, void *out_body) { /* Header */ uint8_t typ = net_bytes[4]; *out_tag = decode_u16le(&net_bytes[5]); @@ -67,12 +72,12 @@ uint8_t p9_unmarshal(struct p9_ctx *ctx, uint8_t *net_bytes, uint16_t *out_tag, /* Body */ void *host_extra = out_body + versions[ctx->version]->msgs[typ].unmarshal_basesize; if (versions[ctx->version]->msgs[typ].unmarshal(net_bytes, &net_offset, &host_extra, out_body)) - return p9_error(ctx, LINUX_EBADMSG, "message contains invalid UTF-8"); + return lib9p_error(ctx, LINUX_EBADMSG, "message contains invalid UTF-8"); return typ; } -uint32_t _p9_marshal(struct p9_ctx *ctx, uint8_t typ, uint16_t msgid, void *body, uint8_t *out_bytes) { +uint32_t lib9p_marshal(struct lib9p_ctx *ctx, uint8_t typ, uint16_t msgid, void *body, uint8_t *out_bytes) { /* Header */ out_bytes[4] = typ; encode_u16le(msgid, &out_bytes[5]); diff --git a/lib9p/9p.h b/lib9p/9p.h deleted file mode 100644 index 63fbd04..0000000 --- a/lib9p/9p.h +++ /dev/null @@ -1,15 +0,0 @@ -/* 9p/9p.h - TODO - * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> - * SPDX-Licence-Identifier: AGPL-3.0-or-later - */ - -#include "9p/linux-errno.h" -#include "9p/defs.h" -#include "9p/defs-9P2000.h" -/*#include "9p/defs-9P2000.u.h"*/ - -#define P9_TYPECODE_FOR_CTYPE(msg) _Generic((in_msg) \ - _P9_TYPECODE_FOR_CTYPE_9P2000(msg) \ - /* _P9_TYPECODE_FOR_CTYPE_9P2000u(msg) */ \ - ) diff --git a/lib9p/CMakeLists.txt b/lib9p/CMakeLists.txt new file mode 100644 index 0000000..0faa109 --- /dev/null +++ b/lib9p/CMakeLists.txt @@ -0,0 +1,34 @@ +# libcr/CMakeLists.txt - TODO +# +# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-Licence-Identifier: AGPL-3.0-or-later + +add_library(lib9p INTERFACE) +target_sources(lib9p INTERFACE + types.c + 9p.c + srv.c +) +target_include_directories(lib9p SYSTEM INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) + +add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/3rd-party/linux-errno.txt + DEPENDS ${CMAKE_SOURCE_DIR}/3rd-party/linux-errno.txt.gen + COMMAND ${CMAKE_SOURCE_DIR}/3rd-party/linux-errno.txt.gen +) +add_custom_command( + OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/include/lib9p/linux-errno.h + DEPENDS include/lib9p/linux-errno.h.gen ${CMAKE_SOURCE_DIR}/3rd-party/linux-errno.txt + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/include/lib9p/linux-errno.h.gen ${CMAKE_SOURCE_DIR}/3rd-party/linux-errno.txt >${CMAKE_CURRENT_SOURCE_DIR}/include/lib9p/linux-errno.h +) +add_custom_command( + OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/types.c ${CMAKE_CURRENT_SOURCE_DIR}/include/lib9p/_types.h + DEPENDS types.gen 9P2000.txt 9P2000.u.txt 9P2000.e.txt + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/types.gen 9P2000.txt 9P2000.u.txt 9P2000.e.txt +) +add_dependencies(generate + ${CMAKE_SOURCE_DIR}/3rd-party/linux-errno.txt + ${CMAKE_CURRENT_SOURCE_DIR}/linux-errno.h + ${CMAKE_CURRENT_SOURCE_DIR}/types.c + ${CMAKE_CURRENT_SOURCE_DIR}/include/lib9p/_types.h +) diff --git a/lib9p/defs.gen b/lib9p/defs.gen deleted file mode 100755 index 1a8dc69..0000000 --- a/lib9p/defs.gen +++ /dev/null @@ -1,456 +0,0 @@ -#!/usr/bin/env python -# 9p/defs.gen - Generate C marshalers/unmarshalers for a .txt file -# defining a 9P protocol variant. -# -# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> -# SPDX-Licence-Identifier: AGPL-3.0-or-later - -import enum -import os.path -import re - -PROGRAM = "./9p/defs.gen" - -# Parse the *.txt ############################################################## - - -class Atom(enum.Enum): - u8 = 1 - u16 = 2 - u32 = 4 - u64 = 8 - - @property - def name(self) -> str: - return str(self.value) - - @property - def static_size(self) -> int: - return self.value - - -# `msgid/structname = "member1 member2..."` -# `structname = "member1 member2..."` -# `structname += "member1 member2..."` -class Struct: - msgid: int | None = None - name: str - members: list["Member"] - - @property - def static_size(self) -> int | None: - size = 0 - for member in self.members: - msize = member.static_size - if msize is None: - return None - size += msize - return size - - -# `cnt*(name[typ])` -# the `cnt*(...)` wrapper is optional -class Member: - cnt: str | None = None - name: str - typ: Atom | Struct - - @property - def static_size(self) -> int | None: - if self.cnt: - return None - return self.typ.static_size - - -re_membername = "(?:[a-zA-Z_][a-zA-Z_0-9]*)" -re_memberspec = ( - f"(?:(?P<cnt>{re_membername})\\*\\()?(?P<name>{re_membername})\\[(?P<typ>.*)\\]\\)?" -) - - -def parse_members( - env: dict[str, Atom | Struct], existing: list[Member], specs: str -) -> list[Member]: - ret = existing - for spec in specs.split(): - m = re.fullmatch(re_memberspec, spec) - if not m: - raise SyntaxError(f"invalid member spec {repr(spec)}") - - member = Member() - - member.name = m.group("name") - if any(x.name == member.name for x in ret): - raise ValueError(f"duplicate member name {repr(member.name)}") - - if m.group("typ") not in env: - raise NameError(f"Unknown type {repr(m.group(2))}") - member.typ = env[m.group("typ")] - - if cnt := m.group("cnt"): - if len(ret) == 0 or ret[-1].name != cnt: - raise ValueError(f"list count must be previous item: {repr(cnt)}") - if not isinstance(ret[-1].typ, Atom): - raise ValueError(f"list count must be an integer type: {repr(cnt)}") - member.cnt = cnt - - ret += [member] - return ret - - -re_version = r'version\s+"(?P<version>[^"]+)"' -re_structspec = ( - r'(?:(?P<msgid>[0-9]+)/)?(?P<name>\S+)\s*(?P<op>\+?=)\s*"(?P<members>[^"]*)"' -) -re_structspec_cont = r'"(?P<members>[^"]*)"' - - -def parse_file(filename: str) -> tuple[str, list[Struct]]: - version: str | None = None - env: dict[str, Atom | Struct] = { - "1": Atom.u8, - "2": Atom.u16, - "4": Atom.u32, - "8": Atom.u64, - } - with open(filename, "r") as fh: - prev: Struct | None = None - for line in fh: - line = line.split("#", 1)[0].strip() - if not line: - continue - if m := re.fullmatch(re_version, line): - if version: - raise SyntaxError("must have exactly 1 version line") - version = m.group("version") - elif m := re.fullmatch(re_structspec, line): - if m.group("op") == "+=" and m.group("msgid"): - raise SyntaxError("cannot += to a message that is not yet defined") - match m.group("op"): - case "=": - struct = Struct() - if m.group("msgid"): - struct.msgid = int(m.group("msgid")) - struct.name = m.group("name") - struct.members = parse_members(env, [], m.group("members")) - env[struct.name] = struct - prev = struct - case "+=": - if m.group("name") not in env: - raise NameError(f"Unknown type {repr(m.group('name'))}") - _struct = env[m.group("name")] - if not isinstance(_struct, Struct): - raise NameError( - f"Type {repr(m.group('name'))} is not a struct" - ) - struct = _struct - struct.members = parse_members( - env, struct.members, m.group("members") - ) - prev = struct - elif m := re.fullmatch(re_structspec_cont, line): - if not prev: - raise SyntaxError("continuation line must come after a struct line") - prev.members = parse_members(env, prev.members, m.group("members")) - else: - raise SyntaxError(f"invalid line {repr(line)}") - if not version: - raise SyntaxError("must have exactly 1 version line") - structs = [x for x in env.values() if isinstance(x, Struct)] - return version, structs - - -# Generate C ################################################################### - - -def c_typename(idprefix: str, typ: Atom | Struct) -> str: - match typ: - case Atom(): - return f"uint{typ.value*8}_t" - case Struct(): - if typ.msgid is not None: - return f"struct {idprefix}msg_{typ.name}" - return f"struct {idprefix}{typ.name}" - case _: - raise ValueError(f"not a type: {typ.__class__.__name__}") - - -def gen_h(txtname: str, idprefix: str, structs: list[Struct]) -> str: - guard = ( - f"_{txtname.replace('.txt', '.h').upper().replace('/', '_').replace('.', '_')}_" - ) - ret = f"""/* Generated by `{PROGRAM} {txtname}`. DO NOT EDIT! */ - -#ifndef {guard} -#define {guard} - -#define {idprefix.upper()}MIN_MSGLEN 7 -""" - ret += """ -/* non-message structs ********************************************************/ - -""" - for struct in structs: - if struct.msgid is not None: - continue - ret += c_typename(idprefix, struct) + " {\n" - typewidth = max( - len(c_typename(idprefix, member.typ)) for member in struct.members - ) - for member in struct.members: - ret += f"\t{c_typename(idprefix, member.typ).ljust(typewidth)} {'*' if member.cnt else ' '}{member.name};\n" - ret += "};\n" - - ret += """ -/* message types **************************************************************/ - -""" - ret += f"enum {idprefix}msg_type {{ /* uint8_t */\n" - namewidth = max(len(msg.name) for msg in structs if msg.msgid is not None) - for msg in structs: - if msg.msgid is None: - continue - ret += f"\t{idprefix.upper()}TYP_{msg.name.ljust(namewidth)} = {msg.msgid},\n" - ret += "};\n" - - ret += """ -/* message structs ************************************************************/ - -""" - for msg in structs: - if msg.msgid is None: - continue - if not msg.members: - ret += c_typename(idprefix, msg) + " {};\n" - continue - ret += c_typename(idprefix, msg) + " {\n" - typewidth = max(len(c_typename(idprefix, member.typ)) for member in msg.members) - for member in msg.members: - ret += f"\t{c_typename(idprefix, member.typ).ljust(typewidth)} {'*' if member.cnt else ' '}{member.name};\n" - ret += "};\n" - - ret += f""" -/* tables *********************************************************************/ - -#define _P9_TYPECODE_FOR_CTYPE(msg) """ - for msg in structs: - if msg.msgid is None: - continue - ret += f", \\\n\t\t{c_typename(idprefix, msg)}: {idprefix.upper()}TYP_{msg.name}" - ret += "\n" - - ret += "\n" - ret += f"#endif /* {guard} */\n" - return ret - - -def gen_c(txtname: str, idprefix: str, structs: list[Struct]) -> str: - txtdir, txtbase = os.path.split(txtname) - header = os.path.join(txtdir, "defs-" + txtbase.replace(".txt", ".h")) - ret = f"""/* Generated by `{PROGRAM} {txtname}`. DO NOT EDIT! */ - -#include <stdbool.h> -#include <stdint.h> -#include <stdlib.h> /* for malloc() */ - -#include "{header}" -#include "9p/internal.h" -""" - - def used(arg: str) -> str: - return arg - - def unused(arg: str) -> str: - return f"UNUSED({arg})" - - # checksize_* ############################################################## - ret += """ -/* checksize_* ****************************************************************/ - -static inline bool _checksize_list(size_t cnt, _checksize_fn_t fn, size_t host_size, - uint32_t net_len, uint8_t *net_bytes, uint32_t *mut_net_offset, size_t *mut_host_extra) { - for (size_t i = 0; i < cnt; i++) - if (__builtin_add_overflow(*mut_host_extra, host_size, mut_host_extra) - || fn(net_len, net_bytes, mut_net_offset, mut_host_extra)) - return true; - return false; -} - -static inline bool checksize_1(uint32_t net_len, uint8_t *UNUSED(net_bytes), uint32_t *mut_net_offset, size_t *UNUSED(mut_host_extra)) { - return __builtin_add_overflow(*mut_net_offset, 1, mut_net_offset) || net_len < *mut_net_offset; -} -static inline bool checksize_2(uint32_t net_len, uint8_t *UNUSED(net_bytes), uint32_t *mut_net_offset, size_t *UNUSED(mut_host_extra)) { - return __builtin_add_overflow(*mut_net_offset, 2, mut_net_offset) || net_len < *mut_net_offset; -} -static inline bool checksize_4(uint32_t net_len, uint8_t *UNUSED(net_bytes), uint32_t *mut_net_offset, size_t *UNUSED(mut_host_extra)) { - return __builtin_add_overflow(*mut_net_offset, 4, mut_net_offset) || net_len < *mut_net_offset; -} -static inline bool checksize_8(uint32_t net_len, uint8_t *UNUSED(net_bytes), uint32_t *mut_net_offset, size_t *UNUSED(mut_host_extra)) { - return __builtin_add_overflow(*mut_net_offset, 8, mut_net_offset) || net_len < *mut_net_offset; -} - -""" - for struct in structs: - inline = ' inline' if struct.msgid is None else '' - argfn = used if struct.members else unused - ret += f"static{inline} bool checksize_{struct.name}(uint32_t {argfn('net_len')}, uint8_t *{argfn('net_bytes')}, uint32_t *{argfn('mut_net_offset')}, size_t *{argfn('mut_host_extra')}) {{" - if len(struct.members) == 0: - ret += "\n\treturn false;\n" - ret += "}\n" - continue - prefix0 = "\treturn " - prefix1 = "\t || " - prefix2 = "\t " - prefix = prefix0 - prev_size: int | None = None - for member in struct.members: - if member.cnt is not None: - assert prev_size - ret += f"\n{prefix }_checksize_list(decode_u{prev_size*8}le(&net_bytes[(*mut_net_offset)-{prev_size}]), checksize_{member.typ.name}, sizeof({c_typename(idprefix, member.typ)})," - ret += f"\n{prefix2} net_len, net_bytes, mut_net_offset, mut_host_extra)" - else: - ret += f"\n{prefix}checksize_{member.typ.name}(net_len, net_bytes, mut_net_offset, mut_host_extra)" - prefix = prefix1 - prev_size = member.static_size - if struct.name == "s": - ret += ( - f"\n{prefix}__builtin_add_overflow(*mut_host_extra, 1, mut_host_extra)" - ) - ret += ";\n}\n" - - # unmarshal_* ############################################################## - ret += """ -/* unmarshal_* ****************************************************************/ -/* checksize_XXX() should be called before unmarshal_XXX(). */ - -static inline bool unmarshal_1(uint8_t *net_bytes, uint32_t *mut_net_offset, void **UNUSED(mut_host_extra), uint8_t *out) { - *out = decode_u8le(&net_bytes[*mut_net_offset]); - *mut_net_offset += 1; - return false; -} -static inline bool unmarshal_2(uint8_t *net_bytes, uint32_t *mut_net_offset, void **UNUSED(mut_host_extra), uint16_t *out) { - *out = decode_u16le(&net_bytes[*mut_net_offset]); - *mut_net_offset += 2; - return false; -} -static inline bool unmarshal_4(uint8_t *net_bytes, uint32_t *mut_net_offset, void **UNUSED(mut_host_extra), uint32_t *out) { - *out = decode_u32le(&net_bytes[*mut_net_offset]); - *mut_net_offset += 4; - return false; -} -static inline bool unmarshal_8(uint8_t *net_bytes, uint32_t *mut_net_offset, void **UNUSED(mut_host_extra), uint64_t *out) { - *out = decode_u64le(&net_bytes[*mut_net_offset]); - *mut_net_offset += 8; - return false; -} - -""" - for struct in structs: - argfn = used if struct.members else unused - ret += f"static inline bool unmarshal_{struct.name}(uint8_t *{argfn('net_bytes')}, uint32_t *{argfn('mut_net_offset')}, void **{argfn('mut_host_extra')}, {c_typename(idprefix, struct)} *{argfn('out')}) {{\n" - for member in struct.members: - if member.cnt: - ret += f"\tout->{member.name} = *mut_host_extra;\n" - ret += f"\t*mut_host_extra += sizeof(*out->{member.name}) * out->{member.cnt};\n" - ret += f"\tfor (typeof(out->{member.cnt}) i = 0; i < out->{member.cnt}; i++)\n" - ret += f"\t\tif (unmarshal_{member.typ.name}(net_bytes, mut_net_offset, mut_host_extra, &(out->{member.name}[i])))\n" - ret += f"\t\t\treturn true;\n" - if struct.name == "s": - ret += f"\tif (!is_valid_utf8_without_nul(out->{member.name}, out->{member.cnt}))\n" - ret += f"\t\treturn true;\n" - ret += f"\tout->{member.name}[out->{member.cnt}] = '\\0';\n" - else: - ret += f"\tif (unmarshal_{member.typ.name}(net_bytes, mut_net_offset, mut_host_extra, &(out->{member.name})))\n" - ret += f"\t\treturn true;\n" - ret += "\treturn false;\n" - ret += "}\n" - - # marshal_* ################################################################ - ret += """ -/* marshal_* ******************************************************************/ - -static inline bool marshal_1(struct p9_ctx *ctx, uint8_t val, uint8_t *out_net_bytes, uint32_t *mut_net_offset) { - if (*mut_net_offset + 1 > ctx->max_msg_size) - return true; - out_net_bytes[*mut_net_offset] = val; - *mut_net_offset += 1; - return false; -} -static inline bool marshal_2(struct p9_ctx *ctx, uint16_t val, uint8_t *out_net_bytes, uint32_t *mut_net_offset) { - if (*mut_net_offset + 2 > ctx->max_msg_size) - return true; - encode_u16le(val, &out_net_bytes[*mut_net_offset]); - *mut_net_offset += 2; - return false; -} -static inline bool marshal_4(struct p9_ctx *ctx, uint32_t val, uint8_t *out_net_bytes, uint32_t *mut_net_offset) { - if (*mut_net_offset + 4 > ctx->max_msg_size) - return true; - encode_u32le(val, &out_net_bytes[*mut_net_offset]); - *mut_net_offset += 4; - return false; -} -static inline bool marshal_8(struct p9_ctx *ctx, uint64_t val, uint8_t *out_net_bytes, uint32_t *mut_net_offset) { - if (*mut_net_offset + 8 > ctx->max_msg_size) - return true; - encode_u64le(val, &out_net_bytes[*mut_net_offset]); - *mut_net_offset += 8; - return false; -} -""" - for struct in structs: - argfn = used if struct.members else unused - ret += f"static inline bool marshal_{struct.name}(struct p9_ctx *{argfn('ctx')}, {c_typename(idprefix, struct)} {argfn('val')}, uint8_t *{argfn('out_net_bytes')}, uint32_t *{argfn('mut_net_offset')}) {{\n" - for member in struct.members: - if member.cnt: - ret += f"\tfor (typeof(val.{member.cnt}) i = 0; i < val.{member.cnt}; i++)\n" - ret += f"\t\tif (marshal_{member.typ.name}(ctx, val.{member.name}[i], out_net_bytes, mut_net_offset))\n" - ret += f"\t\t\treturn true;\n" - else: - ret += f"\tif (marshal_{member.typ.name}(ctx, val.{member.name}, out_net_bytes, mut_net_offset))\n" - ret += f"\t\treturn true;\n" - ret += "\treturn false;\n" - ret += "}\n" - - # tables ################################################################### - ret += """ -/* tables *********************************************************************/ - -""" - for msg in structs: - if msg.msgid is None: - continue - ret += f"static bool _unmarshal_{msg.name}(uint8_t *net_bytes, uint32_t *mut_net_offset, void **mut_host_extra, void *out) {{ return unmarshal_{msg.name}(net_bytes, mut_net_offset, mut_host_extra, ({c_typename(idprefix, msg)} *)out); }}\n" - for msg in structs: - if msg.msgid is None: - continue - ret += f"static bool _marshal_{msg.name}(struct p9_ctx *ctx, void *val, uint8_t *out_net_bytes, uint32_t *mut_net_offset) {{ return marshal_{msg.name}(ctx, *(({c_typename(idprefix, msg)} *)val), out_net_bytes, mut_net_offset); }}\n" - ret += "struct version version_9P2000 = {\n" - ret += "\t.msgs = {\n" - for msg in structs: - if msg.msgid is None: - continue - ret += f"\t\t[{idprefix.upper()}TYP_{msg.name}] = {{ .unmarshal_basesize=sizeof({c_typename(idprefix, msg)}), .unmarshal_extrasize=checksize_{msg.name}, .unmarshal=_unmarshal_{msg.name}, .marshal=_marshal_{msg.name} }},\n" - ret += "\t},\n" - ret += "};\n" - - ############################################################################ - return ret - - -################################################################################ - -if __name__ == "__main__": - import sys - - for txtname in sys.argv[1:]: - txtdir, txtbase = os.path.split(txtname) - version, structs = parse_file(txtname) - with open( - os.path.join(txtdir, "defs-" + txtbase.replace(".txt", ".h")), "w" - ) as fh: - fh.write(gen_h(txtname, "p9_", structs)) - with open( - os.path.join(txtdir, "defs-" + txtbase.replace(".txt", ".c")), "w" - ) as fh: - fh.write(gen_c(txtname, "p9_", structs)) diff --git a/lib9p/defs.h b/lib9p/defs.h deleted file mode 100644 index 907cdde..0000000 --- a/lib9p/defs.h +++ /dev/null @@ -1,74 +0,0 @@ -/* 9p/defs.h - TODO - * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> - * SPDX-Licence-Identifier: AGPL-3.0-or-later - */ - -#ifndef _9P_DEFS_H_ -#define _9P_DEFS_H_ - -#include <stdint.h> - -#define P9_NOTAG ((uint16_t)~0U) -#define P9_NOFID ((uint32_t)~0U) - -enum p9_version { - P9_VER_UNINITIALIZED, - /* P9_VER_9P1, */ - P9_VER_9P2000, - /*P9_VER_9P2000_u,*/ - /*P9_VER_9P2000_L,*/ - /*P9_VER_9P2000_e,*/ - _P9_VER_CNT, -}; - -struct p9_ctx; - -enum p9_version p9_ctx_version(p9_ctx *); - -/** Write an static error into ctx, return -1. */ -int p9_error(struct p9_ctx *ctx, uint32_t linux_errno, char const *msg); -/** Write a printf-style error into ctx, return -1. */ -int p9_errorf(struct p9_ctx *ctx, uint32_t linux_errno, char const *fmt, ...); - -/** - * Return how much space the message at net_bytes will take when - * unmarshaled. This number may be larger than net_bytes due to (1) - * struct padding, (2) nul-terminator byes for strings. - * - * Emits an error (return -1, set ctx->err_num and ctx->err_msg) if - * either the message type is unknown or if net_bytes is too short for - * that message type. - * - * @param net_bytes : the complete request, starting with the "size[4]" - * @return required size, or -1 on error - */ -size_t p9_unmarshal_size(struct p9_ctx *ctx, uint8_t *net_bytes); - -/** - * Unmarshal the 9P message `net_bytes` into the C struct `out_body`. - * - * Emits an error (return 0, set ctx->err_num and ctx->err_msg) if a - * string contains invalid UTF-8 or a nul-byte. - * - * @param net_bytes : the complete message, starting with the "size[4]" - * @param out_tag : the message-ID tag - * @param out_body : the message body, must be at least p9_unmarshal_size() bytes - * @return the message type, or -1 on error - */ -uint8_t p9_unmarshal(struct p9_ctx *ctx, uint8_t *net_bytes, uint16_t *out_tag, void *out_body); - -/** - * Marshal a `struct p9_msg_{type}` structure into a byte-array. - * - * @param struct p9_ctx *ctx : a request context - * @param uint16_t msgid : the message-ID tag - * @param struct p9_msg_{type} msg : the message to encode - * - * @param uint8_t *out_bytes : the buffer to encode to, must be at be at least ctx->max_msg_size bytes - * @return uint32_t : the encoded length, or -1 on error - */ -#define p9_marshal(ctx, msgid, msg, out_bytes) _p9_marshal(ctx, P9_TYPECODE_FOR_CTYPE(msg), msgid, &(msg), out_bytes) -uint32_t _p9_marshal(struct p9_ctx *ctx, uint8_t typ, uint16_t msgid, void *body, uint8_t *out_bytes); - -#endif /* _9P_DEFS_H_ */ diff --git a/lib9p/include/lib9p/9p.h b/lib9p/include/lib9p/9p.h new file mode 100644 index 0000000..a55f08f --- /dev/null +++ b/lib9p/include/lib9p/9p.h @@ -0,0 +1,72 @@ +/* lib9p/9p.h - Base 9P protocol definitions for both clients and servers + * + * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-Licence-Identifier: AGPL-3.0-or-later + */ + +#ifndef _LIB9P_9P_H_ +#define _LIB9P_9P_H_ + +#include <lib9p/linux-errno.h> +#include <lib9p/_types.h> + +#define LIB9P_NOTAG ((uint16_t)~0U) +#define LIB9P_NOFID ((uint32_t)~0U) + +struct lib9p_ctx; +enum lib9p_version lib9p_ctx_version(lib9p_ctx *); +uint32_t lib9p_ctx_max_msg_size(lib9p_ctx *); + +/** Write an static error into ctx, return -1. */ +int lib9p_error(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *msg); +/** Write a printf-style error into ctx, return -1. */ +int lib9p_errorf(struct lib9p_ctx *ctx, uint32_t linux_errno, char const *fmt, ...); + +/** + * Return how much space the message at net_bytes will take when + * unmarshaled. This number may be larger than net_bytes due to (1) + * struct padding, (2) nul-terminator byes for strings. + * + * Emits an error (return -1, set ctx->err_num and ctx->err_msg) if + * either the message type is unknown, or if net_bytes is too short + * for that message type, or if an invalid string (invalid UTF-8, + * contains a nul-byte) is encountered. + * + * @param net_bytes : the complete request, starting with the "size[4]" + * + * @return required size, or -1 on error + */ +ssize_t lib9p_unmarshal_size(struct lib9p_ctx *ctx, uint8_t *net_bytes); + +/** + * Unmarshal the 9P message `net_bytes` into the C struct `ret_body`. + * + * Emits an error (return 0, set ctx->err_num and ctx->err_msg) if a + * string contains invalid UTF-8 or a nul-byte. + * + * @param ctx : negotiated protocol parameters, where to record errors + * @param net_bytes : the complete message, starting with the "size[4]" + * + * @return ret_typ : the mesage type + * @return ret_tag : the message-ID tag + * @return ret_body : the message body, must be at least lib9p_unmarshal_size() bytes + * @return the message type, or -1 on error + */ +bool lib9p_unmarshal(struct lib9p_ctx *ctx, uint8_t *net_bytes, + enum lib9p_msg_typ *ret_typ, uint16_t *ret_tag, void *ret_body); + +/** + * Marshal a `struct lib9p_msg_{typ}` structure into a byte-array. + * + * @param ctx : negotiated protocol parameters, where to record errors + * @param typ : the message type + * @param tag : the message-ID tag + * @param msg : the message to encode + * + * @return ret_bytes : the buffer to encode to, must be at be at least lib9p_ctx_max_msg_size(ctx) bytes + * @return whether there was an error (false=success, true=error) + */ +bool lib9p_marshal(struct lib9p_ctx *ctx, uint8_t typ, uint16_t tag, void *body, + uint8_t *ret_bytes); + +#endif _LIB9P_9P_H_ diff --git a/lib9p/include/lib9p/_types.h b/lib9p/include/lib9p/_types.h new file mode 100644 index 0000000..348945d --- /dev/null +++ b/lib9p/include/lib9p/_types.h @@ -0,0 +1,285 @@ +/* Generated by `./types.gen 9P2000.txt 9P2000.u.txt 9P2000.e.txt`. DO NOT EDIT! */ + +#ifndef _LIB9P__TYPES_H_ +#define _LIB9P__TYPES_H_ + +#include <stdint.h> + +/* versions *******************************************************************/ + +enum lib9p_version { + LIB9P_VER_UNINITIALIZED = 0, + LIB9P_VER_9P2000, /* "9P2000" */ + LIB9P_VER_9P2000_e, /* "9P2000.e" */ + LIB9P_VER_9P2000_u, /* "9P2000.u" */ + LIB9P_VER_NUM, +}; + +/* non-message structs ********************************************************/ + +struct lib9p_d { + uint32_t len; + uint8_t *dat; +}; + +struct lib9p_s { + uint16_t len; + uint8_t *utf8; +}; + +struct lib9p_qid { + uint8_t type; + uint32_t vers; + uint64_t path; +}; + +struct lib9p_stat { + uint16_t stat_size; + uint16_t kern_type; + uint32_t kern_dev; + struct lib9p_qid file_qid; + uint32_t file_mode; + uint32_t file_atime; + uint32_t file_mtime; + uint64_t file_size; + struct lib9p_s file_name; + struct lib9p_s file_owner_uid; + struct lib9p_s file_owner_gid; + struct lib9p_s file_last_modified_uid; + struct lib9p_s file_extension; /* 9P2000.u */ + uint32_t file_owner_n_uid; /* 9P2000.u */ + uint32_t file_owner_n_gid; /* 9P2000.u */ + uint32_t file_last_modified_n_uid; /* 9P2000.u */ +}; + +/* messages *******************************************************************/ + +enum lib9p_msg_type { /* uint8_t */ + LIB9P_TYP_Tversion = 100, + LIB9P_TYP_Rversion = 101, + LIB9P_TYP_Tauth = 102, + LIB9P_TYP_Rauth = 103, + LIB9P_TYP_Tattach = 104, + LIB9P_TYP_Rattach = 105, + LIB9P_TYP_Rerror = 107, + LIB9P_TYP_Tflush = 108, + LIB9P_TYP_Rflush = 109, + LIB9P_TYP_Twalk = 110, + LIB9P_TYP_Rwalk = 111, + LIB9P_TYP_Topen = 112, + LIB9P_TYP_Ropen = 113, + LIB9P_TYP_Tcreate = 114, + LIB9P_TYP_Rcreate = 115, + LIB9P_TYP_Tread = 116, + LIB9P_TYP_Rread = 117, + LIB9P_TYP_Twrite = 118, + LIB9P_TYP_Rwrite = 119, + LIB9P_TYP_Tclunk = 120, + LIB9P_TYP_Rclunk = 121, + LIB9P_TYP_Tremove = 122, + LIB9P_TYP_Rremove = 123, + LIB9P_TYP_Tstat = 124, + LIB9P_TYP_Rstat = 125, + LIB9P_TYP_Twstat = 126, + LIB9P_TYP_Rwstat = 127, + LIB9P_TYP_Tsession = 150, /* 9P2000.e */ + LIB9P_TYP_Rsession = 151, /* 9P2000.e */ + LIB9P_TYP_Tsread = 152, /* 9P2000.e */ + LIB9P_TYP_Rsread = 153, /* 9P2000.e */ + LIB9P_TYP_Tswrite = 154, /* 9P2000.e */ + LIB9P_TYP_Rswrite = 155, /* 9P2000.e */ +}; + +#define LIB9P_TYPECODE_FOR_CTYPE(msg) _Generic((msg), \ + struct lib9p_msg_Tversion: LIB9P_TYP_Tversion, \ + struct lib9p_msg_Rversion: LIB9P_TYP_Rversion, \ + struct lib9p_msg_Tauth: LIB9P_TYP_Tauth, \ + struct lib9p_msg_Rauth: LIB9P_TYP_Rauth, \ + struct lib9p_msg_Tattach: LIB9P_TYP_Tattach, \ + struct lib9p_msg_Rattach: LIB9P_TYP_Rattach, \ + struct lib9p_msg_Rerror: LIB9P_TYP_Rerror, \ + struct lib9p_msg_Tflush: LIB9P_TYP_Tflush, \ + struct lib9p_msg_Rflush: LIB9P_TYP_Rflush, \ + struct lib9p_msg_Twalk: LIB9P_TYP_Twalk, \ + struct lib9p_msg_Rwalk: LIB9P_TYP_Rwalk, \ + struct lib9p_msg_Topen: LIB9P_TYP_Topen, \ + struct lib9p_msg_Ropen: LIB9P_TYP_Ropen, \ + struct lib9p_msg_Tcreate: LIB9P_TYP_Tcreate, \ + struct lib9p_msg_Rcreate: LIB9P_TYP_Rcreate, \ + struct lib9p_msg_Tread: LIB9P_TYP_Tread, \ + struct lib9p_msg_Rread: LIB9P_TYP_Rread, \ + struct lib9p_msg_Twrite: LIB9P_TYP_Twrite, \ + struct lib9p_msg_Rwrite: LIB9P_TYP_Rwrite, \ + struct lib9p_msg_Tclunk: LIB9P_TYP_Tclunk, \ + struct lib9p_msg_Rclunk: LIB9P_TYP_Rclunk, \ + struct lib9p_msg_Tremove: LIB9P_TYP_Tremove, \ + struct lib9p_msg_Rremove: LIB9P_TYP_Rremove, \ + struct lib9p_msg_Tstat: LIB9P_TYP_Tstat, \ + struct lib9p_msg_Rstat: LIB9P_TYP_Rstat, \ + struct lib9p_msg_Twstat: LIB9P_TYP_Twstat, \ + struct lib9p_msg_Rwstat: LIB9P_TYP_Rwstat, \ + struct lib9p_msg_Tsession: LIB9P_TYP_Tsession, \ + struct lib9p_msg_Rsession: LIB9P_TYP_Rsession, \ + struct lib9p_msg_Tsread: LIB9P_TYP_Tsread, \ + struct lib9p_msg_Rsread: LIB9P_TYP_Rsread, \ + struct lib9p_msg_Tswrite: LIB9P_TYP_Tswrite, \ + struct lib9p_msg_Rswrite: LIB9P_TYP_Rswrite) + +struct lib9p_msg_Tversion { + uint32_t max_msg_size; + struct lib9p_s version; +}; + +struct lib9p_msg_Rversion { + uint32_t max_msg_size; + struct lib9p_s version; +}; + +struct lib9p_msg_Tauth { + uint32_t afid; + struct lib9p_s uname; + struct lib9p_s aname; + uint32_t n_uname; /* 9P2000.u */ +}; + +struct lib9p_msg_Rauth { + struct lib9p_qid aqid; +}; + +struct lib9p_msg_Tattach { + uint32_t fid; + uint32_t afid; + struct lib9p_s uname; + struct lib9p_s aname; +}; + +struct lib9p_msg_Rattach { + struct lib9p_qid qid; +}; + +struct lib9p_msg_Rerror { + struct lib9p_s ename; + uint32_t errno; /* 9P2000.u */ +}; + +struct lib9p_msg_Tflush { + uint16_t oldtag; +}; + +struct lib9p_msg_Rflush {}; + +struct lib9p_msg_Twalk { + uint32_t fid; + uint32_t newfid; + uint16_t nwname; + struct lib9p_s *wname; +}; + +struct lib9p_msg_Rwalk { + uint16_t nwqid; + struct lib9p_qid *wqid; +}; + +struct lib9p_msg_Topen { + uint32_t fid; + uint8_t mode; +}; + +struct lib9p_msg_Ropen { + struct lib9p_qid qid; + uint32_t iounit; +}; + +struct lib9p_msg_Tcreate { + uint32_t fid; + struct lib9p_s name; + uint32_t perm; + uint8_t mode; +}; + +struct lib9p_msg_Rcreate { + struct lib9p_qid qid; + uint32_t iounit; +}; + +struct lib9p_msg_Tread { + uint32_t fid; + uint64_t offset; + uint32_t count; +}; + +struct lib9p_msg_Rread { + struct lib9p_d data; +}; + +struct lib9p_msg_Twrite { + uint32_t fid; + uint64_t offset; + struct lib9p_d data; +}; + +struct lib9p_msg_Rwrite { + uint32_t count; +}; + +struct lib9p_msg_Tclunk { + uint32_t fid; +}; + +struct lib9p_msg_Rclunk {}; + +struct lib9p_msg_Tremove { + uint32_t fid; +}; + +struct lib9p_msg_Rremove {}; + +struct lib9p_msg_Tstat { + uint32_t fid; +}; + +struct lib9p_msg_Rstat { + struct lib9p_stat stat; +}; + +struct lib9p_msg_Twstat { + uint32_t fid; + struct lib9p_stat stat; +}; + +struct lib9p_msg_Rwstat {}; + +/* 9P2000.e */ +struct lib9p_msg_Tsession { + uint64_t key; +}; + +/* 9P2000.e */ +struct lib9p_msg_Rsession {}; + +/* 9P2000.e */ +struct lib9p_msg_Tsread { + uint32_t fid; + uint16_t nwname; + struct lib9p_s *wname; +}; + +/* 9P2000.e */ +struct lib9p_msg_Rsread { + struct lib9p_d data; +}; + +/* 9P2000.e */ +struct lib9p_msg_Tswrite { + uint32_t fid; + uint16_t nwname; + struct lib9p_s *wname; + struct lib9p_d data; +}; + +/* 9P2000.e */ +struct lib9p_msg_Rswrite { + uint32_t count; +}; + +#endif /* _LIB9P__TYPES_H_ */ diff --git a/lib9p/linux-errno.h.gen b/lib9p/include/lib9p/linux-errno.h.gen index b896384..b896384 100755 --- a/lib9p/linux-errno.h.gen +++ b/lib9p/include/lib9p/linux-errno.h.gen diff --git a/lib9p/include/lib9p/srv.h b/lib9p/include/lib9p/srv.h new file mode 100644 index 0000000..3b8b21e --- /dev/null +++ b/lib9p/include/lib9p/srv.h @@ -0,0 +1,16 @@ +#ifndef _LIB9P_SRV_H_ +#define _LIB9P_SRV_H_ + +#include <libcr/coroutine.h> + +struct lib9p_srvreq; + +struct lib9p_srv { + int sockfd; + cr_chan_t(lib9p_srvreq *) reqch; +}; + +COROUTINE lib9p_srv_read_cr(void *_srv); +COROUTINE lib9p_srv_write_cr(void *_srv); + +#endif /* _LIB9P_SRV_H_ */ diff --git a/lib9p/internal.h b/lib9p/internal.h index 61977d4..ebdc3f3 100644 --- a/lib9p/internal.h +++ b/lib9p/internal.h @@ -1,21 +1,20 @@ -/* 9p/internal.h - TODO +/* lib9p/internal.h - TODO * * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-Licence-Identifier: AGPL-3.0-or-later */ -#ifndef _9P_INTERNAL_H_ -#define _9P_INTERNAL_H_ +#ifndef _LIB9P_INTERNAL_H_ +#define _LIB9P_INTERNAL_H_ #include <assert.h> -#include <stdint.h> #include <stdbool.h> -#include "9p/defs.h" +#include <lib9p/9p.h> -#define USE_CONFIG_9P +#define USE_CONFIG_LIB9P #include "config.h" -static_assert(CONFIG_9P_MAX_ERR_SIZE <= UINT16_MAX); +static_assert(CONFIG_LIB9P_MAX_ERR_SIZE <= UINT16_MAX); /* C language *****************************************************************/ @@ -23,39 +22,65 @@ static_assert(CONFIG_9P_MAX_ERR_SIZE <= UINT16_MAX); /* types **********************************************************************/ -struct p9_ctx { - enum p9_version version; - uint32_t max_msg_size; - uint32_t Rerror_overhead; +/* NB: We declare this here instead of in the public <lib9p/9p.h> + * because we don't want to include "config.h" from public headers, + * and I want the MAX_ERR_SIZE to be configurable. */ +struct lib9p_ctx { + /* negotiated */ + enum lib9p_version version; + uint32_t max_msg_size; + /* negotiated (server) */ + uint32_t Rerror_overhead; + + /* state */ + uint32_t err_num; + char err_msg[CONFIG_LIB9P_MAX_ERR_SIZE]; +}; + +/* vtables ********************************************************************/ - uint32_t err_num; - char err_msg[CONFIG_9P_MAX_ERR_SIZE]; +struct _checksize_ctx { + struct lib9p_ctx *ctx; + uint32_t net_size; + uint8_t net_bytes; + + uint32_t net_offset; + /* Increment `host_extra` to pre-allocate space that is + * "extra" beyond sizeof(). */ + size_t host_extra; }; -static inline enum p9_version p9_ctx_version(p9_ctx *ctx) { - assert(ctx); - return ctx->version; -} +struct _unmarshal_ctx { + struct lib9p_ctx *ctx; -/* vtables ********************************************************************/ + uint32_t net_offset; + /* `extra` points to the beginning of unallocated space. */ + void *extra; +}; + +struct _marshal_ctx { + struct lib9p_ctx *ctx; + + uint8_t *net_bytes; + uint32_t net_offset; +}; -typedef bool (*_checksize_fn_t)(uint32_t net_len, uint8_t *net_bytes, uint32_t *mut_net_offset, size_t *mut_host_extra); -typedef bool (*_unmarshal_fn_t)(uint8_t *net_bytes, uint32_t *mut_net_offset, void **mut_host_extra, void *out); -typedef bool (*_marshal_fn_t)(struct p9_ctx *ctx, void *val, uint8_t *out_net_bytes, uint32_t *mut_net_offset); +typedef bool (*_checksize_fn_t)(struct _checksize_ctx *ctx); +typedef void (*_unmarshal_fn_t)(struct _unmarshal_ctx *ctx, void *out); +typedef bool (*_marshal_fn_t)(struct _marshal_ctx *ctx, void *host_val); -struct msg_vtable { +struct _vtable_msg { size_t unmarshal_basesize; _checksize_fn_t unmarshal_extrasize; _unmarshal_fn_t unmarshal; _marshal_fn_t marshal; }; -struct version { - struct msg_vtable msgs[0xFF]; +struct _vtable_version { + struct _vtable_msg msgs[0xFF]; }; -extern struct version version_9P2000; -/*extern struct version version_9P2000u; */ +extern struct _vtable_version _lib9p_vtables[LIB9P_VER_NUM]; /* unmarshal utilities ********************************************************/ @@ -136,4 +161,4 @@ static inline void encode_u64le(uint64_t in, uint8_t *out) { out[7] = (uint8_t)((in >> 56) & 0xFF); } -#endif /* _9P_INTERNAL_H_ */ +#endif /* _LIB9P_INTERNAL_H_ */ diff --git a/lib9p/misc.txt b/lib9p/misc.txt deleted file mode 100644 index 93aa304..0000000 --- a/lib9p/misc.txt +++ /dev/null @@ -1,24 +0,0 @@ -# qid.types -QTDIR = 1<<7 -QTAPPEND = 1<<6 -QTEXCL = 1<<5 -QTMOUNT = 1<<4 # been around forever, but undocumented? -QTAUTH = 1<<3 -QTTMP = 1<<2 # added to Plan 9 2003-12 -QTSYMLINK = 1<<1 # .u -QTFILE = 1<<0 - -DMDIR = 1<<31 -DMAPPEND = 1<<30 -DMEXCL = 1<<29 -DMMOUNT = 1<<28 -DMAUTH = 1<<27 -DMTMP = 1<<26 -# = 1<<25 -# = 1<<24 -DMDEVICE = 1<<23 # .u -# = 1<<22 -DMNAMEDPIPE = 1<<21 # .u -DMSOCKET = 1<<20 # .u -DMSETUID = 1<<19 # .u -DMSETGID = 1<<18 # .u diff --git a/lib9p/srv.h b/lib9p/srv.h deleted file mode 100644 index e3623ed..0000000 --- a/lib9p/srv.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _NET9P_H_ -#define _NET9P_H_ - -#include "coroutine.h" - -struct p9_srvreq; - -struct p9_srv { - int sockfd; - cr_chan_t(p9_srvreq *) reqch; -}; - -COROUTINE p9_srv_read_cr(void *_srv); -COROUTINE p9_srv_write_cr(void *_srv); - -#endif /* _NET9P_H_ */ diff --git a/lib9p/types.c b/lib9p/types.c new file mode 100644 index 0000000..73ac28e --- /dev/null +++ b/lib9p/types.c @@ -0,0 +1,1331 @@ +/* Generated by `./types.gen 9P2000.txt 9P2000.u.txt 9P2000.e.txt`. DO NOT EDIT! */ + +#include <stdbool.h> + +#include <lib9p/9p.h> + +#include "internal.h" + +/* checksize_* (internals of unmarshal_size()) ********************************/ + +static inline bool _checksize_net(struct _checksize_ctx *ctx, uint32_t n) { + if (__builtin_add_overflow(ctx->net_offset, n, &ctx->net_offset)) + /* If needed-net-size overflowed uint32_t, then + * there's no way that actual-net-size will live up to + * that. */ + return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content"); + if (ctx->net_offset > ctx->net_size) + return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content"); + return false; +} + +static inline bool _checksize_host(struct _checksize_ctx *ctx, size_t n) { + if (__builtin_add_overflow(ctx->host_extra, n, &ctx->host_extra)) + /* If needed-host-size overflowed size_t, then there's + * no way that actual-net-size will live up to + * that. */ + return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content"); + return false; +} + +static inline bool _checksize_list(struct _checksize_ctx *ctx, + size_t cnt, _checksize_fn_t item_fn, size_t item_host_size) { + for (size_t i = 0; i < cnt; i++) + if (_checksize_host(ctx, item_host_size) || item_fn(ctx)) + return true; + return false; +} + +#define checksize_1(ctx) _checksize_net(ctx, 1) +#define checksize_2(ctx) _checksize_net(ctx, 2) +#define checksize_4(ctx) _checksize_net(ctx, 4) +#define checksize_8(ctx) _checksize_net(ctx, 8) + +static inline bool checksize_d(struct _checksize_ctx *ctx) { + uint32_t base_offset = ctx->net_offset; + if (_checksize_4(ctx)) + return true; + uint32_t len = decode_u32le(&ctx->net_bytes[base_offset]); + return checksize_net(ctx, len) || checksize_host(ctx, len); +} + +static inline bool checksize_s(struct _checksize_ctx *ctx) { + uint32_t base_offset = ctx->net_offset; + if (_checksize_2(ctx)) + return true; + uint16_t len = decode_u16le(&ctx->net_bytes[base_offset]); + if (checksize_net(ctx, len) || checksize_host(ctx, ((size_t)len)+1)) + return true; + if (!is_valid_utf8_without_nul(&ctx->net_bytes[base_offset+2], len)) + return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message contains invalid UTF-8"); + return false; +} + +static inline bool checksize_qid(struct _checksize_ctx *ctx) { + return checksize_1(ctx) + || checksize_4(ctx) + || checksize_8(ctx); +} + +static inline bool checksize_stat(struct _checksize_ctx *ctx) { + return checksize_2(ctx) + || checksize_2(ctx) + || checksize_4(ctx) + || checksize_qid(ctx) + || checksize_4(ctx) + || checksize_4(ctx) + || checksize_4(ctx) + || checksize_8(ctx) + || checksize_s(ctx) + || checksize_s(ctx) + || checksize_s(ctx) + || checksize_s(ctx) + || ( ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) && checksize_s(ctx) ) + || ( ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) && checksize_4(ctx) ) + || ( ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) && checksize_4(ctx) ) + || ( ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) && checksize_4(ctx) ); +} + +static bool checksize_Tversion(struct _checksize_ctx *ctx) { + return checksize_4(ctx) + || checksize_s(ctx); +} + +static bool checksize_Rversion(struct _checksize_ctx *ctx) { + return checksize_4(ctx) + || checksize_s(ctx); +} + +static bool checksize_Tauth(struct _checksize_ctx *ctx) { + return checksize_4(ctx) + || checksize_s(ctx) + || checksize_s(ctx) + || ( ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) && checksize_4(ctx) ); +} + +static bool checksize_Rauth(struct _checksize_ctx *ctx) { + return checksize_qid(ctx); +} + +static bool checksize_Tattach(struct _checksize_ctx *ctx) { + return checksize_4(ctx) + || checksize_4(ctx) + || checksize_s(ctx) + || checksize_s(ctx); +} + +static bool checksize_Rattach(struct _checksize_ctx *ctx) { + return checksize_qid(ctx); +} + +static bool checksize_Rerror(struct _checksize_ctx *ctx) { + return checksize_s(ctx) + || ( ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) && checksize_4(ctx) ); +} + +static bool checksize_Tflush(struct _checksize_ctx *ctx) { + return checksize_2(ctx); +} + +static bool checksize_Rflush(struct _checksize_ctx *UNUSED(ctx)) { + return false; +} + +static bool checksize_Twalk(struct _checksize_ctx *ctx) { + return checksize_4(ctx) + || checksize_4(ctx) + || checksize_2(ctx) + || _checksize_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), checksize_s, sizeof(struct lib9p_s)); +} + +static bool checksize_Rwalk(struct _checksize_ctx *ctx) { + return checksize_2(ctx) + || _checksize_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), checksize_qid, sizeof(struct lib9p_qid)); +} + +static bool checksize_Topen(struct _checksize_ctx *ctx) { + return checksize_4(ctx) + || checksize_1(ctx); +} + +static bool checksize_Ropen(struct _checksize_ctx *ctx) { + return checksize_qid(ctx) + || checksize_4(ctx); +} + +static bool checksize_Tcreate(struct _checksize_ctx *ctx) { + return checksize_4(ctx) + || checksize_s(ctx) + || checksize_4(ctx) + || checksize_1(ctx); +} + +static bool checksize_Rcreate(struct _checksize_ctx *ctx) { + return checksize_qid(ctx) + || checksize_4(ctx); +} + +static bool checksize_Tread(struct _checksize_ctx *ctx) { + return checksize_4(ctx) + || checksize_8(ctx) + || checksize_4(ctx); +} + +static bool checksize_Rread(struct _checksize_ctx *ctx) { + return checksize_d(ctx); +} + +static bool checksize_Twrite(struct _checksize_ctx *ctx) { + return checksize_4(ctx) + || checksize_8(ctx) + || checksize_d(ctx); +} + +static bool checksize_Rwrite(struct _checksize_ctx *ctx) { + return checksize_4(ctx); +} + +static bool checksize_Tclunk(struct _checksize_ctx *ctx) { + return checksize_4(ctx); +} + +static bool checksize_Rclunk(struct _checksize_ctx *UNUSED(ctx)) { + return false; +} + +static bool checksize_Tremove(struct _checksize_ctx *ctx) { + return checksize_4(ctx); +} + +static bool checksize_Rremove(struct _checksize_ctx *UNUSED(ctx)) { + return false; +} + +static bool checksize_Tstat(struct _checksize_ctx *ctx) { + return checksize_4(ctx); +} + +static bool checksize_Rstat(struct _checksize_ctx *ctx) { + return checksize_stat(ctx); +} + +static bool checksize_Twstat(struct _checksize_ctx *ctx) { + return checksize_4(ctx) + || checksize_stat(ctx); +} + +static bool checksize_Rwstat(struct _checksize_ctx *UNUSED(ctx)) { + return false; +} + +static bool checksize_Tsession(struct _checksize_ctx *ctx) { + return checksize_8(ctx); +} + +static bool checksize_Rsession(struct _checksize_ctx *UNUSED(ctx)) { + return false; +} + +static bool checksize_Tsread(struct _checksize_ctx *ctx) { + return checksize_4(ctx) + || checksize_2(ctx) + || _checksize_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), checksize_s, sizeof(struct lib9p_s)); +} + +static bool checksize_Rsread(struct _checksize_ctx *ctx) { + return checksize_d(ctx); +} + +static bool checksize_Tswrite(struct _checksize_ctx *ctx) { + return checksize_4(ctx) + || checksize_2(ctx) + || _checksize_list(ctx, decode_u16le(&ctx->net_bytes[ctx->net_offset-2]), checksize_s, sizeof(struct lib9p_s)) + || checksize_d(ctx); +} + +static bool checksize_Rswrite(struct _checksize_ctx *ctx) { + return checksize_4(ctx); +} + +/* unmarshal_* ****************************************************************/ + +static inline vold unmarshal_1(struct _unmarshal_ctx *ctx, uint8_t *out) { + *out = decode_u8le(&ctx->net_bytes[ctx->net_offset]); + ctx->net_offset += 1; +} + +static inline vold unmarshal_2(struct _unmarshal_ctx *ctx, uint16_t *out) { + *out = decode_u16le(&ctx->net_bytes[ctx->net_offset]); + ctx->net_offset += 2; +} + +static inline vold unmarshal_4(struct _unmarshal_ctx *ctx, uint32_t *out) { + *out = decode_u32le(&ctx->net_bytes[ctx->net_offset]); + ctx->net_offset += 4; +} + +static inline vold unmarshal_8(struct _unmarshal_ctx *ctx, uint64_t *out) { + *out = decode_u64le(&ctx->net_bytes[ctx->net_offset]); + ctx->net_offset += 8; +} + +static inline void unmarshal_d(struct _unmarshal_ctx *ctx, struct lib9p_d *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->len); + out->dat = ctx->host_extra; + ctx->host_extra += sizeof(out->dat[0]) * out->len; + for (typeof(out->len) i = 0; i < out->len; i++) + unmarshal_1(ctx, &out->dat[i]); +} + +static inline void unmarshal_s(struct _unmarshal_ctx *ctx, struct lib9p_s *out) { + memset(out, 0, sizeof(*out)); + unmarshal_2(ctx, &out->len); + out->utf8 = ctx->host_extra; + ctx->host_extra += sizeof(out->utf8[0]) * out->len; + for (typeof(out->len) i = 0; i < out->len; i++) + unmarshal_1(ctx, &out->utf8[i]); +} + +static inline void unmarshal_qid(struct _unmarshal_ctx *ctx, struct lib9p_qid *out) { + memset(out, 0, sizeof(*out)); + unmarshal_1(ctx, &out->type); + unmarshal_4(ctx, &out->vers); + unmarshal_8(ctx, &out->path); +} + +static inline void unmarshal_stat(struct _unmarshal_ctx *ctx, struct lib9p_stat *out) { + memset(out, 0, sizeof(*out)); + unmarshal_2(ctx, &out->stat_size); + unmarshal_2(ctx, &out->kern_type); + unmarshal_4(ctx, &out->kern_dev); + unmarshal_qid(ctx, &out->file_qid); + unmarshal_4(ctx, &out->file_mode); + unmarshal_4(ctx, &out->file_atime); + unmarshal_4(ctx, &out->file_mtime); + unmarshal_8(ctx, &out->file_size); + unmarshal_s(ctx, &out->file_name); + unmarshal_s(ctx, &out->file_owner_uid); + unmarshal_s(ctx, &out->file_owner_gid); + unmarshal_s(ctx, &out->file_last_modified_uid); + if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_s(ctx, &out->file_extension); + if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->file_owner_n_uid); + if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->file_owner_n_gid); + if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->file_last_modified_n_uid); +} + +static void unmarshal_Tversion(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tversion *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->max_msg_size); + unmarshal_s(ctx, &out->version); +} + +static void unmarshal_Rversion(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rversion *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->max_msg_size); + unmarshal_s(ctx, &out->version); +} + +static void unmarshal_Tauth(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tauth *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->afid); + unmarshal_s(ctx, &out->uname); + unmarshal_s(ctx, &out->aname); + if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->n_uname); +} + +static void unmarshal_Rauth(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rauth *out) { + memset(out, 0, sizeof(*out)); + unmarshal_qid(ctx, &out->aqid); +} + +static void unmarshal_Tattach(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tattach *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->fid); + unmarshal_4(ctx, &out->afid); + unmarshal_s(ctx, &out->uname); + unmarshal_s(ctx, &out->aname); +} + +static void unmarshal_Rattach(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rattach *out) { + memset(out, 0, sizeof(*out)); + unmarshal_qid(ctx, &out->qid); +} + +static void unmarshal_Rerror(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rerror *out) { + memset(out, 0, sizeof(*out)); + unmarshal_s(ctx, &out->ename); + if ( (ctx->ctx->version==LIB9P_VER_9P2000_u) ) unmarshal_4(ctx, &out->errno); +} + +static void unmarshal_Tflush(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tflush *out) { + memset(out, 0, sizeof(*out)); + unmarshal_2(ctx, &out->oldtag); +} + +static void unmarshal_Rflush(struct _unmarshal_ctx *UNUSED(ctx), struct lib9p_msg_Rflush *UNUSED(out)) { + memset(out, 0, sizeof(*out)); +} + +static void unmarshal_Twalk(struct _unmarshal_ctx *ctx, struct lib9p_msg_Twalk *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->fid); + unmarshal_4(ctx, &out->newfid); + unmarshal_2(ctx, &out->nwname); + out->wname = ctx->host_extra; + ctx->host_extra += sizeof(out->wname[0]) * out->nwname; + for (typeof(out->nwname) i = 0; i < out->nwname; i++) + unmarshal_s(ctx, &out->wname[i]); +} + +static void unmarshal_Rwalk(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rwalk *out) { + memset(out, 0, sizeof(*out)); + unmarshal_2(ctx, &out->nwqid); + out->wqid = ctx->host_extra; + ctx->host_extra += sizeof(out->wqid[0]) * out->nwqid; + for (typeof(out->nwqid) i = 0; i < out->nwqid; i++) + unmarshal_qid(ctx, &out->wqid[i]); +} + +static void unmarshal_Topen(struct _unmarshal_ctx *ctx, struct lib9p_msg_Topen *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->fid); + unmarshal_1(ctx, &out->mode); +} + +static void unmarshal_Ropen(struct _unmarshal_ctx *ctx, struct lib9p_msg_Ropen *out) { + memset(out, 0, sizeof(*out)); + unmarshal_qid(ctx, &out->qid); + unmarshal_4(ctx, &out->iounit); +} + +static void unmarshal_Tcreate(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tcreate *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->fid); + unmarshal_s(ctx, &out->name); + unmarshal_4(ctx, &out->perm); + unmarshal_1(ctx, &out->mode); +} + +static void unmarshal_Rcreate(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rcreate *out) { + memset(out, 0, sizeof(*out)); + unmarshal_qid(ctx, &out->qid); + unmarshal_4(ctx, &out->iounit); +} + +static void unmarshal_Tread(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tread *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->fid); + unmarshal_8(ctx, &out->offset); + unmarshal_4(ctx, &out->count); +} + +static void unmarshal_Rread(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rread *out) { + memset(out, 0, sizeof(*out)); + unmarshal_d(ctx, &out->data); +} + +static void unmarshal_Twrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Twrite *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->fid); + unmarshal_8(ctx, &out->offset); + unmarshal_d(ctx, &out->data); +} + +static void unmarshal_Rwrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rwrite *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->count); +} + +static void unmarshal_Tclunk(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tclunk *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->fid); +} + +static void unmarshal_Rclunk(struct _unmarshal_ctx *UNUSED(ctx), struct lib9p_msg_Rclunk *UNUSED(out)) { + memset(out, 0, sizeof(*out)); +} + +static void unmarshal_Tremove(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tremove *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->fid); +} + +static void unmarshal_Rremove(struct _unmarshal_ctx *UNUSED(ctx), struct lib9p_msg_Rremove *UNUSED(out)) { + memset(out, 0, sizeof(*out)); +} + +static void unmarshal_Tstat(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tstat *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->fid); +} + +static void unmarshal_Rstat(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rstat *out) { + memset(out, 0, sizeof(*out)); + unmarshal_stat(ctx, &out->stat); +} + +static void unmarshal_Twstat(struct _unmarshal_ctx *ctx, struct lib9p_msg_Twstat *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->fid); + unmarshal_stat(ctx, &out->stat); +} + +static void unmarshal_Rwstat(struct _unmarshal_ctx *UNUSED(ctx), struct lib9p_msg_Rwstat *UNUSED(out)) { + memset(out, 0, sizeof(*out)); +} + +static void unmarshal_Tsession(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tsession *out) { + memset(out, 0, sizeof(*out)); + unmarshal_8(ctx, &out->key); +} + +static void unmarshal_Rsession(struct _unmarshal_ctx *UNUSED(ctx), struct lib9p_msg_Rsession *UNUSED(out)) { + memset(out, 0, sizeof(*out)); +} + +static void unmarshal_Tsread(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tsread *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->fid); + unmarshal_2(ctx, &out->nwname); + out->wname = ctx->host_extra; + ctx->host_extra += sizeof(out->wname[0]) * out->nwname; + for (typeof(out->nwname) i = 0; i < out->nwname; i++) + unmarshal_s(ctx, &out->wname[i]); +} + +static void unmarshal_Rsread(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rsread *out) { + memset(out, 0, sizeof(*out)); + unmarshal_d(ctx, &out->data); +} + +static void unmarshal_Tswrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Tswrite *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->fid); + unmarshal_2(ctx, &out->nwname); + out->wname = ctx->host_extra; + ctx->host_extra += sizeof(out->wname[0]) * out->nwname; + for (typeof(out->nwname) i = 0; i < out->nwname; i++) + unmarshal_s(ctx, &out->wname[i]); + unmarshal_d(ctx, &out->data); +} + +static void unmarshal_Rswrite(struct _unmarshal_ctx *ctx, struct lib9p_msg_Rswrite *out) { + memset(out, 0, sizeof(*out)); + unmarshal_4(ctx, &out->count); +} + +/* marshal_* ******************************************************************/ + +static inline bool _marshal_too_large(struct _marshal_ctx *ctx) { + lib9p_errorf(ctx->ctx, "%s too large to marshal into %s limit (limit=%"PRIu32")", + (ctx->net_bytes[4] % 2 == 0) ? "T-message" : "R-message", + ctx->ctx->version ? "negotiated" : ((ctx->net_bytes[4] % 2 == 0) ? "client" : "server"), + ctx->ctx->max_msg_size)); + return true; +} + +static inline bool marshal_1(struct _marshal_ctx *ctx, uint8_t *val) { + if (ctx->net_offset + 1 > ctx->max_msg_size) + return _marshal_too_large(ctx); + out_net_bytes[ctx->net_offset] = *val; + ctx->net_offset += 1; + return false; +} + +static inline bool marshal_2(struct _marshal_ctx *ctx, uint16_t *val) { + if (ctx->net_offset + 2 > ctx->max_msg_size) + return _marshal_too_large(ctx); + encode_u16le(*val, &out_net_bytes[ctx->net_offset]); + ctx->net_offset += 2; + return false; +} + +static inline bool marshal_4(struct _marshal_ctx *ctx, uint32_t *val) { + if (ctx->net_offset + 4 > ctx->max_msg_size) + return true; + encode_u32le(*val, &out_net_bytes[ctx->net_offset]); + ctx->net_offset += 4; + return false; +} + +static inline bool marshal_8(struct _marshal_ctx *ctx, uint64_t *val) { + if (ctx->net_offset + 8 > ctx->max_msg_size) + return true; + encode_u64le(*val, &out_net_bytes[ctx->net_offset]); + ctx->net_offset += 8; + return false; +} + +static inline bool marshal_d(struct _marshal_ctx *ctx, struct lib9p_d *val) { + return marshal_4(ctx, &val->len) + || ({ + bool err = false; + for (typeof(val->len) i = 0; i < val->len && !err; i++) + err = marshal_1(ctx, &val->dat[i])); + err; + }); +} + +static inline bool marshal_s(struct _marshal_ctx *ctx, struct lib9p_s *val) { + return marshal_2(ctx, &val->len) + || ({ + bool err = false; + for (typeof(val->len) i = 0; i < val->len && !err; i++) + err = marshal_1(ctx, &val->utf8[i])); + err; + }); +} + +static inline bool marshal_qid(struct _marshal_ctx *ctx, struct lib9p_qid *val) { + return marshal_1(ctx, &val->type) + || marshal_4(ctx, &val->vers) + || marshal_8(ctx, &val->path); +} + +static inline bool marshal_stat(struct _marshal_ctx *ctx, struct lib9p_stat *val) { + return marshal_2(ctx, &val->stat_size) + || marshal_2(ctx, &val->kern_type) + || marshal_4(ctx, &val->kern_dev) + || marshal_qid(ctx, &val->file_qid) + || marshal_4(ctx, &val->file_mode) + || marshal_4(ctx, &val->file_atime) + || marshal_4(ctx, &val->file_mtime) + || marshal_8(ctx, &val->file_size) + || marshal_s(ctx, &val->file_name) + || marshal_s(ctx, &val->file_owner_uid) + || marshal_s(ctx, &val->file_owner_gid) + || marshal_s(ctx, &val->file_last_modified_uid) + || marshal_s(ctx, &val->file_extension) + || marshal_4(ctx, &val->file_owner_n_uid) + || marshal_4(ctx, &val->file_owner_n_gid) + || marshal_4(ctx, &val->file_last_modified_n_uid); +} + +static bool marshal_Tversion(struct _marshal_ctx *ctx, struct lib9p_msg_Tversion *val) { + return marshal_4(ctx, &val->max_msg_size) + || marshal_s(ctx, &val->version); +} + +static bool marshal_Rversion(struct _marshal_ctx *ctx, struct lib9p_msg_Rversion *val) { + return marshal_4(ctx, &val->max_msg_size) + || marshal_s(ctx, &val->version); +} + +static bool marshal_Tauth(struct _marshal_ctx *ctx, struct lib9p_msg_Tauth *val) { + return marshal_4(ctx, &val->afid) + || marshal_s(ctx, &val->uname) + || marshal_s(ctx, &val->aname) + || marshal_4(ctx, &val->n_uname); +} + +static bool marshal_Rauth(struct _marshal_ctx *ctx, struct lib9p_msg_Rauth *val) { + return marshal_qid(ctx, &val->aqid); +} + +static bool marshal_Tattach(struct _marshal_ctx *ctx, struct lib9p_msg_Tattach *val) { + return marshal_4(ctx, &val->fid) + || marshal_4(ctx, &val->afid) + || marshal_s(ctx, &val->uname) + || marshal_s(ctx, &val->aname); +} + +static bool marshal_Rattach(struct _marshal_ctx *ctx, struct lib9p_msg_Rattach *val) { + return marshal_qid(ctx, &val->qid); +} + +static bool marshal_Rerror(struct _marshal_ctx *ctx, struct lib9p_msg_Rerror *val) { + return marshal_s(ctx, &val->ename) + || marshal_4(ctx, &val->errno); +} + +static bool marshal_Tflush(struct _marshal_ctx *ctx, struct lib9p_msg_Tflush *val) { + return marshal_2(ctx, &val->oldtag); +} + +static bool marshal_Rflush(struct _marshal_ctx *UNUSED(ctx), struct lib9p_msg_Rflush *UNUSED(val)) { + return false; +} + +static bool marshal_Twalk(struct _marshal_ctx *ctx, struct lib9p_msg_Twalk *val) { + return marshal_4(ctx, &val->fid) + || marshal_4(ctx, &val->newfid) + || marshal_2(ctx, &val->nwname) + || ({ + bool err = false; + for (typeof(val->nwname) i = 0; i < val->nwname && !err; i++) + err = marshal_s(ctx, &val->wname[i])); + err; + }); +} + +static bool marshal_Rwalk(struct _marshal_ctx *ctx, struct lib9p_msg_Rwalk *val) { + return marshal_2(ctx, &val->nwqid) + || ({ + bool err = false; + for (typeof(val->nwqid) i = 0; i < val->nwqid && !err; i++) + err = marshal_qid(ctx, &val->wqid[i])); + err; + }); +} + +static bool marshal_Topen(struct _marshal_ctx *ctx, struct lib9p_msg_Topen *val) { + return marshal_4(ctx, &val->fid) + || marshal_1(ctx, &val->mode); +} + +static bool marshal_Ropen(struct _marshal_ctx *ctx, struct lib9p_msg_Ropen *val) { + return marshal_qid(ctx, &val->qid) + || marshal_4(ctx, &val->iounit); +} + +static bool marshal_Tcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Tcreate *val) { + return marshal_4(ctx, &val->fid) + || marshal_s(ctx, &val->name) + || marshal_4(ctx, &val->perm) + || marshal_1(ctx, &val->mode); +} + +static bool marshal_Rcreate(struct _marshal_ctx *ctx, struct lib9p_msg_Rcreate *val) { + return marshal_qid(ctx, &val->qid) + || marshal_4(ctx, &val->iounit); +} + +static bool marshal_Tread(struct _marshal_ctx *ctx, struct lib9p_msg_Tread *val) { + return marshal_4(ctx, &val->fid) + || marshal_8(ctx, &val->offset) + || marshal_4(ctx, &val->count); +} + +static bool marshal_Rread(struct _marshal_ctx *ctx, struct lib9p_msg_Rread *val) { + return marshal_d(ctx, &val->data); +} + +static bool marshal_Twrite(struct _marshal_ctx *ctx, struct lib9p_msg_Twrite *val) { + return marshal_4(ctx, &val->fid) + || marshal_8(ctx, &val->offset) + || marshal_d(ctx, &val->data); +} + +static bool marshal_Rwrite(struct _marshal_ctx *ctx, struct lib9p_msg_Rwrite *val) { + return marshal_4(ctx, &val->count); +} + +static bool marshal_Tclunk(struct _marshal_ctx *ctx, struct lib9p_msg_Tclunk *val) { + return marshal_4(ctx, &val->fid); +} + +static bool marshal_Rclunk(struct _marshal_ctx *UNUSED(ctx), struct lib9p_msg_Rclunk *UNUSED(val)) { + return false; +} + +static bool marshal_Tremove(struct _marshal_ctx *ctx, struct lib9p_msg_Tremove *val) { + return marshal_4(ctx, &val->fid); +} + +static bool marshal_Rremove(struct _marshal_ctx *UNUSED(ctx), struct lib9p_msg_Rremove *UNUSED(val)) { + return false; +} + +static bool marshal_Tstat(struct _marshal_ctx *ctx, struct lib9p_msg_Tstat *val) { + return marshal_4(ctx, &val->fid); +} + +static bool marshal_Rstat(struct _marshal_ctx *ctx, struct lib9p_msg_Rstat *val) { + return marshal_stat(ctx, &val->stat); +} + +static bool marshal_Twstat(struct _marshal_ctx *ctx, struct lib9p_msg_Twstat *val) { + return marshal_4(ctx, &val->fid) + || marshal_stat(ctx, &val->stat); +} + +static bool marshal_Rwstat(struct _marshal_ctx *UNUSED(ctx), struct lib9p_msg_Rwstat *UNUSED(val)) { + return false; +} + +static bool marshal_Tsession(struct _marshal_ctx *ctx, struct lib9p_msg_Tsession *val) { + return marshal_8(ctx, &val->key); +} + +static bool marshal_Rsession(struct _marshal_ctx *UNUSED(ctx), struct lib9p_msg_Rsession *UNUSED(val)) { + return false; +} + +static bool marshal_Tsread(struct _marshal_ctx *ctx, struct lib9p_msg_Tsread *val) { + return marshal_4(ctx, &val->fid) + || marshal_2(ctx, &val->nwname) + || ({ + bool err = false; + for (typeof(val->nwname) i = 0; i < val->nwname && !err; i++) + err = marshal_s(ctx, &val->wname[i])); + err; + }); +} + +static bool marshal_Rsread(struct _marshal_ctx *ctx, struct lib9p_msg_Rsread *val) { + return marshal_d(ctx, &val->data); +} + +static bool marshal_Tswrite(struct _marshal_ctx *ctx, struct lib9p_msg_Tswrite *val) { + return marshal_4(ctx, &val->fid) + || marshal_2(ctx, &val->nwname) + || ({ + bool err = false; + for (typeof(val->nwname) i = 0; i < val->nwname && !err; i++) + err = marshal_s(ctx, &val->wname[i])); + err; + }) + || marshal_d(ctx, &val->data); +} + +static bool marshal_Rswrite(struct _marshal_ctx *ctx, struct lib9p_msg_Rswrite *val) { + return marshal_4(ctx, &val->count); +} + +/* vtables ********************************************************************/ + +struct _vtable_version _lib9p_vtables[LIB9P_VER_NUM] = { + [LIB9P_VER_UNINITIALIZED] = { + [LIB9P_TYP_Tversion] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tversion), + r.unmarshal_extrasize = checksize_Tversion, + r.unmarshal = unmarshal_Tversion, + r.marshal = (_marshal_fn_t)marshal_Tversion, + }, + [LIB9P_TYP_Rversion] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rversion), + r.unmarshal_extrasize = checksize_Rversion, + r.unmarshal = unmarshal_Rversion, + r.marshal = (_marshal_fn_t)marshal_Rversion, + }, + }, + [LIB9P_VER_9P2000] = { + [LIB9P_TYP_Tversion] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tversion), + r.unmarshal_extrasize = checksize_Tversion, + r.unmarshal = unmarshal_Tversion, + r.marshal = (_marshal_fn_t)marshal_Tversion, + }, + [LIB9P_TYP_Rversion] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rversion), + r.unmarshal_extrasize = checksize_Rversion, + r.unmarshal = unmarshal_Rversion, + r.marshal = (_marshal_fn_t)marshal_Rversion, + }, + [LIB9P_TYP_Tauth] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tauth), + r.unmarshal_extrasize = checksize_Tauth, + r.unmarshal = unmarshal_Tauth, + r.marshal = (_marshal_fn_t)marshal_Tauth, + }, + [LIB9P_TYP_Rauth] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rauth), + r.unmarshal_extrasize = checksize_Rauth, + r.unmarshal = unmarshal_Rauth, + r.marshal = (_marshal_fn_t)marshal_Rauth, + }, + [LIB9P_TYP_Tattach] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tattach), + r.unmarshal_extrasize = checksize_Tattach, + r.unmarshal = unmarshal_Tattach, + r.marshal = (_marshal_fn_t)marshal_Tattach, + }, + [LIB9P_TYP_Rattach] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rattach), + r.unmarshal_extrasize = checksize_Rattach, + r.unmarshal = unmarshal_Rattach, + r.marshal = (_marshal_fn_t)marshal_Rattach, + }, + [LIB9P_TYP_Rerror] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rerror), + r.unmarshal_extrasize = checksize_Rerror, + r.unmarshal = unmarshal_Rerror, + r.marshal = (_marshal_fn_t)marshal_Rerror, + }, + [LIB9P_TYP_Tflush] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tflush), + r.unmarshal_extrasize = checksize_Tflush, + r.unmarshal = unmarshal_Tflush, + r.marshal = (_marshal_fn_t)marshal_Tflush, + }, + [LIB9P_TYP_Rflush] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rflush), + r.unmarshal_extrasize = checksize_Rflush, + r.unmarshal = unmarshal_Rflush, + r.marshal = (_marshal_fn_t)marshal_Rflush, + }, + [LIB9P_TYP_Twalk] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Twalk), + r.unmarshal_extrasize = checksize_Twalk, + r.unmarshal = unmarshal_Twalk, + r.marshal = (_marshal_fn_t)marshal_Twalk, + }, + [LIB9P_TYP_Rwalk] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwalk), + r.unmarshal_extrasize = checksize_Rwalk, + r.unmarshal = unmarshal_Rwalk, + r.marshal = (_marshal_fn_t)marshal_Rwalk, + }, + [LIB9P_TYP_Topen] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Topen), + r.unmarshal_extrasize = checksize_Topen, + r.unmarshal = unmarshal_Topen, + r.marshal = (_marshal_fn_t)marshal_Topen, + }, + [LIB9P_TYP_Ropen] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Ropen), + r.unmarshal_extrasize = checksize_Ropen, + r.unmarshal = unmarshal_Ropen, + r.marshal = (_marshal_fn_t)marshal_Ropen, + }, + [LIB9P_TYP_Tcreate] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tcreate), + r.unmarshal_extrasize = checksize_Tcreate, + r.unmarshal = unmarshal_Tcreate, + r.marshal = (_marshal_fn_t)marshal_Tcreate, + }, + [LIB9P_TYP_Rcreate] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rcreate), + r.unmarshal_extrasize = checksize_Rcreate, + r.unmarshal = unmarshal_Rcreate, + r.marshal = (_marshal_fn_t)marshal_Rcreate, + }, + [LIB9P_TYP_Tread] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tread), + r.unmarshal_extrasize = checksize_Tread, + r.unmarshal = unmarshal_Tread, + r.marshal = (_marshal_fn_t)marshal_Tread, + }, + [LIB9P_TYP_Rread] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rread), + r.unmarshal_extrasize = checksize_Rread, + r.unmarshal = unmarshal_Rread, + r.marshal = (_marshal_fn_t)marshal_Rread, + }, + [LIB9P_TYP_Twrite] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Twrite), + r.unmarshal_extrasize = checksize_Twrite, + r.unmarshal = unmarshal_Twrite, + r.marshal = (_marshal_fn_t)marshal_Twrite, + }, + [LIB9P_TYP_Rwrite] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwrite), + r.unmarshal_extrasize = checksize_Rwrite, + r.unmarshal = unmarshal_Rwrite, + r.marshal = (_marshal_fn_t)marshal_Rwrite, + }, + [LIB9P_TYP_Tclunk] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tclunk), + r.unmarshal_extrasize = checksize_Tclunk, + r.unmarshal = unmarshal_Tclunk, + r.marshal = (_marshal_fn_t)marshal_Tclunk, + }, + [LIB9P_TYP_Rclunk] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rclunk), + r.unmarshal_extrasize = checksize_Rclunk, + r.unmarshal = unmarshal_Rclunk, + r.marshal = (_marshal_fn_t)marshal_Rclunk, + }, + [LIB9P_TYP_Tremove] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tremove), + r.unmarshal_extrasize = checksize_Tremove, + r.unmarshal = unmarshal_Tremove, + r.marshal = (_marshal_fn_t)marshal_Tremove, + }, + [LIB9P_TYP_Rremove] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rremove), + r.unmarshal_extrasize = checksize_Rremove, + r.unmarshal = unmarshal_Rremove, + r.marshal = (_marshal_fn_t)marshal_Rremove, + }, + [LIB9P_TYP_Tstat] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tstat), + r.unmarshal_extrasize = checksize_Tstat, + r.unmarshal = unmarshal_Tstat, + r.marshal = (_marshal_fn_t)marshal_Tstat, + }, + [LIB9P_TYP_Rstat] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rstat), + r.unmarshal_extrasize = checksize_Rstat, + r.unmarshal = unmarshal_Rstat, + r.marshal = (_marshal_fn_t)marshal_Rstat, + }, + [LIB9P_TYP_Twstat] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Twstat), + r.unmarshal_extrasize = checksize_Twstat, + r.unmarshal = unmarshal_Twstat, + r.marshal = (_marshal_fn_t)marshal_Twstat, + }, + [LIB9P_TYP_Rwstat] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwstat), + r.unmarshal_extrasize = checksize_Rwstat, + r.unmarshal = unmarshal_Rwstat, + r.marshal = (_marshal_fn_t)marshal_Rwstat, + }, + }, + [LIB9P_VER_9P2000_e] = { + [LIB9P_TYP_Tversion] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tversion), + r.unmarshal_extrasize = checksize_Tversion, + r.unmarshal = unmarshal_Tversion, + r.marshal = (_marshal_fn_t)marshal_Tversion, + }, + [LIB9P_TYP_Rversion] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rversion), + r.unmarshal_extrasize = checksize_Rversion, + r.unmarshal = unmarshal_Rversion, + r.marshal = (_marshal_fn_t)marshal_Rversion, + }, + [LIB9P_TYP_Tauth] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tauth), + r.unmarshal_extrasize = checksize_Tauth, + r.unmarshal = unmarshal_Tauth, + r.marshal = (_marshal_fn_t)marshal_Tauth, + }, + [LIB9P_TYP_Rauth] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rauth), + r.unmarshal_extrasize = checksize_Rauth, + r.unmarshal = unmarshal_Rauth, + r.marshal = (_marshal_fn_t)marshal_Rauth, + }, + [LIB9P_TYP_Tattach] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tattach), + r.unmarshal_extrasize = checksize_Tattach, + r.unmarshal = unmarshal_Tattach, + r.marshal = (_marshal_fn_t)marshal_Tattach, + }, + [LIB9P_TYP_Rattach] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rattach), + r.unmarshal_extrasize = checksize_Rattach, + r.unmarshal = unmarshal_Rattach, + r.marshal = (_marshal_fn_t)marshal_Rattach, + }, + [LIB9P_TYP_Rerror] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rerror), + r.unmarshal_extrasize = checksize_Rerror, + r.unmarshal = unmarshal_Rerror, + r.marshal = (_marshal_fn_t)marshal_Rerror, + }, + [LIB9P_TYP_Tflush] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tflush), + r.unmarshal_extrasize = checksize_Tflush, + r.unmarshal = unmarshal_Tflush, + r.marshal = (_marshal_fn_t)marshal_Tflush, + }, + [LIB9P_TYP_Rflush] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rflush), + r.unmarshal_extrasize = checksize_Rflush, + r.unmarshal = unmarshal_Rflush, + r.marshal = (_marshal_fn_t)marshal_Rflush, + }, + [LIB9P_TYP_Twalk] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Twalk), + r.unmarshal_extrasize = checksize_Twalk, + r.unmarshal = unmarshal_Twalk, + r.marshal = (_marshal_fn_t)marshal_Twalk, + }, + [LIB9P_TYP_Rwalk] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwalk), + r.unmarshal_extrasize = checksize_Rwalk, + r.unmarshal = unmarshal_Rwalk, + r.marshal = (_marshal_fn_t)marshal_Rwalk, + }, + [LIB9P_TYP_Topen] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Topen), + r.unmarshal_extrasize = checksize_Topen, + r.unmarshal = unmarshal_Topen, + r.marshal = (_marshal_fn_t)marshal_Topen, + }, + [LIB9P_TYP_Ropen] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Ropen), + r.unmarshal_extrasize = checksize_Ropen, + r.unmarshal = unmarshal_Ropen, + r.marshal = (_marshal_fn_t)marshal_Ropen, + }, + [LIB9P_TYP_Tcreate] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tcreate), + r.unmarshal_extrasize = checksize_Tcreate, + r.unmarshal = unmarshal_Tcreate, + r.marshal = (_marshal_fn_t)marshal_Tcreate, + }, + [LIB9P_TYP_Rcreate] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rcreate), + r.unmarshal_extrasize = checksize_Rcreate, + r.unmarshal = unmarshal_Rcreate, + r.marshal = (_marshal_fn_t)marshal_Rcreate, + }, + [LIB9P_TYP_Tread] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tread), + r.unmarshal_extrasize = checksize_Tread, + r.unmarshal = unmarshal_Tread, + r.marshal = (_marshal_fn_t)marshal_Tread, + }, + [LIB9P_TYP_Rread] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rread), + r.unmarshal_extrasize = checksize_Rread, + r.unmarshal = unmarshal_Rread, + r.marshal = (_marshal_fn_t)marshal_Rread, + }, + [LIB9P_TYP_Twrite] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Twrite), + r.unmarshal_extrasize = checksize_Twrite, + r.unmarshal = unmarshal_Twrite, + r.marshal = (_marshal_fn_t)marshal_Twrite, + }, + [LIB9P_TYP_Rwrite] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwrite), + r.unmarshal_extrasize = checksize_Rwrite, + r.unmarshal = unmarshal_Rwrite, + r.marshal = (_marshal_fn_t)marshal_Rwrite, + }, + [LIB9P_TYP_Tclunk] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tclunk), + r.unmarshal_extrasize = checksize_Tclunk, + r.unmarshal = unmarshal_Tclunk, + r.marshal = (_marshal_fn_t)marshal_Tclunk, + }, + [LIB9P_TYP_Rclunk] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rclunk), + r.unmarshal_extrasize = checksize_Rclunk, + r.unmarshal = unmarshal_Rclunk, + r.marshal = (_marshal_fn_t)marshal_Rclunk, + }, + [LIB9P_TYP_Tremove] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tremove), + r.unmarshal_extrasize = checksize_Tremove, + r.unmarshal = unmarshal_Tremove, + r.marshal = (_marshal_fn_t)marshal_Tremove, + }, + [LIB9P_TYP_Rremove] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rremove), + r.unmarshal_extrasize = checksize_Rremove, + r.unmarshal = unmarshal_Rremove, + r.marshal = (_marshal_fn_t)marshal_Rremove, + }, + [LIB9P_TYP_Tstat] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tstat), + r.unmarshal_extrasize = checksize_Tstat, + r.unmarshal = unmarshal_Tstat, + r.marshal = (_marshal_fn_t)marshal_Tstat, + }, + [LIB9P_TYP_Rstat] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rstat), + r.unmarshal_extrasize = checksize_Rstat, + r.unmarshal = unmarshal_Rstat, + r.marshal = (_marshal_fn_t)marshal_Rstat, + }, + [LIB9P_TYP_Twstat] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Twstat), + r.unmarshal_extrasize = checksize_Twstat, + r.unmarshal = unmarshal_Twstat, + r.marshal = (_marshal_fn_t)marshal_Twstat, + }, + [LIB9P_TYP_Rwstat] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwstat), + r.unmarshal_extrasize = checksize_Rwstat, + r.unmarshal = unmarshal_Rwstat, + r.marshal = (_marshal_fn_t)marshal_Rwstat, + }, + [LIB9P_TYP_Tsession] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tsession), + r.unmarshal_extrasize = checksize_Tsession, + r.unmarshal = unmarshal_Tsession, + r.marshal = (_marshal_fn_t)marshal_Tsession, + }, + [LIB9P_TYP_Rsession] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rsession), + r.unmarshal_extrasize = checksize_Rsession, + r.unmarshal = unmarshal_Rsession, + r.marshal = (_marshal_fn_t)marshal_Rsession, + }, + [LIB9P_TYP_Tsread] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tsread), + r.unmarshal_extrasize = checksize_Tsread, + r.unmarshal = unmarshal_Tsread, + r.marshal = (_marshal_fn_t)marshal_Tsread, + }, + [LIB9P_TYP_Rsread] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rsread), + r.unmarshal_extrasize = checksize_Rsread, + r.unmarshal = unmarshal_Rsread, + r.marshal = (_marshal_fn_t)marshal_Rsread, + }, + [LIB9P_TYP_Tswrite] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tswrite), + r.unmarshal_extrasize = checksize_Tswrite, + r.unmarshal = unmarshal_Tswrite, + r.marshal = (_marshal_fn_t)marshal_Tswrite, + }, + [LIB9P_TYP_Rswrite] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rswrite), + r.unmarshal_extrasize = checksize_Rswrite, + r.unmarshal = unmarshal_Rswrite, + r.marshal = (_marshal_fn_t)marshal_Rswrite, + }, + }, + [LIB9P_VER_9P2000_u] = { + [LIB9P_TYP_Tversion] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tversion), + r.unmarshal_extrasize = checksize_Tversion, + r.unmarshal = unmarshal_Tversion, + r.marshal = (_marshal_fn_t)marshal_Tversion, + }, + [LIB9P_TYP_Rversion] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rversion), + r.unmarshal_extrasize = checksize_Rversion, + r.unmarshal = unmarshal_Rversion, + r.marshal = (_marshal_fn_t)marshal_Rversion, + }, + [LIB9P_TYP_Tauth] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tauth), + r.unmarshal_extrasize = checksize_Tauth, + r.unmarshal = unmarshal_Tauth, + r.marshal = (_marshal_fn_t)marshal_Tauth, + }, + [LIB9P_TYP_Rauth] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rauth), + r.unmarshal_extrasize = checksize_Rauth, + r.unmarshal = unmarshal_Rauth, + r.marshal = (_marshal_fn_t)marshal_Rauth, + }, + [LIB9P_TYP_Tattach] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tattach), + r.unmarshal_extrasize = checksize_Tattach, + r.unmarshal = unmarshal_Tattach, + r.marshal = (_marshal_fn_t)marshal_Tattach, + }, + [LIB9P_TYP_Rattach] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rattach), + r.unmarshal_extrasize = checksize_Rattach, + r.unmarshal = unmarshal_Rattach, + r.marshal = (_marshal_fn_t)marshal_Rattach, + }, + [LIB9P_TYP_Rerror] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rerror), + r.unmarshal_extrasize = checksize_Rerror, + r.unmarshal = unmarshal_Rerror, + r.marshal = (_marshal_fn_t)marshal_Rerror, + }, + [LIB9P_TYP_Tflush] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tflush), + r.unmarshal_extrasize = checksize_Tflush, + r.unmarshal = unmarshal_Tflush, + r.marshal = (_marshal_fn_t)marshal_Tflush, + }, + [LIB9P_TYP_Rflush] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rflush), + r.unmarshal_extrasize = checksize_Rflush, + r.unmarshal = unmarshal_Rflush, + r.marshal = (_marshal_fn_t)marshal_Rflush, + }, + [LIB9P_TYP_Twalk] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Twalk), + r.unmarshal_extrasize = checksize_Twalk, + r.unmarshal = unmarshal_Twalk, + r.marshal = (_marshal_fn_t)marshal_Twalk, + }, + [LIB9P_TYP_Rwalk] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwalk), + r.unmarshal_extrasize = checksize_Rwalk, + r.unmarshal = unmarshal_Rwalk, + r.marshal = (_marshal_fn_t)marshal_Rwalk, + }, + [LIB9P_TYP_Topen] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Topen), + r.unmarshal_extrasize = checksize_Topen, + r.unmarshal = unmarshal_Topen, + r.marshal = (_marshal_fn_t)marshal_Topen, + }, + [LIB9P_TYP_Ropen] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Ropen), + r.unmarshal_extrasize = checksize_Ropen, + r.unmarshal = unmarshal_Ropen, + r.marshal = (_marshal_fn_t)marshal_Ropen, + }, + [LIB9P_TYP_Tcreate] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tcreate), + r.unmarshal_extrasize = checksize_Tcreate, + r.unmarshal = unmarshal_Tcreate, + r.marshal = (_marshal_fn_t)marshal_Tcreate, + }, + [LIB9P_TYP_Rcreate] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rcreate), + r.unmarshal_extrasize = checksize_Rcreate, + r.unmarshal = unmarshal_Rcreate, + r.marshal = (_marshal_fn_t)marshal_Rcreate, + }, + [LIB9P_TYP_Tread] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tread), + r.unmarshal_extrasize = checksize_Tread, + r.unmarshal = unmarshal_Tread, + r.marshal = (_marshal_fn_t)marshal_Tread, + }, + [LIB9P_TYP_Rread] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rread), + r.unmarshal_extrasize = checksize_Rread, + r.unmarshal = unmarshal_Rread, + r.marshal = (_marshal_fn_t)marshal_Rread, + }, + [LIB9P_TYP_Twrite] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Twrite), + r.unmarshal_extrasize = checksize_Twrite, + r.unmarshal = unmarshal_Twrite, + r.marshal = (_marshal_fn_t)marshal_Twrite, + }, + [LIB9P_TYP_Rwrite] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwrite), + r.unmarshal_extrasize = checksize_Rwrite, + r.unmarshal = unmarshal_Rwrite, + r.marshal = (_marshal_fn_t)marshal_Rwrite, + }, + [LIB9P_TYP_Tclunk] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tclunk), + r.unmarshal_extrasize = checksize_Tclunk, + r.unmarshal = unmarshal_Tclunk, + r.marshal = (_marshal_fn_t)marshal_Tclunk, + }, + [LIB9P_TYP_Rclunk] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rclunk), + r.unmarshal_extrasize = checksize_Rclunk, + r.unmarshal = unmarshal_Rclunk, + r.marshal = (_marshal_fn_t)marshal_Rclunk, + }, + [LIB9P_TYP_Tremove] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tremove), + r.unmarshal_extrasize = checksize_Tremove, + r.unmarshal = unmarshal_Tremove, + r.marshal = (_marshal_fn_t)marshal_Tremove, + }, + [LIB9P_TYP_Rremove] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rremove), + r.unmarshal_extrasize = checksize_Rremove, + r.unmarshal = unmarshal_Rremove, + r.marshal = (_marshal_fn_t)marshal_Rremove, + }, + [LIB9P_TYP_Tstat] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Tstat), + r.unmarshal_extrasize = checksize_Tstat, + r.unmarshal = unmarshal_Tstat, + r.marshal = (_marshal_fn_t)marshal_Tstat, + }, + [LIB9P_TYP_Rstat] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rstat), + r.unmarshal_extrasize = checksize_Rstat, + r.unmarshal = unmarshal_Rstat, + r.marshal = (_marshal_fn_t)marshal_Rstat, + }, + [LIB9P_TYP_Twstat] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Twstat), + r.unmarshal_extrasize = checksize_Twstat, + r.unmarshal = unmarshal_Twstat, + r.marshal = (_marshal_fn_t)marshal_Twstat, + }, + [LIB9P_TYP_Rwstat] = { + r.unmarshal_basesize = sizeof(struct lib9p_msg_Rwstat), + r.unmarshal_extrasize = checksize_Rwstat, + r.unmarshal = unmarshal_Rwstat, + r.marshal = (_marshal_fn_t)marshal_Rwstat, + }, + }, +}; diff --git a/lib9p/types.gen b/lib9p/types.gen new file mode 100755 index 0000000..141b591 --- /dev/null +++ b/lib9p/types.gen @@ -0,0 +1,611 @@ +#!/usr/bin/env python +# lib9p/types.gen - Generate C marshalers/unmarshalers for .txt files +# defining 9P protocol variants. +# +# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-Licence-Identifier: AGPL-3.0-or-later + +import enum +import os.path +import re +from typing import Callable + +# Parse *.txt ################################################################## + + +class Atom(enum.Enum): + u8 = 1 + u16 = 2 + u32 = 4 + u64 = 8 + + @property + def name(self) -> str: + return str(self.value) + + @property + def static_size(self) -> int: + return self.value + + +# `msgid/structname = "member1 member2..."` +# `structname = "member1 member2..."` +# `structname += "member1 member2..."` +class Struct: + msgid: int | None = None + msgver: set[str] + name: str + members: list["Member"] + + def __init__(self) -> None: + self.msgver = set() + + @property + def static_size(self) -> int | None: + size = 0 + for member in self.members: + msize = member.static_size + if msize is None: + return None + size += msize + return size + + +# `cnt*(name[typ])` +# the `cnt*(...)` wrapper is optional +class Member: + cnt: str | None = None + name: str + typ: Atom | Struct + ver: set[str] + + @property + def static_size(self) -> int | None: + if self.cnt: + return None + return self.typ.static_size + + +re_membername = "(?:[a-zA-Z_][a-zA-Z_0-9]*)" +re_memberspec = ( + f"(?:(?P<cnt>{re_membername})\\*\\()?(?P<name>{re_membername})\\[(?P<typ>.*)\\]\\)?" +) + + +def parse_members( + ver: str, + env: dict[str, Atom | Struct], existing: list[Member], specs: str +) -> list[Member]: + ret = existing + for spec in specs.split(): + m = re.fullmatch(re_memberspec, spec) + if not m: + raise SyntaxError(f"invalid member spec {repr(spec)}") + + member = Member() + member.ver = {ver} + + member.name = m.group("name") + if any(x.name == member.name for x in ret): + raise ValueError(f"duplicate member name {repr(member.name)}") + + if m.group("typ") not in env: + raise NameError(f"Unknown type {repr(m.group(2))}") + member.typ = env[m.group("typ")] + + if cnt := m.group("cnt"): + if len(ret) == 0 or ret[-1].name != cnt: + raise ValueError(f"list count must be previous item: {repr(cnt)}") + if not isinstance(ret[-1].typ, Atom): + raise ValueError(f"list count must be an integer type: {repr(cnt)}") + member.cnt = cnt + + ret += [member] + return ret + + +re_version = r'version\s+"(?P<version>[^"]+)"' +re_import = r'from\s+(?P<file>\S+)\s+import\s+(?P<syms>\S+(?:\s*,\s*\S+)*)\s*' +re_structspec = ( + r'(?:(?P<msgid>[0-9]+)/)?(?P<name>\S+)\s*(?P<op>\+?=)\s*"(?P<members>[^"]*)"' +) +re_structspec_cont = r'"(?P<members>[^"]*)"' + + +def parse_file(filename: str, get_include: Callable[[str], tuple[str, list[Struct]]]) -> tuple[str, list[Struct]]: + version: str | None = None + env: dict[str, Atom | Struct] = { + "1": Atom.u8, + "2": Atom.u16, + "4": Atom.u32, + "8": Atom.u64, + } + with open(filename, "r") as fh: + prev: Struct | None = None + for line in fh: + line = line.split("#", 1)[0].strip() + if not line: + continue + if m := re.fullmatch(re_version, line): + if version: + raise SyntaxError("must have exactly 1 version line") + version = m.group("version") + elif m := re.fullmatch(re_import, line): + if not version: + raise SyntaxError("must have exactly 1 version line") + other_version, other_structs = get_include(m.group("file")) + for symname in m.group("syms").split(sep=","): + symname = symname.strip() + for struct in other_structs: + if struct.name == symname or symname == '*': + if struct.msgid: + struct.msgver.add(version) + for member in struct.members: + if other_version in member.ver: + member.ver.add(version) + env[struct.name] = struct + elif m := re.fullmatch(re_structspec, line): + if not version: + raise SyntaxError("must have exactly 1 version line") + if m.group("op") == "+=" and m.group("msgid"): + raise SyntaxError("cannot += to a message that is not yet defined") + match m.group("op"): + case "=": + struct = Struct() + if m.group("msgid"): + struct.msgid = int(m.group("msgid")) + struct.msgver.add(version) + struct.name = m.group("name") + struct.members = parse_members(version, env, [], m.group("members")) + env[struct.name] = struct + prev = struct + case "+=": + if m.group("name") not in env: + raise NameError(f"Unknown type {repr(m.group('name'))}") + _struct = env[m.group("name")] + if not isinstance(_struct, Struct): + raise NameError( + f"Type {repr(m.group('name'))} is not a struct" + ) + struct = _struct + struct.members = parse_members(version, + env, struct.members, m.group("members") + ) + prev = struct + elif m := re.fullmatch(re_structspec_cont, line): + if not prev: + raise SyntaxError("continuation line must come after a struct line") + assert(version) + prev.members = parse_members(version, env, prev.members, m.group("members")) + else: + raise SyntaxError(f"invalid line {repr(line)}") + if not version: + raise SyntaxError("must have exactly 1 version line") + structs = [x for x in env.values() if isinstance(x, Struct)] + return version, structs + +# Generate C ################################################################### + + +def c_typename(idprefix: str, typ: Atom | Struct) -> str: + match typ: + case Atom(): + return f"uint{typ.value*8}_t" + case Struct(): + if typ.msgid is not None: + return f"struct {idprefix}msg_{typ.name}" + return f"struct {idprefix}{typ.name}" + case _: + raise ValueError(f"not a type: {typ.__class__.__name__}") + +def c_vercomment(versions: set[str]) -> str|None: + if "9P2000" in versions: + return None + return "/* "+(", ".join(sorted(versions)))+" */" + +def c_ver(idprefix: str, ver: str) -> str: + return f"{idprefix.upper()}VER_{ver.replace('.', '_')}" + +def gen_h(idprefix: str, versions: set[str], structs: list[Struct]) -> str: + guard = "_LIB9P__TYPES_H_" + ret = f"""/* Generated by `{' '.join(sys.argv)}`. DO NOT EDIT! */ + +#ifndef {guard} +#define {guard} + +#include <stdint.h> +""" + + ret += f""" +/* versions *******************************************************************/ + +enum {idprefix}version {{ + {idprefix.upper()}VER_UNINITIALIZED = 0, +""" + verwidth = max(len(v) for v in versions) + for ver in sorted(versions): + ret += f"\t{c_ver(idprefix, ver)}," + ret += (" "*(verwidth-len(ver))) + ' /* "' + ver + '" */\n' + ret += f"\t{idprefix.upper()}VER_NUM,\n" + ret += "};\n" + + ret += """ +/* non-message structs ********************************************************/ +""" + for struct in structs: + if struct.msgid is not None: + continue + + all_the_same = len(struct.members) == 0 or all(m.ver == struct.members[0].ver for m in struct.members) + typewidth = max(len(c_typename(idprefix, m.typ)) for m in struct.members) + if not all_the_same: + namewidth = max(len(m.name) for m in struct.members) + + ret += "\n" + ret += c_typename(idprefix, struct) + " {\n" + for member in struct.members: + ret += f"\t{c_typename(idprefix, member.typ).ljust(typewidth)} {'*' if member.cnt else ' '}{member.name};" + if (not all_the_same) and (comment := c_vercomment(member.ver)): + ret += (" "*(namewidth-len(member.name))) + " " + comment + ret += "\n" + ret += "};\n" + + ret += """ +/* messages *******************************************************************/ + +""" + ret += f"enum {idprefix}msg_type {{ /* uint8_t */\n" + namewidth = max(len(msg.name) for msg in structs if msg.msgid is not None) + for msg in structs: + if msg.msgid is None: + continue + ret += f"\t{idprefix.upper()}TYP_{msg.name.ljust(namewidth)} = {msg.msgid}," + if (comment := c_vercomment(msg.msgver)): + ret += " " + comment + ret += "\n" + ret += "};\n" + + ret += "\n" + ret += f"#define {idprefix.upper()}TYPECODE_FOR_CTYPE(msg) _Generic((msg)" + for msg in structs: + if msg.msgid is None: + continue + ret += f", \\\n\t\t{c_typename(idprefix, msg)}: {idprefix.upper()}TYP_{msg.name}" + ret += ")\n" + + for msg in structs: + if msg.msgid is None: + continue + + ret += "\n" + if comment := c_vercomment(msg.msgver): + ret += comment + "\n" + ret += c_typename(idprefix, msg) + " {" + if not msg.members: + ret += "};\n" + continue + ret += "\n" + + all_the_same = len(msg.members) == 0 or all(m.ver == msg.members[0].ver for m in msg.members) + typewidth = max(len(c_typename(idprefix, m.typ)) for m in msg.members) + if not all_the_same: + namewidth = max(len(m.name) for m in msg.members) + + for member in msg.members: + ret += f"\t{c_typename(idprefix, member.typ).ljust(typewidth)} {'*' if member.cnt else ' '}{member.name};" + if (not all_the_same) and (comment := c_vercomment(member.ver)): + ret += (" "*(namewidth-len(member.name))) + " " + comment + ret += "\n" + ret += "};\n" + + + ret += "\n" + ret += f"#endif /* {guard} */\n" + return ret + + +def gen_c(idprefix: str, versions: set[str], structs: list[Struct]) -> str: + ret = f"""/* Generated by `{' '.join(sys.argv)}`. DO NOT EDIT! */ + +#include <stdbool.h> + +#include <lib9p/9p.h> + +#include "internal.h" +""" + + def used(arg: str) -> str: + return arg + + def unused(arg: str) -> str: + return f"UNUSED({arg})" + + # checksize_* ############################################################## + ret += """ +/* checksize_* (internals of unmarshal_size()) ********************************/ + +static inline bool _checksize_net(struct _checksize_ctx *ctx, uint32_t n) { + if (__builtin_add_overflow(ctx->net_offset, n, &ctx->net_offset)) + /* If needed-net-size overflowed uint32_t, then + * there's no way that actual-net-size will live up to + * that. */ + return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content"); + if (ctx->net_offset > ctx->net_size) + return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content"); + return false; +} + +static inline bool _checksize_host(struct _checksize_ctx *ctx, size_t n) { + if (__builtin_add_overflow(ctx->host_extra, n, &ctx->host_extra)) + /* If needed-host-size overflowed size_t, then there's + * no way that actual-net-size will live up to + * that. */ + return lib9p_error(ctx->ctx, LINUX_EBADMSG, "message is too short for content"); + return false; +} + +static inline bool _checksize_list(struct _checksize_ctx *ctx, + size_t cnt, _checksize_fn_t item_fn, size_t item_host_size) { + for (size_t i = 0; i < cnt; i++) + if (_checksize_host(ctx, item_host_size) || item_fn(ctx)) + return true; + return false; +} + +#define checksize_1(ctx) _checksize_net(ctx, 1) +#define checksize_2(ctx) _checksize_net(ctx, 2) +#define checksize_4(ctx) _checksize_net(ctx, 4) +#define checksize_8(ctx) _checksize_net(ctx, 8) +""" + for struct in structs: + inline = ' inline' if struct.msgid is None else '' + argfn = used if struct.members else unused + ret += "\n" + ret += f"static{inline} bool checksize_{struct.name}(struct _checksize_ctx *{argfn('ctx')}) {{" + if len(struct.members) == 0: + ret += "\n\treturn false;\n" + ret += "}\n" + continue + + prefix0 = "\treturn " + prefix1 = "\t || " + + match struct.name: + case "d": + # Optimize... maybe the compiler could figure out to do + # this, but let's make it obvious. + ret += "\n" + ret += "\tuint32_t base_offset = ctx->net_offset;\n" + ret += "\tif (_checksize_4(ctx))\n" + ret += "\t\treturn true;\n" + ret += "\tuint32_t len = decode_u32le(&ctx->net_bytes[base_offset]);\n" + ret += "\treturn checksize_net(ctx, len) || checksize_host(ctx, len);\n" + ret += "}\n" + case "s": + # Add an extra nul-byte on the host, and validate + # UTF-8 (also, similar optimization to "d"). + ret += "\n" + ret += "\tuint32_t base_offset = ctx->net_offset;\n" + ret += "\tif (_checksize_2(ctx))\n" + ret += "\t\treturn true;\n" + ret += "\tuint16_t len = decode_u16le(&ctx->net_bytes[base_offset]);\n" + ret += "\tif (checksize_net(ctx, len) || checksize_host(ctx, ((size_t)len)+1))\n" + ret += "\t\treturn true;\n" + ret += "\tif (!is_valid_utf8_without_nul(&ctx->net_bytes[base_offset+2], len))\n" + ret += '\t\treturn lib9p_error(ctx->ctx, LINUX_EBADMSG, "message contains invalid UTF-8");\n' + ret += "\treturn false;\n" + ret += "}\n" + case _: + struct_versions = struct.members[0].ver + + prefix = prefix0 + prev_size: int | None = None + for member in struct.members: + ret += f"\n{prefix}" + if member.ver != struct_versions: + ret += "( ( " + (" || ".join(f"(ctx->ctx->version=={c_ver(idprefix, v)})" for v in sorted(member.ver))) + " ) && " + if member.cnt is not None: + assert prev_size + ret += f"_checksize_list(ctx, decode_u{prev_size*8}le(&ctx->net_bytes[ctx->net_offset-{prev_size}]), checksize_{member.typ.name}, sizeof({c_typename(idprefix, member.typ)}))" + else: + ret += f"checksize_{member.typ.name}(ctx)" + if member.ver != struct_versions: + ret += " )" + prefix = prefix1 + prev_size = member.static_size + ret += ";\n}\n" + + # unmarshal_* ############################################################## + ret += """ +/* unmarshal_* ****************************************************************/ + +static inline vold unmarshal_1(struct _unmarshal_ctx *ctx, uint8_t *out) { + *out = decode_u8le(&ctx->net_bytes[ctx->net_offset]); + ctx->net_offset += 1; +} + +static inline vold unmarshal_2(struct _unmarshal_ctx *ctx, uint16_t *out) { + *out = decode_u16le(&ctx->net_bytes[ctx->net_offset]); + ctx->net_offset += 2; +} + +static inline vold unmarshal_4(struct _unmarshal_ctx *ctx, uint32_t *out) { + *out = decode_u32le(&ctx->net_bytes[ctx->net_offset]); + ctx->net_offset += 4; +} + +static inline vold unmarshal_8(struct _unmarshal_ctx *ctx, uint64_t *out) { + *out = decode_u64le(&ctx->net_bytes[ctx->net_offset]); + ctx->net_offset += 8; +} +""" + for struct in structs: + inline = ' inline' if struct.msgid is None else '' + argfn = used if struct.members else unused + ret += "\n" + ret += f"static{inline} void unmarshal_{struct.name}(struct _unmarshal_ctx *{argfn('ctx')}, {c_typename(idprefix, struct)} *{argfn('out')}) {{\n" + ret += "\tmemset(out, 0, sizeof(*out));\n" + + if struct.members: + struct_versions = struct.members[0].ver + for member in struct.members: + ret += "\t" + prefix = "\t" + if member.ver != struct_versions: + ret += "if ( " + (" || ".join(f"(ctx->ctx->version=={c_ver(idprefix, v)})" for v in sorted(member.ver))) + " ) " + prefix = "\t\t" + if member.cnt: + if member.ver != struct_versions: + ret += "{\n" + ret += f"{prefix}out->{member.name} = ctx->host_extra;\n" + ret += f"{prefix}ctx->host_extra += sizeof(out->{member.name}[0]) * out->{member.cnt};\n" + ret += f"{prefix}for (typeof(out->{member.cnt}) i = 0; i < out->{member.cnt}; i++)\n" + ret += f"{prefix}\tunmarshal_{member.typ.name}(ctx, &out->{member.name}[i]);\n" + if member.ver != struct_versions: + ret += "\t}\n" + else: + ret += f"unmarshal_{member.typ.name}(ctx, &out->{member.name});\n" + ret += "}\n" + + # marshal_* ################################################################ + ret += """ +/* marshal_* ******************************************************************/ + +static inline bool _marshal_too_large(struct _marshal_ctx *ctx) { + lib9p_errorf(ctx->ctx, "%s too large to marshal into %s limit (limit=%"PRIu32")", + (ctx->net_bytes[4] % 2 == 0) ? "T-message" : "R-message", + ctx->ctx->version ? "negotiated" : ((ctx->net_bytes[4] % 2 == 0) ? "client" : "server"), + ctx->ctx->max_msg_size)); + return true; +} + +static inline bool marshal_1(struct _marshal_ctx *ctx, uint8_t *val) { + if (ctx->net_offset + 1 > ctx->max_msg_size) + return _marshal_too_large(ctx); + out_net_bytes[ctx->net_offset] = *val; + ctx->net_offset += 1; + return false; +} + +static inline bool marshal_2(struct _marshal_ctx *ctx, uint16_t *val) { + if (ctx->net_offset + 2 > ctx->max_msg_size) + return _marshal_too_large(ctx); + encode_u16le(*val, &out_net_bytes[ctx->net_offset]); + ctx->net_offset += 2; + return false; +} + +static inline bool marshal_4(struct _marshal_ctx *ctx, uint32_t *val) { + if (ctx->net_offset + 4 > ctx->max_msg_size) + return true; + encode_u32le(*val, &out_net_bytes[ctx->net_offset]); + ctx->net_offset += 4; + return false; +} + +static inline bool marshal_8(struct _marshal_ctx *ctx, uint64_t *val) { + if (ctx->net_offset + 8 > ctx->max_msg_size) + return true; + encode_u64le(*val, &out_net_bytes[ctx->net_offset]); + ctx->net_offset += 8; + return false; +} +""" + for struct in structs: + inline = ' inline' if struct.msgid is None else '' + argfn = used if struct.members else unused + ret += "\n" + ret += f"static{inline} bool marshal_{struct.name}(struct _marshal_ctx *{argfn('ctx')}, {c_typename(idprefix, struct)} *{argfn('val')}) {{" + if len(struct.members) == 0: + ret += "\n\treturn false;\n" + ret += "}\n" + continue + + prefix0 = "\treturn " + prefix1 = "\t || " + prefix2 = "\t " + + prefix = prefix0 + for member in struct.members: + if member.cnt: + ret += f"\n{prefix }({{" + ret += f"\n{prefix2}\tbool err = false;" + ret += f"\n{prefix2}\tfor (typeof(val->{member.cnt}) i = 0; i < val->{member.cnt} && !err; i++)" + ret += f"\n{prefix2}\t\terr = marshal_{member.typ.name}(ctx, &val->{member.name}[i]));" + ret += f"\n{prefix2}\terr;" + ret += f"\n{prefix2}}})" + else: + ret += f"\n{prefix}marshal_{member.typ.name}(ctx, &val->{member.name})" + prefix = prefix1 + ret += ";\n}\n" + + # vtables ################################################################## + def msg_entry(msg: Struct) -> str: + ret = "" + ret += f"\t\t[{idprefix.upper()}TYP_{msg.name}] = {{\n" + ret += f"\t\t\tr.unmarshal_basesize = sizeof({c_typename(idprefix, msg)}),\n" + ret += f"\t\t\tr.unmarshal_extrasize = checksize_{msg.name},\n" + ret += f"\t\t\tr.unmarshal = unmarshal_{msg.name},\n" + ret += f"\t\t\tr.marshal = (_marshal_fn_t)marshal_{msg.name},\n" + ret += "\t\t}" + return ret + ret += f""" +/* vtables ********************************************************************/ + +struct _vtable_version _{idprefix}vtables[LIB9P_VER_NUM] = {{ + [{idprefix.upper()}VER_UNINITIALIZED] = {{ +{msg_entry(next(msg for msg in structs if msg.name == 'Tversion'))}, +{msg_entry(next(msg for msg in structs if msg.name == 'Rversion'))}, + }}, +""" + for ver in sorted(versions): + ret += f"\t[{c_ver(idprefix, ver)}] = {{\n" + for msg in structs: + if ver not in msg.msgver: + continue + ret += msg_entry(msg) + ",\n" + ret += "\t},\n" + ret += "};\n" + + ############################################################################ + return ret + + +################################################################################ + +class Parser: + cache: dict[str, tuple[str, list[Struct]]] = {} + + def parse_file(self, filename: str) -> tuple[str, list[Struct]]: + if filename not in self.cache: + self.cache[filename] = parse_file(filename, self.parse_file) + return self.cache[filename] + + def all(self) -> tuple[set[str], list[Struct]]: + ret_versions: set[str] = set() + ret_structs: dict[str, Struct] = {} + for (version, structs) in self.cache.values(): + if version in ret_versions: + raise ValueError(f"duplicate protocol version {repr(version)}") + ret_versions.add(version) + for struct in structs: + if struct.name in ret_structs: + if struct != ret_structs[struct.name]: + raise ValueError(f"duplicate struct name {repr(struct.name)}") + else: + ret_structs[struct.name] = struct + return ret_versions, list(ret_structs.values()) + +if __name__ == "__main__": + import sys + + if len(sys.argv) < 2: + raise ValueError("requires at least 1 .txt filename") + parser = Parser() + for txtname in sys.argv[1:]: + parser.parse_file(txtname) + versions, structs = parser.all() + with open("include/lib9p/_types.h", "w") as fh: + fh.write(gen_h("lib9p_", versions, structs)) + with open("types.c", "w") as fh: + fh.write(gen_c("lib9p_", versions, structs)) diff --git a/libcr/CMakeLists.txt b/libcr/CMakeLists.txt new file mode 100644 index 0000000..ad7997f --- /dev/null +++ b/libcr/CMakeLists.txt @@ -0,0 +1,10 @@ +# libcr/CMakeLists.txt - TODO +# +# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-Licence-Identifier: AGPL-3.0-or-later + +add_library(libcr INTERFACE) +target_sources(libcr INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/coroutine.c +) +target_include_directories(libcr SYSTEM INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include) diff --git a/libcr/coroutine.c b/libcr/coroutine.c index 12d4a25..34a96b6 100644 --- a/libcr/coroutine.c +++ b/libcr/coroutine.c @@ -10,7 +10,7 @@ #include <assert.h> #include <setjmp.h> -#include "coroutine.h" +#include "libcr/coroutine.h" /* Configuration **************************************************************/ diff --git a/libcr/coroutine.h b/libcr/include/libcr/coroutine.h index 4d83181..5c2d608 100644 --- a/libcr/coroutine.h +++ b/libcr/include/libcr/coroutine.h @@ -1,4 +1,4 @@ -/* coroutine.h - Simple embeddable coroutine implementation +/* libcr/coroutine.h - Simple embeddable coroutine implementation * * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-Licence-Identifier: AGPL-3.0-or-later diff --git a/libcr_ipc/CMakeLists.txt b/libcr_ipc/CMakeLists.txt new file mode 100644 index 0000000..3efb6d9 --- /dev/null +++ b/libcr_ipc/CMakeLists.txt @@ -0,0 +1,10 @@ +# libcr_ipc/CMakeLists.txt - TODO +# +# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-Licence-Identifier: AGPL-3.0-or-later + +add_library(libcr_ipc INTERFACE) +target_sources(libcr_ipc INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/sema.c +) +target_include_directories(libcr_ipc SYSTEM INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include) diff --git a/libcr_ipc/coroutine_chan.h b/libcr_ipc/include/libcr_ipc/chan.h index a3621a6..a3621a6 100644 --- a/libcr_ipc/coroutine_chan.h +++ b/libcr_ipc/include/libcr_ipc/chan.h diff --git a/libcr_ipc/coroutine_rpc.h b/libcr_ipc/include/libcr_ipc/rpc.h index 11d40d7..11d40d7 100644 --- a/libcr_ipc/coroutine_rpc.h +++ b/libcr_ipc/include/libcr_ipc/rpc.h diff --git a/libcr_ipc/coroutine_sema.h b/libcr_ipc/include/libcr_ipc/sema.h index 57d5855..57d5855 100644 --- a/libcr_ipc/coroutine_sema.h +++ b/libcr_ipc/include/libcr_ipc/sema.h diff --git a/libcr_ipc/coroutine_sema.c b/libcr_ipc/sema.c index a8b5ec4..a8b5ec4 100644 --- a/libcr_ipc/coroutine_sema.c +++ b/libcr_ipc/sema.c diff --git a/libnetio/CMakeLists.txt b/libnetio/CMakeLists.txt new file mode 100644 index 0000000..226a2e5 --- /dev/null +++ b/libnetio/CMakeLists.txt @@ -0,0 +1,10 @@ +# libnetio/CMakeLists.txt - Build script for libnetio support library +# +# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-Licence-Identifier: AGPL-3.0-or-later + +add_library(libnetio INTERFACE) +target_sources(libnetio INTERFACE + netio_posix.c +) +target_include_directories(libnetio SYSTEM INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include) diff --git a/libusb/CMakeLists.txt b/libusb/CMakeLists.txt new file mode 100644 index 0000000..8f015a1 --- /dev/null +++ b/libusb/CMakeLists.txt @@ -0,0 +1,23 @@ +# libusb/CMakeLists.txt - Build script for libusb support library +# +# Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> +# SPDX-Licence-Identifier: AGPL-3.0-or-later + +add_library(libusb INTERFACE) +target_sources(libusb INTERFACE + usb_common.c +) +target_include_directories(libusb SYSTEM INTERFACE ${CMAKE_CURRENT_LIST_DIR}/include) + +add_custom_command( + OUTPUT ${CMAKE_SOURCE_DIR}/3rd-party/MS-LCID.pdf + ${CMAKE_SOURCE_DIR}/3rd-party/MS-LCID.txt + ${CMAKE_CURRENT_SOURCE_DIR}/include/libusb/tusb_helpers.h + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/include/libusb/tusb_helpers.gen + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/include/libusb/tusb_helpers.gen +) +add_dependencies(generate + ${CMAKE_SOURCE_DIR}/3rd-party/MS-LCID.pdf + ${CMAKE_SOURCE_DIR}/3rd-party/MS-LCID.txt + ${CMAKE_CURRENT_SOURCE_DIR}/include/libusb/tusb_helpers.h +) diff --git a/libusb/tusb_helpers.h b/libusb/include/libusb/tusb_helpers.h index cd96357..cd96357 100644 --- a/libusb/tusb_helpers.h +++ b/libusb/include/libusb/tusb_helpers.h diff --git a/libusb/tusb_helpers.h.gen b/libusb/include/libusb/tusb_helpers.h.gen index a348b16..213eda0 100755 --- a/libusb/tusb_helpers.h.gen +++ b/libusb/include/libusb/tusb_helpers.h.gen @@ -3,7 +3,7 @@ set -e exec >"${0%.gen}" cat <<'EOT' -/* tusb_helpers.h - Preprocessor macros that I think should be included in TinyUSB +/* libusb/tusb_helpers.h - Preprocessor macros that I think should be included in TinyUSB * * Copyright (c) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> * @@ -29,10 +29,11 @@ cat <<'EOT' * */ -#ifndef _USB_HELPERS_H_ -#define _USB_HELPERS_H_ +#ifndef _LIBUSB_TUSB_HELPERS_H_ +#define _LIBUSB_TUSB_HELPERS_H_ -/* USB 2.0 §9.6.7 "String" says "The list of currently defined USB LANGIDs can be found at +/** + * USB 2.0 §9.6.7 "String" says "The list of currently defined USB LANGIDs can be found at * http://www.usb.org/developers/docs.html.", but that page 404s. * * Once upon a time the USB-IF (usb.org) published a "Language Identifiers (LANGIDs)" version 1.0, @@ -61,10 +62,9 @@ cat <<'EOT' * to sort their list of by most-significant-byte was a poor editorial choice. */ EOT -[ -d 3rd-party ] || mkdir 3rd-party -[ -f 3rd-party/MS-LCID.pdf ] || wget -O 3rd-party/MS-LCID.pdf 'https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-LCID/%5bMS-LCID%5d.pdf' -[ -f 3rd-party/MS-LCID.txt ] || pdftotext -layout 3rd-party/MS-LCID.pdf -<3rd-party/MS-LCID.txt \ +[ -f ${CMAKE_SOURCE_DIR?}/3rd-party/MS-LCID.pdf ] || wget -O ${CMAKE_SOURCE_DIR?}/3rd-party/MS-LCID.pdf 'https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-LCID/%5bMS-LCID%5d.pdf' +[ -f ${CMAKE_SOURCE_DIR?}/3rd-party/MS-LCID.txt ] || pdftotext -layout ${CMAKE_SOURCE_DIR?}/3rd-party/MS-LCID.pdf +<${CMAKE_SOURCE_DIR?}/3rd-party/MS-LCID.txt \ grep -E '^\s*0x[0-9A-F]{4}\s+[a-z]' | sed 's/,.*//' | grep -v reserved | # find the lines we're interested in sed -E 's/^\s*0x(..)(..)\s+(\S.*)/\2 \1 \3/p' | tr '[:lower:]-' '[:upper:]_' | # format them as 'PRIhex SUBhex UPPER_STR' sort | @@ -72,11 +72,11 @@ EOT column --table --output-separator=' ' cat <<'EOT' -/* USB 2.0 §9.6.6 "Endpoint", field bEndpointAddress, bit 7 */ +/** USB 2.0 §9.6.6 "Endpoint", field bEndpointAddress, bit 7 */ #define TUD_ENDPOINT_OUT 0x00 #define TUD_ENDPOINT_IN 0x80 #define TU_UTF16(str) u ## str -#endif /* _USB_HELPERS_H_ */ +#endif /* _LIBUSB_TUSB_HELPERS_H_ */ EOT diff --git a/libusb/usb_common.h b/libusb/include/libusb/usb_common.h index 3b45246..3b45246 100644 --- a/libusb/usb_common.h +++ b/libusb/include/libusb/usb_common.h |