cmake: linker generator: Handle NOT PASS and multiple PASS options

Make it possible to have multiple PASS parameters to
zephyr_linker_section() and zephyr_linker_section_configure() sections
(oring them) OR to have multiple PASS NOT p options (in which case the
sections applies in neither of the passes)

Signed-off-by: Björn Bergman <bjorn.bergman@iar.com>
diff --git a/cmake/linker/linker_script_common.cmake b/cmake/linker/linker_script_common.cmake
index 017de14..38d6c83 100644
--- a/cmake/linker/linker_script_common.cmake
+++ b/cmake/linker/linker_script_common.cmake
@@ -94,6 +94,25 @@
   set(${OBJECT_OBJECT} GROUP_${OBJECT_NAME} PARENT_SCOPE)
 endfunction()
 
+function(is_active_in_pass ret_ptr current_pass pass_rules)
+  # by validation in zephyr_linker_* we know that if there is a NOT,
+  # it is the first, and the other entries are pass names
+  if(NOT pass_rules)
+    set(result 1)
+  elseif("NOT" IN_LIST pass_rules)
+    set(result 1)
+    if(current_pass IN_LIST pass_rules)
+      set(result 0)
+    endif()
+  else()
+    set(result 0)
+    if(current_pass IN_LIST pass_rules)
+      set(result 1)
+    endif()
+  endif()
+  set(${ret_ptr} ${result} PARENT_SCOPE)
+endfunction()
+
 function(create_section)
   set(single_args "NAME;ADDRESS;ALIGN_WITH_INPUT;TYPE;ALIGN;ENDALIGN;SUBALIGN;VMA;LMA;NOINPUT;NOINIT;NOSYMBOLS;GROUP;SYSTEM")
   set(multi_args  "PASS")
@@ -101,8 +120,8 @@
   cmake_parse_arguments(SECTION "" "${single_args}" "${multi_args}" ${ARGN})
 
   if(DEFINED SECTION_PASS)
-    if(NOT (${SECTION_PASS} IN_LIST PASS))
-      # This section is not active in this pass, ignore.
+    is_active_in_pass(active ${PASS} "${SECTION_PASS}")
+    if(NOT active)
       return()
     endif()
   endif()
@@ -141,8 +160,8 @@
       endif()
 
       if(DEFINED SETTINGS_PASS)
-        if(NOT (${SETTINGS_PASS} IN_LIST PASS))
-          # This section setting is not active in this pass, ignore.
+        is_active_in_pass(active ${PASS} "${SETTINGS_PASS}")
+        if(NOT active)
           continue()
         endif()
       endif()
diff --git a/cmake/modules/extensions.cmake b/cmake/modules/extensions.cmake
index 209e487..0ba73a6 100644
--- a/cmake/modules/extensions.cmake
+++ b/cmake/modules/extensions.cmake
@@ -5010,7 +5010,7 @@
 #                         [ADDRESS <address>] [ALIGN <alignment>]
 #                         [SUBALIGN <alignment>] [FLAGS <flags>]
 #                         [HIDDEN] [NOINPUT] [NOINIT]
-#                         [PASS [NOT] <name>]
+#                         [PASS [NOT] [<name>]]
 #   )
 #
 # Zephyr linker output section.
@@ -5065,15 +5065,13 @@
 # NOINPUT             : No default input sections will be defined, to setup input
 #                       sections for section <name>, the corresponding
 #                       `zephyr_linker_section_configure()` must be used.
-# PASS [NOT] <name>   : Linker pass iteration where this section should be active.
-#                       Default a section will be present during all linker passes
-#                       but in cases a section shall only be present at a specific
-#                       pass, this argument can be used. For example to only have
-#                       this section present on the `TEST` linker pass, use `PASS TEST`.
-#                       It is possible to negate <name>, such as `PASS NOT <name>`.
-#                       For example, `PASS NOT TEST` means the call is effective
-#                       on all but the `TEST` linker pass iteration.
-#
+# PASS [NOT] [<name> ..]: Linker pass where this section should be active.
+#                       By default a section will be present during all linker
+#                       passes.
+#                       PASS [<p1>] [<p2>...] makes the section present only in
+#                       the given passes. Empty list means no passes.
+#                       PASS NOT [<p1>] [<p2>...] makes the section present in
+#                       all but the given passes. Empty list means all passes.
 # Note: VMA and LMA are mutual exclusive with GROUP
 #
 function(zephyr_linker_section)
@@ -5110,16 +5108,7 @@
     endif()
   endif()
 
-  if(DEFINED SECTION_PASS)
-    list(LENGTH SECTION_PASS pass_length)
-    if(${pass_length} GREATER 1)
-      list(GET SECTION_PASS 0 pass_elem_0)
-      if((NOT (${pass_elem_0} STREQUAL "NOT")) OR (${pass_length} GREATER 2))
-        message(FATAL_ERROR "zephyr_linker_section(PASS takes maximum "
-          "a single argument of the form: '<pass name>' or 'NOT <pass_name>'.")
-      endif()
-    endif()
-  endif()
+  zephyr_linker_check_pass_param("${SECTION_PASS}")
 
   set(SECTION)
   zephyr_linker_arg_val_list(SECTION "${single_args}")
@@ -5326,15 +5315,12 @@
 #                       you may use `PRIO 50`, `PRIO 20` and so on.
 #                       To ensure an input section is at the end, it is advised
 #                       to use `PRIO 200` and above.
-# PASS [NOT] <name>   : The call should only be considered for linker pass where
-#                       <name> is defined. It is possible to negate <name>, such
-#                       as `PASS NOT <name>.
-#                       For example, `PASS TEST` means the call is only effective
-#                       on the `TEST` linker pass iteration. `PASS NOT TEST` on
-#                       all iterations the are not `TEST`.
+# PASS [NOT] [<pass>..]: Control in which linker passes this piece is present
+#                       See zephyr_linker_section(PASS) for details.
 # FLAGS <flags>       : Special section flags such as "+RO", +XO, "+ZI".
 # ANY                 : ANY section flag in scatter file.
 #                       The FLAGS and ANY arguments only has effect for scatter files.
+# INPUT <input>       : Input section name or list of input section names.
 #
 function(zephyr_linker_section_configure)
   set(options     "ANY;FIRST;KEEP")
@@ -5354,16 +5340,7 @@
     endif()
   endif()
 
-  if(DEFINED SECTION_PASS)
-    list(LENGTH SECTION_PASS pass_length)
-    if(${pass_length} GREATER 1)
-      list(GET SECTION_PASS 0 pass_elem_0)
-      if((NOT (${pass_elem_0} STREQUAL "NOT")) OR (${pass_length} GREATER 2))
-        message(FATAL_ERROR "zephyr_linker_section_configure(PASS takes maximum "
-          "a single argument of the form: '<pass name>' or 'NOT <pass_name>'.")
-      endif()
-    endif()
-  endif()
+  zephyr_linker_check_pass_param("${SECTION_PASS}")
 
   set(SECTION)
   zephyr_linker_arg_val_list(SECTION "${single_args}")
@@ -5432,6 +5409,16 @@
   endforeach()
 endmacro()
 
+
+# Internal helper that checks if we have consistent PASS arguments.
+# Allow PASS [NOT] [<pass>...]
+function(zephyr_linker_check_pass_param PASSES)
+  list(POP_FRONT PASSES)
+  if("NOT" IN_LIST PASSES)
+    message(FATAL_ERROR "NOT only allowed before first <pass> value, like this: PASS [NOT] <pass>...")
+  endif()
+endfunction()
+
 ########################################################
 # 6. Function helper macros
 ########################################################